• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

hivesolutions / admin-scripts / 347

pending completion
347

push

travis-ci-com

joamag
fix: changed default version to 3.6

1 of 1 new or added line in 1 file covered. (100.0%)

684 of 1620 relevant lines covered (42.22%)

3.8 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

20.0
/src/admin_scripts/base/pydev.py
1
#!/usr/bin/python
2
# -*- coding: utf-8 -*-
3

4
# Hive Administration Scripts
5
# Copyright (c) 2008-2020 Hive Solutions Lda.
6
#
7
# This file is part of Hive Administration Scripts.
8
#
9
# Hive Administration Scripts is free software: you can redistribute it and/or modify
10
# it under the terms of the Apache License as published by the Apache
11
# Foundation, either version 2.0 of the License, or (at your option) any
12
# later version.
13
#
14
# Hive Administration Scripts is distributed in the hope that it will be useful,
15
# but WITHOUT ANY WARRANTY; without even the implied warranty of
16
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
# Apache License for more details.
18
#
19
# You should have received a copy of the Apache License along with
20
# Hive Administration Scripts. If not, see <http://www.apache.org/licenses/>.
21

22
__author__ = "João Magalhães <joamag@hive.pt>"
9✔
23
""" The author(s) of the module """
24

25
__version__ = "1.0.0"
9✔
26
""" The version of the module """
27

28
__revision__ = "$LastChangedRevision$"
9✔
29
""" The revision number of the module """
30

31
__date__ = "$LastChangedDate$"
9✔
32
""" The last change date of the module """
33

34
__copyright__ = "Copyright (c) 2008-2020 Hive Solutions Lda."
9✔
35
""" The copyright for the module """
36

37
__license__ = "Apache License, Version 2.0"
9✔
38
""" The license for the module """
39

40
import os
9✔
41
import re
9✔
42
import sys
9✔
43
import getopt
9✔
44

45
import xml.dom.minidom
9✔
46

47
import legacy
9✔
48

49
import admin_scripts.extra as extra
9✔
50

51
USAGE_MESSAGE = "pydev [-r] [-w exclusion_1, exclusion_2, ...] [-c configuration_file]"
9✔
52
""" The usage message to be printed in case there's an
53
error with the command line or help is requested. """
54

55
PREFIX_REGEX = re.compile("/[^/]+")
9✔
56
""" The prefix regular expression used to match the initial
57
part of the source directory file path """
58

59
VALID_PROPERTIES = (
9✔
60
    "org.python.pydev.PYTHON_PROJECT_VERSION",
61
    "org.python.pydev.PYTHON_PROJECT_INTERPRETER"
62
)
63
""" The sequence that defines the complete set of properties that
64
are considered valid under the current pydev specification """
65

66
def pydev_file(file_path, fix = True):
9✔
67
    """
68
    Runs the pydev configuration file normalization that consists
69
    in the definition in order of each of the XML lines.
70

71
    This operation should fail with an exception in case the
72
    structure of the XML document is not the expected one.
73

74
    :type file_path: String
75
    :param file_path: The path to the file that contains the
76
    pydev configuration specification in XML.
77
    :type fix: bool
78
    :param fix: If any "fixable" error in the pydev project
79
    file should be automatically fixes using the known heuristics,
80
    this is a dangerous option as errors may be created.
81
    """
82

83
    paths = []
×
84
    properties = dict()
×
85
    buffer = []
×
86

87
    xmldoc = xml.dom.minidom.parse(file_path)
×
88
    nodes = xmldoc.getElementsByTagName("pydev_property")
×
89

90
    for node in nodes:
×
91
        value = text_value(node)
×
92
        name = node.attributes["name"].value
×
93
        properties[name] = value
×
94

95
    nodes = xmldoc.getElementsByTagName("pydev_pathproperty")
×
96
    nodes = nodes[0].childNodes if nodes else []
×
97

98
    for node in nodes:
×
99
        value = text_value(node)
×
100
        if not value: continue
×
101
        paths.append(value)
×
102

103
    for key in legacy.keys(properties):
×
104
        if key in VALID_PROPERTIES: continue
×
105
        raise RuntimeError("Invalid property '%s'" % key)
×
106

107
    if fix: paths, properties = fix_values(paths, properties)
×
108

109
    python_version = properties.get("org.python.pydev.PYTHON_PROJECT_VERSION", None)
×
110
    if not python_version: extra.warn("No python version defined")
×
111
    elif not python_version == "python 3.6": extra.warn("Python version not 3.6")
×
112

113
    for path in paths:
×
114
        if path.startswith("/${PROJECT_DIR_NAME}"): continue
×
115
        extra.warn("Project directory path not normalized '%s'" % path)
×
116

117
    property_keys = legacy.keys(properties)
×
118
    property_keys.sort()
×
119

120
    buffer.append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n")
×
121
    buffer.append("<?eclipse-pydev version=\"1.0\"?><pydev_project>\n")
×
122
    if paths: buffer.append("<pydev_pathproperty name=\"org.python.pydev.PROJECT_SOURCE_PATH\">\n")
×
123
    for path in paths:
×
124
        buffer.append("<path>%s</path>\n" % path)
×
125
    if paths: buffer.append("</pydev_pathproperty>\n")
×
126
    for key in property_keys:
×
127
        value = properties[key]
×
128
        buffer.append("<pydev_property name=\"%s\">%s</pydev_property>\n" % (key, value))
×
129
    buffer.append("</pydev_project>\n")
×
130

131
    result = "".join(buffer)
×
132
    result = result.encode("utf-8")
×
133

134
    file = open(file_path, "wb")
×
135
    try: file.write(result)
×
136
    finally: file.close()
×
137

138
def fix_values(paths, properties):
9✔
139
    """
140
    Runs the fixer of the various loaded values from the pydev
141
    configuration file.
142

143
    These set of operations should be able to fix most of the
144
    known errors in the pydev configuration, this is a dangerous
145
    operation as it may cause problems in data structure.
146

147
    :type paths: List
148
    :param paths: The sequences of paths that should represent
149
    the main entry points for the python source code in project.
150
    :type properties: Dictionary
151
    :param properties: The map containing the option name to value
152
    associations that were loaded from the source pydev file.
153
    :rtype: Tuple
154
    :return: The resulting values from the provided configurations
155
    these values should have been fixed.
156
    """
157

158
    _paths = []
×
159

160
    for path in paths:
×
161
        if not path: continue
×
162
        if not "/" in path: _paths.append(path)
×
163
        elif path.startswith("/${PROJECT_DIR_NAME}"): _paths.append(path)
×
164
        else: _paths.append(PREFIX_REGEX.sub("/${PROJECT_DIR_NAME}", path, 1))
×
165

166
    return _paths, properties
×
167

168
def text_value(node):
9✔
169
    """
170
    Retrieves the text/XML string value for the provided
171
    node, this is a recursive approach and the child nodes
172
    are used as the entry point.
173

174
    :type node: Element
175
    :param node: The base element node from which the values
176
    are going to be retrieved.
177
    :rtype: String
178
    :return: The string/textual part of the XML element node
179
    provided.
180
    """
181

182
    nodes = node.childNodes
×
183

184
    data = []
×
185
    for node in nodes:
×
186
        if not node.nodeType == node.TEXT_NODE: continue
×
187
        data.append(node.data)
×
188

189
    return "".join(data)
×
190

191
def pydev_walker(arguments, directory_name, names):
9✔
192
    """
193
    Walker method to be used by the path walker for running the
194
    normalization pydev process.
195

196
    :type arguments: Tuple
197
    :param arguments: The arguments tuple sent by the walker method.
198
    :type directory_name: String
199
    :param directory_name: The name of the current directory in the walk.
200
    :type names: List
201
    :param names: The list of names in the current directory.
202
    """
203

204
    # unpacks the arguments tuple
205
    file_exclusion, fix = arguments
×
206

207
    # tries to run the handle ignore operation for the current set of names and
208
    # in case there's a processing returns the control flow immediately as no
209
    # more handling is meant to occur for the current operation (ignored)
210
    if extra.handle_ignore(names): return
×
211

212
    # removes the complete set of names that are meant to be excluded from the
213
    # current set names to be visit (avoid visiting them)
214
    for exclusion in file_exclusion:
×
215
        if not exclusion in names: continue
×
216
        names.remove(exclusion)
×
217

218
    # retrieves the valid names for the names list (removes directory entries)
219
    valid_complete_names = [directory_name + "/" + name for name in names\
×
220
        if not os.path.isdir(directory_name + "/" + name)]
221

222
    # filters the names with non valid file extensions so that only the
223
    # ones that conform with the pydev project ones are selected
224
    valid_complete_names = [os.path.normpath(name) for name in valid_complete_names\
×
225
        if name.endswith(".pydevproject")]
226

227
    # iterates over all the valid complete names with valid structure
228
    # as defined by the pydev project specification
229
    for valid_complete_name in valid_complete_names:
×
230
        # print a message a message about the pydev
231
        # operation that is going to be performed and
232
        # then runs the operation with the correct path
233
        extra.echo("Normalizing pydev configuration file: %s" % valid_complete_name)
×
234
        pydev_file(valid_complete_name, fix = fix)
×
235

236
def pydev_recursive(directory_path, file_exclusion, fix = True):
9✔
237
    """
238
    Normalizes pydev in recursive mode.
239
    All the options are arguments to be passed to the
240
    walker function.
241

242
    :type directory_path: String
243
    :param directory_path: The path to the (entry point) directory.
244
    :type file_exclusion: List
245
    :param file_exclusion: The list of file exclusion to be used.
246
    :type fix: bool
247
    :param fix: If any "fixable" error in the pydev project
248
    file should be automatically fixes using the known heuristics,
249
    this is a dangerous option as errors may be created.
250
    """
251

252
    legacy.walk(directory_path, pydev_walker, (file_exclusion, fix))
×
253

254
def main():
9✔
255
    """
256
    Main function used for the pydev file normalization.
257
    """
258

259
    # in case the number of arguments
260
    # is not sufficient
261
    if len(sys.argv) < 2:
×
262
        # prints a series of message related with he
263
        # correct usage of the command line and then
264
        # exits the process with error indication
265
        extra.echo("Invalid number of arguments")
×
266
        extra.echo("Usage: " + USAGE_MESSAGE)
×
267
        sys.exit(2)
×
268

269
    # sets the default values for the parameters
270
    # this values are going to be used as the basis
271
    # for the generation of the configuration
272
    path = sys.argv[1]
×
273
    recursive = False
×
274
    file_exclusion = None
×
275
    configuration_file_path = None
×
276

277
    try:
×
278
        options, _arguments = getopt.getopt(sys.argv[2:], "rw:c:", [])
×
279
    except getopt.GetoptError:
×
280
        # prints a series of messages about the
281
        # correct usage of the command line and
282
        # exits the current process with an error
283
        extra.echo("Invalid number of arguments")
×
284
        extra.echo("Usage: " + USAGE_MESSAGE)
×
285
        sys.exit(2)
×
286

287
    # iterates over all the options, retrieving the option
288
    # and the value for each
289
    for option, value in options:
×
290
        if option == "-r":
×
291
            recursive = True
×
292
        elif option == "-w":
×
293
            file_exclusion = [value.strip() for value in value.split(",")]
×
294
        elif option == "-c":
×
295
            configuration_file_path = value
×
296

297
    # retrieves the configurations from the command line arguments
298
    # either from the command line or configuration file
299
    configurations = extra.configuration(
×
300
        file_path = configuration_file_path,
301
        recursive = recursive,
302
        file_exclusion = file_exclusion
303
    )
304

305
    # iterates over all the configurations, executing them
306
    for configuration in configurations:
×
307
        # retrieves the configuration values
308
        recursive = configuration["recursive"]
×
309
        file_exclusion = configuration["file_exclusion"]
×
310
        fix = configuration.get("fix", True)
×
311

312
        # in case the recursive flag is set, normalizes the multiple
313
        # found pydev configuration file
314
        if recursive: pydev_recursive(path, file_exclusion, fix = fix)
×
315
        # otherwise it's a "normal" iteration and runs the
316
        # pydev normalization process in it
317
        else: pydev_file(path, fix = fix)
×
318

319
    # verifies if there were messages printed to the standard
320
    # error output and if that's the case exits in error
321
    sys.exit(1 if extra.has_errors() else 0)
×
322

323
if __name__ == "__main__":
9✔
324
    main()
×
325
else:
326
    __path__ = []
9✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc