Mercurial > hg > truffle
comparison mxtool/mx.py @ 5055:90c150a0a22b
Merge.
author | Thomas Wuerthinger <thomas.wuerthinger@oracle.com> |
---|---|
date | Thu, 08 Mar 2012 12:46:19 +0100 |
parents | e2de9649f0a9 |
children | 9d055af068a8 |
comparison
equal
deleted
inserted
replaced
5054:b4f548d49f96 | 5055:90c150a0a22b |
---|---|
23 # or visit www.oracle.com if you need additional information or have any | 23 # or visit www.oracle.com if you need additional information or have any |
24 # questions. | 24 # questions. |
25 # | 25 # |
26 # ---------------------------------------------------------------------------------------------------- | 26 # ---------------------------------------------------------------------------------------------------- |
27 # | 27 # |
28 # mx is a command line tool inspired by mvn (http://maven.apache.org/) | 28 |
29 # and hg (http://mercurial.selenic.com/). It includes a mechanism for | 29 r""" |
30 # managing the dependencies between a set of projects (like Maven) | 30 mx is a command line tool inspired by mvn (http://maven.apache.org/) |
31 # as well as making it simple to run commands | 31 and hg (http://mercurial.selenic.com/). It includes a mechanism for |
32 # (like hg is the interface to the Mercurial commands). | 32 managing the dependencies between a set of projects (like Maven) |
33 # | 33 as well as making it simple to run commands |
34 # The organizing principle of mx is a project suite. A suite is a directory | 34 (like hg is the interface to the Mercurial commands). |
35 # containing one or more projects. It's not coincidental that this closely | 35 |
36 # matches the layout of one or more projects in a Mercurial repository. | 36 The organizing principle of mx is a project suite. A suite is a directory |
37 # The configuration information for a suite lives in an 'mx' sub-directory | 37 containing one or more projects. It's not coincidental that this closely |
38 # at the top level of the suite. | 38 matches the layout of one or more projects in a Mercurial repository. |
39 # | 39 The configuration information for a suite lives in an 'mx' sub-directory |
40 # When launched, mx treats the current working directory as a suite. | 40 at the top level of the suite. |
41 # This is the primary suite. All other suites are called included suites. | 41 |
42 # | 42 When launched, mx treats the current working directory as a suite. |
43 # The configuration files (i.e. in the 'mx' sub-directory) of a suite are: | 43 This is the primary suite. All other suites are called included suites. |
44 # | 44 |
45 # projects - Defines the projects and libraries in the suite and the dependencies between them | 45 The configuration files (i.e. in the 'mx' sub-directory) of a suite are: |
46 # commands.py - Suite specific extensions to the commands available to mx. This is only processed | 46 |
47 # for the primary suite. | 47 projects |
48 # includes - Other suites to be loaded. This is recursive. | 48 Defines the projects and libraries in the suite and the |
49 # env - A set of environment variable definitions. | 49 dependencies between them. |
50 # | 50 |
51 # The includes and env files are typically not put under version control | 51 commands.py |
52 # as they usually contain local file-system paths. | 52 Suite specific extensions to the commands available to mx. |
53 # | 53 This is only processed for the primary suite. |
54 # The projects file is like the pom.xml file from Maven except that | 54 |
55 # it is a properties file (not XML). Each non-comment line | 55 includes |
56 # in the file specifies an attribute of a project or library. The main | 56 Other suites to be loaded. This is recursive. |
57 # difference between a project and a library is that the former contains | 57 |
58 # source code built by the mx tool where as the latter is an external | 58 env |
59 # dependency. The format of the projects file is | 59 A set of environment variable definitions. These override any |
60 # | 60 existing environment variables. |
61 # Library specification format: | 61 |
62 # | 62 The includes and env files are typically not put under version control |
63 # library@<name>@<prop>=<value> | 63 as they usually contain local file-system paths. |
64 # | 64 |
65 # Built-in library properties (* = required): | 65 The projects file is like the pom.xml file from Maven except that |
66 # | 66 it is a properties file (not XML). Each non-comment line |
67 # *path: the file system path for the library to appear on a class path | 67 in the file specifies an attribute of a project or library. The main |
68 # urls: a comma seperated list of URLs from which the library can be downloaded | 68 difference between a project and a library is that the former contains |
69 # optional: if "true" then this library will be omitted from a class path if it doesn't exist on the file system and no URLs are specified | 69 source code built by the mx tool where as the latter is an external |
70 # | 70 dependency. The format of the projects file is |
71 # Project specification format: | 71 |
72 # | 72 Library specification format: |
73 # project@<name>@<prop>=<value> | 73 |
74 # | 74 library@<name>@<prop>=<value> |
75 # The name of a project also denotes the directory it is in. | 75 |
76 # | 76 Built-in library properties (* = required): |
77 # Built-in project properties: | 77 |
78 # | 78 *path |
79 # *sourceDirs: a comma separated list of source directoriy names (relative to the project directory) | 79 The file system path for the library to appear on a class path. |
80 # dependencies: a comma separated list of the libraries and project the project depends upon (transitive dependencies may be omitted) | 80 |
81 # checkstyle: the project whose Checkstyle configuration (i.e. <project>/.checkstyle_checks.xml) is used | 81 urls |
82 # | 82 A comma separated list of URLs from which the library (jar) can |
83 # Other properties can be specified for projects and libraries for use by extension commands. | 83 be downloaded and saved in the location specified by 'path'. |
84 # | 84 |
85 # Values can use environment variables with Bash syntax (e.g. ${HOME}). | 85 optional |
86 If "true" then this library will be omitted from a class path | |
87 if it doesn't exist on the file system and no URLs are specified. | |
88 | |
89 Project specification format: | |
90 | |
91 project@<name>@<prop>=<value> | |
92 | |
93 The name of a project also denotes the directory it is in. | |
94 | |
95 Built-in project properties (* = required): | |
96 | |
97 subDir | |
98 The sub-directory of the suite in which the project directory is | |
99 contained. If not specified, the project directory is directly | |
100 under the suite directory. | |
101 | |
102 *sourceDirs | |
103 A comma separated list of source directory names (relative to | |
104 the project directory). | |
105 | |
106 dependencies | |
107 A comma separated list of the libraries and project the project | |
108 depends upon (transitive dependencies should be omitted). | |
109 | |
110 checkstyle | |
111 The project whose Checkstyle configuration | |
112 (i.e. <project>/.checkstyle_checks.xml) is used. | |
113 | |
114 native | |
115 "true" if the project is native. | |
116 | |
117 javaCompliance | |
118 The minimum JDK version (format: x.y) to which the project's | |
119 sources comply (required for non-native projects). | |
120 | |
121 Other properties can be specified for projects and libraries for use | |
122 by extension commands. | |
123 | |
124 Property values can use environment variables with Bash syntax (e.g. ${HOME}). | |
125 """ | |
86 | 126 |
87 import sys, os, errno, time, subprocess, shlex, types, urllib2, contextlib, StringIO, zipfile, signal | 127 import sys, os, errno, time, subprocess, shlex, types, urllib2, contextlib, StringIO, zipfile, signal |
88 import shutil, fnmatch, re, xml.dom.minidom | 128 import shutil, fnmatch, re, xml.dom.minidom |
89 from collections import Callable | 129 from collections import Callable |
90 from threading import Thread | 130 from threading import Thread |
105 """ | 145 """ |
106 class Dependency: | 146 class Dependency: |
107 def __init__(self, suite, name): | 147 def __init__(self, suite, name): |
108 self.name = name | 148 self.name = name |
109 self.suite = suite | 149 self.suite = suite |
110 | 150 |
111 def __str__(self): | 151 def __str__(self): |
112 return self.name | 152 return self.name |
113 | 153 |
114 def __eq__(self, other): | 154 def __eq__(self, other): |
115 return self.name == other.name | 155 return self.name == other.name |
116 | 156 |
117 def __ne__(self, other): | 157 def __ne__(self, other): |
118 return self.name != other.name | 158 return self.name != other.name |
119 | 159 |
120 def __hash__(self): | 160 def __hash__(self): |
121 return hash(self.name) | 161 return hash(self.name) |
122 | 162 |
123 def isLibrary(self): | 163 def isLibrary(self): |
124 return isinstance(self, Library) | 164 return isinstance(self, Library) |
125 | 165 |
126 class Project(Dependency): | 166 class Project(Dependency): |
127 def __init__(self, suite, name, srcDirs, deps, dir): | 167 def __init__(self, suite, name, srcDirs, deps, javaCompliance, dir): |
128 Dependency.__init__(self, suite, name) | 168 Dependency.__init__(self, suite, name) |
129 self.srcDirs = srcDirs | 169 self.srcDirs = srcDirs |
130 self.deps = deps | 170 self.deps = deps |
131 self.checkstyleProj = name | 171 self.checkstyleProj = name |
172 self.javaCompliance = JavaCompliance(javaCompliance) if javaCompliance is not None else None | |
132 self.native = False | 173 self.native = False |
133 self.dir = dir | 174 self.dir = dir |
134 | 175 |
135 def all_deps(self, deps, includeLibs, includeSelf=True): | 176 def all_deps(self, deps, includeLibs, includeSelf=True): |
136 """ | 177 """ |
137 Add the transitive set of dependencies for this project, including | 178 Add the transitive set of dependencies for this project, including |
138 libraries if 'includeLibs' is true, to the 'deps' list. | 179 libraries if 'includeLibs' is true, to the 'deps' list. |
139 """ | 180 """ |
150 if not dep in deps: | 191 if not dep in deps: |
151 dep.all_deps(deps, includeLibs) | 192 dep.all_deps(deps, includeLibs) |
152 if not self in deps and includeSelf: | 193 if not self in deps and includeSelf: |
153 deps.append(self) | 194 deps.append(self) |
154 return deps | 195 return deps |
155 | 196 |
156 def _compute_max_dep_distances(self, name, distances, dist): | 197 def _compute_max_dep_distances(self, name, distances, dist): |
157 currentDist = distances.get(name); | 198 currentDist = distances.get(name); |
158 if currentDist is None or currentDist < dist: | 199 if currentDist is None or currentDist < dist: |
159 distances[name] = dist | 200 distances[name] = dist |
160 p = project(name, False) | 201 p = project(name, False) |
161 if p is not None: | 202 if p is not None: |
162 for dep in p.deps: | 203 for dep in p.deps: |
163 self._compute_max_dep_distances(dep, distances, dist + 1) | 204 self._compute_max_dep_distances(dep, distances, dist + 1) |
164 | 205 |
165 def canonical_deps(self): | 206 def canonical_deps(self): |
166 """ | 207 """ |
167 Get the dependencies of this project that are not recursive (i.e. cannot be reached | 208 Get the dependencies of this project that are not recursive (i.e. cannot be reached |
168 via other dependencies). | 209 via other dependencies). |
169 """ | 210 """ |
172 self._compute_max_dep_distances(self.name, distances, 0) | 213 self._compute_max_dep_distances(self.name, distances, 0) |
173 for n,d in distances.iteritems(): | 214 for n,d in distances.iteritems(): |
174 assert d > 0 or n == self.name | 215 assert d > 0 or n == self.name |
175 if d == 1: | 216 if d == 1: |
176 result.add(n) | 217 result.add(n) |
177 | 218 |
178 | 219 |
179 if len(result) == len(self.deps) and frozenset(self.deps) == result: | 220 if len(result) == len(self.deps) and frozenset(self.deps) == result: |
180 return self.deps | 221 return self.deps |
181 return result; | 222 return result; |
182 | 223 |
183 | 224 |
184 def source_dirs(self): | 225 def source_dirs(self): |
185 """ | 226 """ |
186 Get the directories in which the sources of this project are found. | 227 Get the directories in which the sources of this project are found. |
187 """ | 228 """ |
188 return [join(self.dir, s) for s in self.srcDirs] | 229 return [join(self.dir, s) for s in self.srcDirs] |
189 | 230 |
190 def output_dir(self): | 231 def output_dir(self): |
191 """ | 232 """ |
192 Get the directory in which the class files of this project are found/placed. | 233 Get the directory in which the class files of this project are found/placed. |
193 """ | 234 """ |
194 if self.native: | 235 if self.native: |
195 return None | 236 return None |
196 return join(self.dir, 'bin') | 237 return join(self.dir, 'bin') |
197 | 238 |
239 def jasmin_output_dir(self): | |
240 """ | |
241 Get the directory in which the Jasmin assembled class files of this project are found/placed. | |
242 """ | |
243 if self.native: | |
244 return None | |
245 return join(self.dir, 'jasmin_classes') | |
246 | |
198 def append_to_classpath(self, cp, resolve): | 247 def append_to_classpath(self, cp, resolve): |
199 if not self.native: | 248 if not self.native: |
200 cp.append(self.output_dir()) | 249 cp.append(self.output_dir()) |
201 | 250 |
202 class Library(Dependency): | 251 class Library(Dependency): |
203 def __init__(self, suite, name, path, mustExist, urls): | 252 def __init__(self, suite, name, path, mustExist, urls): |
204 Dependency.__init__(self, suite, name) | 253 Dependency.__init__(self, suite, name) |
205 self.path = path.replace('/', os.sep) | 254 self.path = path.replace('/', os.sep) |
206 self.urls = urls | 255 self.urls = urls |
207 self.mustExist = mustExist | 256 self.mustExist = mustExist |
208 | 257 |
209 def get_path(self, resolve): | 258 def get_path(self, resolve): |
210 path = self.path | 259 path = self.path |
211 if not isabs(path): | 260 if not isabs(path): |
212 path = join(self.suite.dir, path) | 261 path = join(self.suite.dir, path) |
213 if resolve and self.mustExist and not exists(path): | 262 if resolve and self.mustExist and not exists(path): |
214 assert not len(self.urls) == 0, 'cannot find required library ' + self.name + " " + path; | 263 assert not len(self.urls) == 0, 'cannot find required library ' + self.name + " " + path; |
215 print('Downloading ' + self.name + ' from ' + str(self.urls)) | 264 print('Downloading ' + self.name + ' from ' + str(self.urls)) |
216 download(path, self.urls) | 265 download(path, self.urls) |
217 | 266 |
218 return path | 267 return path |
219 | 268 |
220 def append_to_classpath(self, cp, resolve): | 269 def append_to_classpath(self, cp, resolve): |
221 path = self.get_path(resolve) | 270 path = self.get_path(resolve) |
222 if exists(path) or not resolve: | 271 if exists(path) or not resolve: |
223 cp.append(path) | 272 cp.append(path) |
224 | 273 |
225 class Suite: | 274 class Suite: |
226 def __init__(self, dir, primary): | 275 def __init__(self, dir, primary): |
227 self.dir = dir | 276 self.dir = dir |
228 self.projects = [] | 277 self.projects = [] |
229 self.libs = [] | 278 self.libs = [] |
235 if primary: | 284 if primary: |
236 self._load_commands(mxDir) | 285 self._load_commands(mxDir) |
237 | 286 |
238 def _load_projects(self, mxDir): | 287 def _load_projects(self, mxDir): |
239 libsMap = dict() | 288 libsMap = dict() |
240 projsMap = dict() | 289 projsMap = dict() |
241 projectsFile = join(mxDir, 'projects') | 290 projectsFile = join(mxDir, 'projects') |
242 if not exists(projectsFile): | 291 if not exists(projectsFile): |
243 return | 292 return |
244 with open(projectsFile) as f: | 293 with open(projectsFile) as f: |
245 for line in f: | 294 for line in f: |
246 line = line.strip() | 295 line = line.strip() |
247 if len(line) != 0 and line[0] != '#': | 296 if len(line) != 0 and line[0] != '#': |
248 key, value = line.split('=', 1) | 297 key, value = line.split('=', 1) |
249 | 298 |
250 parts = key.split('@') | 299 parts = key.split('@') |
251 | 300 |
252 if len(parts) == 2: | 301 if len(parts) == 2: |
253 pass | 302 pass |
254 if len(parts) != 3: | 303 if len(parts) != 3: |
255 abort('Property name does not have 3 parts separated by "@": ' + key) | 304 abort('Property name does not have 3 parts separated by "@": ' + key) |
256 kind, name, attr = parts | 305 kind, name, attr = parts |
258 m = projsMap | 307 m = projsMap |
259 elif kind == 'library': | 308 elif kind == 'library': |
260 m = libsMap | 309 m = libsMap |
261 else: | 310 else: |
262 abort('Property name does not start with "project@" or "library@": ' + key) | 311 abort('Property name does not start with "project@" or "library@": ' + key) |
263 | 312 |
264 attrs = m.get(name) | 313 attrs = m.get(name) |
265 if attrs is None: | 314 if attrs is None: |
266 attrs = dict() | 315 attrs = dict() |
267 m[name] = attrs | 316 m[name] = attrs |
268 value = expandvars_in_property(value) | 317 value = expandvars_in_property(value) |
269 attrs[attr] = value | 318 attrs[attr] = value |
270 | 319 |
271 def pop_list(attrs, name): | 320 def pop_list(attrs, name): |
272 v = attrs.pop(name, None) | 321 v = attrs.pop(name, None) |
273 if v is None or len(v.strip()) == 0: | 322 if v is None or len(v.strip()) == 0: |
274 return [] | 323 return [] |
275 return [n.strip() for n in v.split(',')] | 324 return [n.strip() for n in v.split(',')] |
276 | 325 |
277 for name, attrs in projsMap.iteritems(): | 326 for name, attrs in projsMap.iteritems(): |
278 srcDirs = pop_list(attrs, 'sourceDirs') | 327 srcDirs = pop_list(attrs, 'sourceDirs') |
279 deps = pop_list(attrs, 'dependencies') | 328 deps = pop_list(attrs, 'dependencies') |
329 javaCompliance = attrs.pop('javaCompliance', None) | |
280 subDir = attrs.pop('subDir', None); | 330 subDir = attrs.pop('subDir', None); |
281 if subDir is None: | 331 if subDir is None: |
282 dir = join(self.dir, name) | 332 dir = join(self.dir, name) |
283 else: | 333 else: |
284 dir = join(self.dir, subDir, name) | 334 dir = join(self.dir, subDir, name) |
285 p = Project(self, name, srcDirs, deps, dir) | 335 p = Project(self, name, srcDirs, deps, javaCompliance, dir) |
286 p.checkstyleProj = attrs.pop('checkstyle', name) | 336 p.checkstyleProj = attrs.pop('checkstyle', name) |
287 p.native = attrs.pop('native', '') == 'true' | 337 p.native = attrs.pop('native', '') == 'true' |
338 if not p.native and p.javaCompliance is None: | |
339 abort('javaCompliance property required for non-native project ' + name) | |
288 p.__dict__.update(attrs) | 340 p.__dict__.update(attrs) |
289 self.projects.append(p) | 341 self.projects.append(p) |
290 | 342 |
291 for name, attrs in libsMap.iteritems(): | 343 for name, attrs in libsMap.iteritems(): |
292 path = attrs.pop('path') | 344 path = attrs.pop('path') |
293 mustExist = attrs.pop('optional', 'false') != 'true' | 345 mustExist = attrs.pop('optional', 'false') != 'true' |
294 urls = pop_list(attrs, 'urls') | 346 urls = pop_list(attrs, 'urls') |
295 l = Library(self, name, path, mustExist, urls) | 347 l = Library(self, name, path, mustExist, urls) |
296 l.__dict__.update(attrs) | 348 l.__dict__.update(attrs) |
297 self.libs.append(l) | 349 self.libs.append(l) |
298 | 350 |
299 def _load_commands(self, mxDir): | 351 def _load_commands(self, mxDir): |
300 commands = join(mxDir, 'commands.py') | 352 commands = join(mxDir, 'commands.py') |
301 if exists(commands): | 353 if exists(commands): |
302 # temporarily extend the Python path | 354 # temporarily extend the Python path |
303 sys.path.insert(0, mxDir) | 355 sys.path.insert(0, mxDir) |
304 | 356 |
305 mod = __import__('commands') | 357 mod = __import__('commands') |
306 | 358 |
307 # revert the Python path | 359 # revert the Python path |
308 del sys.path[0] | 360 del sys.path[0] |
309 | 361 |
310 if not hasattr(mod, 'mx_init'): | 362 if not hasattr(mod, 'mx_init'): |
311 abort(commands + ' must define an mx_init(env) function') | 363 abort(commands + ' must define an mx_init(env) function') |
312 if hasattr(mod, 'mx_post_parse_cmd_line'): | 364 if hasattr(mod, 'mx_post_parse_cmd_line'): |
313 self.mx_post_parse_cmd_line = mod.mx_post_parse_cmd_line | 365 self.mx_post_parse_cmd_line = mod.mx_post_parse_cmd_line |
314 | 366 |
315 mod.mx_init() | 367 mod.mx_init() |
316 self.commands = mod | 368 self.commands = mod |
317 | 369 |
318 def _load_includes(self, mxDir): | 370 def _load_includes(self, mxDir): |
319 includes = join(mxDir, 'includes') | 371 includes = join(mxDir, 'includes') |
320 if exists(includes): | 372 if exists(includes): |
321 with open(includes) as f: | 373 with open(includes) as f: |
322 for line in f: | 374 for line in f: |
323 self.includes.append(expandvars_in_property(line.strip())) | 375 self.includes.append(expandvars_in_property(line.strip())) |
324 | 376 |
325 def _load_env(self, mxDir): | 377 def _load_env(self, mxDir): |
326 e = join(mxDir, 'env') | 378 e = join(mxDir, 'env') |
327 if exists(e): | 379 if exists(e): |
328 with open(e) as f: | 380 with open(e) as f: |
329 for line in f: | 381 for line in f: |
330 line = line.strip() | 382 line = line.strip() |
331 if len(line) != 0 and line[0] != '#': | 383 if len(line) != 0 and line[0] != '#': |
332 key, value = line.split('=', 1) | 384 key, value = line.split('=', 1) |
333 os.environ[key.strip()] = expandvars_in_property(value.strip()) | 385 os.environ[key.strip()] = expandvars_in_property(value.strip()) |
334 | 386 |
335 def _post_init(self, opts): | 387 def _post_init(self, opts): |
336 mxDir = join(self.dir, 'mx') | 388 mxDir = join(self.dir, 'mx') |
337 self._load_includes(mxDir) | 389 self._load_includes(mxDir) |
338 self._load_projects(mxDir) | 390 self._load_projects(mxDir) |
339 if self.mx_post_parse_cmd_line is not None: | 391 if self.mx_post_parse_cmd_line is not None: |
346 for l in self.libs: | 398 for l in self.libs: |
347 existing = _libs.get(l.name) | 399 existing = _libs.get(l.name) |
348 if existing is not None: | 400 if existing is not None: |
349 abort('cannot redefine library ' + l.name) | 401 abort('cannot redefine library ' + l.name) |
350 _libs[l.name] = l | 402 _libs[l.name] = l |
351 | 403 |
352 def get_os(): | 404 def get_os(): |
353 """ | 405 """ |
354 Get a canonical form of sys.platform. | 406 Get a canonical form of sys.platform. |
355 """ | 407 """ |
356 if sys.platform.startswith('darwin'): | 408 if sys.platform.startswith('darwin'): |
369 if not exists(mxDir) or not isdir(mxDir): | 421 if not exists(mxDir) or not isdir(mxDir): |
370 return None | 422 return None |
371 if not _suites.has_key(dir): | 423 if not _suites.has_key(dir): |
372 suite = Suite(dir, primary) | 424 suite = Suite(dir, primary) |
373 _suites[dir] = suite | 425 _suites[dir] = suite |
374 return suite | 426 return suite |
375 | 427 |
376 def suites(): | 428 def suites(): |
377 """ | 429 """ |
378 Get the list of all loaded suites. | 430 Get the list of all loaded suites. |
379 """ | 431 """ |
382 def projects(): | 434 def projects(): |
383 """ | 435 """ |
384 Get the list of all loaded projects. | 436 Get the list of all loaded projects. |
385 """ | 437 """ |
386 return _projects.values() | 438 return _projects.values() |
387 | 439 |
388 def project(name, fatalIfMissing=True): | 440 def project(name, fatalIfMissing=True): |
389 """ | 441 """ |
390 Get the project for a given name. This will abort if the named project does | 442 Get the project for a given name. This will abort if the named project does |
391 not exist and 'fatalIfMissing' is true. | 443 not exist and 'fatalIfMissing' is true. |
392 """ | 444 """ |
419 """ | 471 """ |
420 Get the class path for a list of given projects, resolving each entry in the | 472 Get the class path for a list of given projects, resolving each entry in the |
421 path (e.g. downloading a missing library) if 'resolve' is true. | 473 path (e.g. downloading a missing library) if 'resolve' is true. |
422 """ | 474 """ |
423 if names is None: | 475 if names is None: |
424 return _as_classpath(sorted_deps(True), resolve) | 476 return _as_classpath(sorted_deps(includeLibs=True), resolve) |
425 deps = [] | 477 deps = [] |
426 if isinstance(names, types.StringTypes): | 478 if isinstance(names, types.StringTypes): |
427 project(names).all_deps(deps, True, includeSelf) | 479 project(names).all_deps(deps, True, includeSelf) |
428 else: | 480 else: |
429 for n in names: | 481 for n in names: |
430 project(n).all_deps(deps, True, includeSelf) | 482 project(n).all_deps(deps, True, includeSelf) |
431 return _as_classpath(deps, resolve) | 483 return _as_classpath(deps, resolve) |
432 | 484 |
433 def sorted_deps(includeLibs=False): | 485 def sorted_deps(projectNames=None, includeLibs=False): |
434 """ | 486 """ |
435 Gets the loaded projects and libraries sorted such that dependencies | 487 Gets projects and libraries sorted such that dependencies |
436 are before the projects that depend on them. Unless 'includeLibs' is | 488 are before the projects that depend on them. Unless 'includeLibs' is |
437 true, libraries are omitted from the result. | 489 true, libraries are omitted from the result. |
438 """ | 490 """ |
439 deps = [] | 491 deps = [] |
440 for p in _projects.itervalues(): | 492 if projectNames is None: |
493 projects = _projects.values() | |
494 else: | |
495 projects = [project(name) for name in projectNames] | |
496 | |
497 for p in projects: | |
441 p.all_deps(deps, includeLibs) | 498 p.all_deps(deps, includeLibs) |
442 return deps | 499 return deps |
443 | 500 |
444 class ArgParser(ArgumentParser): | 501 class ArgParser(ArgumentParser): |
445 | 502 |
446 # Override parent to append the list of available commands | 503 # Override parent to append the list of available commands |
447 def format_help(self): | 504 def format_help(self): |
448 return ArgumentParser.format_help(self) + _format_commands() | 505 return ArgumentParser.format_help(self) + _format_commands() |
449 | 506 |
450 | 507 |
451 def __init__(self): | 508 def __init__(self): |
452 self.java_initialized = False | 509 self.java_initialized = False |
453 ArgumentParser.__init__(self, prog='mx') | 510 ArgumentParser.__init__(self, prog='mx') |
454 | 511 |
455 self.add_argument('-v', action='store_true', dest='verbose', help='enable verbose output') | 512 self.add_argument('-v', action='store_true', dest='verbose', help='enable verbose output') |
456 self.add_argument('-d', action='store_true', dest='java_dbg', help='make Java processes wait on port 8000 for a debugger') | 513 self.add_argument('--dbg', type=int, dest='java_dbg_port', help='make Java processes wait on <port> for a debugger', metavar='<port>') |
514 self.add_argument('-d', action='store_const', const=8000, dest='java_dbg_port', help='alias for "-dbg 8000"') | |
457 self.add_argument('--cp-pfx', dest='cp_prefix', help='class path prefix', metavar='<arg>') | 515 self.add_argument('--cp-pfx', dest='cp_prefix', help='class path prefix', metavar='<arg>') |
458 self.add_argument('--cp-sfx', dest='cp_suffix', help='class path suffix', metavar='<arg>') | 516 self.add_argument('--cp-sfx', dest='cp_suffix', help='class path suffix', metavar='<arg>') |
459 self.add_argument('--J', dest='java_args', help='Java VM arguments (e.g. --J @-dsa)', metavar='@<args>', default=DEFAULT_JAVA_ARGS) | 517 self.add_argument('--J', dest='java_args', help='Java VM arguments (e.g. --J @-dsa)', metavar='@<args>', default=DEFAULT_JAVA_ARGS) |
460 self.add_argument('--Jp', action='append', dest='java_args_pfx', help='prefix Java VM arguments (e.g. --Jp @-dsa)', metavar='@<args>', default=[]) | 518 self.add_argument('--Jp', action='append', dest='java_args_pfx', help='prefix Java VM arguments (e.g. --Jp @-dsa)', metavar='@<args>', default=[]) |
461 self.add_argument('--Ja', action='append', dest='java_args_sfx', help='suffix Java VM arguments (e.g. --Ja @-dsa)', metavar='@<args>', default=[]) | 519 self.add_argument('--Ja', action='append', dest='java_args_sfx', help='suffix Java VM arguments (e.g. --Ja @-dsa)', metavar='@<args>', default=[]) |
463 self.add_argument('--java-home', help='JDK installation directory (must be JDK 6 or later)', metavar='<path>') | 521 self.add_argument('--java-home', help='JDK installation directory (must be JDK 6 or later)', metavar='<path>') |
464 if get_os() != 'windows': | 522 if get_os() != 'windows': |
465 # Time outs are (currently) implemented with Unix specific functionality | 523 # Time outs are (currently) implemented with Unix specific functionality |
466 self.add_argument('--timeout', help='Timeout (in seconds) for command', type=int, default=0, metavar='<secs>') | 524 self.add_argument('--timeout', help='Timeout (in seconds) for command', type=int, default=0, metavar='<secs>') |
467 self.add_argument('--ptimeout', help='Timeout (in seconds) for subprocesses', type=int, default=0, metavar='<secs>') | 525 self.add_argument('--ptimeout', help='Timeout (in seconds) for subprocesses', type=int, default=0, metavar='<secs>') |
468 | 526 |
469 def _parse_cmd_line(self, args=None): | 527 def _parse_cmd_line(self, args=None): |
470 if args is None: | 528 if args is None: |
471 args = sys.argv[1:] | 529 args = sys.argv[1:] |
472 | 530 |
473 self.add_argument('commandAndArgs', nargs=REMAINDER, metavar='command args...') | 531 self.add_argument('commandAndArgs', nargs=REMAINDER, metavar='command args...') |
474 | 532 |
475 opts = self.parse_args() | 533 opts = self.parse_args() |
476 | 534 |
477 # Give the timeout options a default value to avoid the need for hasattr() tests | 535 # Give the timeout options a default value to avoid the need for hasattr() tests |
478 opts.__dict__.setdefault('timeout', 0) | 536 opts.__dict__.setdefault('timeout', 0) |
479 opts.__dict__.setdefault('ptimeout', 0) | 537 opts.__dict__.setdefault('ptimeout', 0) |
480 | 538 |
481 if opts.java_home is None: | 539 if opts.java_home is None: |
484 if opts.java_home is None or opts.java_home == '': | 542 if opts.java_home is None or opts.java_home == '': |
485 abort('Could not find Java home. Use --java-home option or ensure JAVA_HOME environment variable is set.') | 543 abort('Could not find Java home. Use --java-home option or ensure JAVA_HOME environment variable is set.') |
486 | 544 |
487 if opts.user_home is None or opts.user_home == '': | 545 if opts.user_home is None or opts.user_home == '': |
488 abort('Could not find user home. Use --user-home option or ensure HOME environment variable is set.') | 546 abort('Could not find user home. Use --user-home option or ensure HOME environment variable is set.') |
489 | 547 |
490 os.environ['JAVA_HOME'] = opts.java_home | 548 os.environ['JAVA_HOME'] = opts.java_home |
491 os.environ['HOME'] = opts.user_home | 549 os.environ['HOME'] = opts.user_home |
492 | 550 |
493 commandAndArgs = opts.__dict__.pop('commandAndArgs') | 551 commandAndArgs = opts.__dict__.pop('commandAndArgs') |
494 return opts, commandAndArgs | 552 return opts, commandAndArgs |
495 | 553 |
496 def _format_commands(): | 554 def _format_commands(): |
497 msg = '\navailable commands:\n\n' | 555 msg = '\navailable commands:\n\n' |
498 for cmd in sorted(commands.iterkeys()): | 556 for cmd in sorted(commands.iterkeys()): |
499 c, _ = commands[cmd][:2] | 557 c, _ = commands[cmd][:2] |
500 doc = c.__doc__ | 558 doc = c.__doc__ |
529 return os.waitpid(pid, os.WNOHANG) | 587 return os.waitpid(pid, os.WNOHANG) |
530 except OSError, e: | 588 except OSError, e: |
531 if e.errno == errno.EINTR: | 589 if e.errno == errno.EINTR: |
532 continue | 590 continue |
533 raise | 591 raise |
534 | 592 |
535 def _returncode(status): | 593 def _returncode(status): |
536 if os.WIFSIGNALED(status): | 594 if os.WIFSIGNALED(status): |
537 return -os.WTERMSIG(status) | 595 return -os.WTERMSIG(status) |
538 elif os.WIFEXITED(status): | 596 elif os.WIFEXITED(status): |
539 return os.WEXITSTATUS(status) | 597 return os.WEXITSTATUS(status) |
540 else: | 598 else: |
541 # Should never happen | 599 # Should never happen |
542 raise RuntimeError("Unknown child exit status!") | 600 raise RuntimeError("Unknown child exit status!") |
543 | 601 |
544 end = time.time() + timeout | 602 end = time.time() + timeout |
545 delay = 0.0005 | 603 delay = 0.0005 |
546 while True: | 604 while True: |
547 (pid, status) = _waitpid(process.pid) | 605 (pid, status) = _waitpid(process.pid) |
548 if pid == process.pid: | 606 if pid == process.pid: |
574 If the exit status is non-zero and `nonZeroIsFatal` is true, then mx is exited with | 632 If the exit status is non-zero and `nonZeroIsFatal` is true, then mx is exited with |
575 the same exit status. | 633 the same exit status. |
576 Each line of the standard output and error streams of the subprocess are redirected to | 634 Each line of the standard output and error streams of the subprocess are redirected to |
577 out and err if they are callable objects. | 635 out and err if they are callable objects. |
578 """ | 636 """ |
579 | 637 |
580 assert isinstance(args, types.ListType), "'args' must be a list: " + str(args) | 638 assert isinstance(args, types.ListType), "'args' must be a list: " + str(args) |
581 for arg in args: | 639 for arg in args: |
582 assert isinstance(arg, types.StringTypes), 'argument is not a string: ' + str(arg) | 640 assert isinstance(arg, types.StringTypes), 'argument is not a string: ' + str(arg) |
583 | 641 |
584 if _opts.verbose: | 642 if _opts.verbose: |
585 log(' '.join(args)) | 643 log(' '.join(args)) |
586 | 644 |
587 if timeout is None and _opts.ptimeout != 0: | 645 if timeout is None and _opts.ptimeout != 0: |
588 timeout = _opts.ptimeout | 646 timeout = _opts.ptimeout |
589 | 647 |
590 global _currentSubprocess | 648 global _currentSubprocess |
591 | 649 |
592 try: | 650 try: |
593 # On Unix, the new subprocess should be in a separate group so that a timeout alarm | 651 # On Unix, the new subprocess should be in a separate group so that a timeout alarm |
594 # can use os.killpg() to kill the whole subprocess group | 652 # can use os.killpg() to kill the whole subprocess group |
595 preexec_fn = None | 653 preexec_fn = None |
596 creationflags = 0 | 654 creationflags = 0 |
597 if get_os() == 'windows': | 655 if get_os() == 'windows': |
598 creationflags = subprocess.CREATE_NEW_PROCESS_GROUP | 656 creationflags = subprocess.CREATE_NEW_PROCESS_GROUP |
599 else: | 657 else: |
600 preexec_fn = os.setsid | 658 preexec_fn = os.setsid |
601 | 659 |
602 if not callable(out) and not callable(err) and timeout is None: | 660 if not callable(out) and not callable(err) and timeout is None: |
603 # The preexec_fn=os.setsid | 661 # The preexec_fn=os.setsid |
604 p = subprocess.Popen(args, cwd=cwd, preexec_fn=preexec_fn, creationflags=creationflags) | 662 p = subprocess.Popen(args, cwd=cwd, preexec_fn=preexec_fn, creationflags=creationflags) |
605 _currentSubprocess = (p, args) | 663 _currentSubprocess = (p, args) |
606 retcode = waitOn(p) | 664 retcode = waitOn(p) |
607 else: | 665 else: |
608 def redirect(stream, f): | 666 def redirect(stream, f): |
609 for line in iter(stream.readline, ''): | 667 for line in iter(stream.readline, ''): |
610 f(line) | 668 f(line) |
611 stream.close() | 669 stream.close() |
639 | 697 |
640 if retcode and nonZeroIsFatal: | 698 if retcode and nonZeroIsFatal: |
641 if _opts.verbose: | 699 if _opts.verbose: |
642 raise subprocess.CalledProcessError(retcode, ' '.join(args)) | 700 raise subprocess.CalledProcessError(retcode, ' '.join(args)) |
643 abort(retcode) | 701 abort(retcode) |
644 | 702 |
645 return retcode | 703 return retcode |
646 | 704 |
647 def exe_suffix(name): | 705 def exe_suffix(name): |
648 """ | 706 """ |
649 Gets the platform specific suffix for an executable | 707 Gets the platform specific suffix for an executable |
650 """ | 708 """ |
651 if get_os() == 'windows': | 709 if get_os() == 'windows': |
652 return name + '.exe' | 710 return name + '.exe' |
653 return name | 711 return name |
654 | 712 |
662 if os == 'linux': | 720 if os == 'linux': |
663 return name + '.so' | 721 return name + '.so' |
664 return name | 722 return name |
665 | 723 |
666 """ | 724 """ |
725 A JavaCompliance simplifies comparing Java compliance values extracted from a JDK version string. | |
726 """ | |
727 class JavaCompliance: | |
728 def __init__(self, ver): | |
729 m = re.match('1\.(\d+).*', ver) | |
730 assert m is not None, 'not a recognized version string: ' + vstring | |
731 self.value = int(m.group(1)) | |
732 | |
733 def __str__ (self): | |
734 return '1.' + str(self.value) | |
735 | |
736 def __cmp__ (self, other): | |
737 if isinstance(other, types.StringType): | |
738 other = JavaCompliance(other) | |
739 | |
740 return cmp(self.value, other.value) | |
741 | |
742 """ | |
667 A JavaConfig object encapsulates info on how Java commands are run. | 743 A JavaConfig object encapsulates info on how Java commands are run. |
668 """ | 744 """ |
669 class JavaConfig: | 745 class JavaConfig: |
670 def __init__(self, opts): | 746 def __init__(self, opts): |
671 self.jdk = opts.java_home | 747 self.jdk = opts.java_home |
672 self.debug = opts.java_dbg | 748 self.debug_port = opts.java_dbg_port |
673 self.java = exe_suffix(join(self.jdk, 'bin', 'java')) | 749 self.java = exe_suffix(join(self.jdk, 'bin', 'java')) |
674 self.javac = exe_suffix(join(self.jdk, 'bin', 'javac')) | 750 self.javac = exe_suffix(join(self.jdk, 'bin', 'javac')) |
675 self.javap = exe_suffix(join(self.jdk, 'bin', 'javap')) | 751 self.javap = exe_suffix(join(self.jdk, 'bin', 'javap')) |
676 | 752 |
677 if not exists(self.java): | 753 if not exists(self.java): |
678 abort('Java launcher derived from JAVA_HOME does not exist: ' + self.java) | 754 abort('Java launcher derived from JAVA_HOME does not exist: ' + self.java) |
679 | 755 |
680 def delAtAndSplit(s): | 756 def delAtAndSplit(s): |
681 return shlex.split(s.lstrip('@')) | 757 return shlex.split(s.lstrip('@')) |
682 | 758 |
683 self.java_args = delAtAndSplit(_opts.java_args) | 759 self.java_args = delAtAndSplit(_opts.java_args) |
684 self.java_args_pfx = sum(map(delAtAndSplit, _opts.java_args_pfx), []) | 760 self.java_args_pfx = sum(map(delAtAndSplit, _opts.java_args_pfx), []) |
685 self.java_args_sfx = sum(map(delAtAndSplit, _opts.java_args_sfx), []) | 761 self.java_args_sfx = sum(map(delAtAndSplit, _opts.java_args_sfx), []) |
686 | 762 |
687 # Prepend the -d64 VM option only if the java command supports it | 763 # Prepend the -d64 VM option only if the java command supports it |
688 try: | 764 try: |
689 output = subprocess.check_output([self.java, '-d64', '-version'], stderr=subprocess.STDOUT) | 765 output = subprocess.check_output([self.java, '-d64', '-version'], stderr=subprocess.STDOUT) |
690 self.java_args = ['-d64'] + self.java_args | 766 self.java_args = ['-d64'] + self.java_args |
691 except subprocess.CalledProcessError as e: | 767 except subprocess.CalledProcessError as e: |
692 try: | 768 try: |
693 output = subprocess.check_output([self.java, '-version'], stderr=subprocess.STDOUT) | 769 output = subprocess.check_output([self.java, '-version'], stderr=subprocess.STDOUT) |
694 except subprocess.CalledProcessError as e: | 770 except subprocess.CalledProcessError as e: |
695 print e.output | 771 print e.output |
696 abort(e.returncode) | 772 abort(e.returncode) |
697 | 773 |
698 output = output.split() | 774 output = output.split() |
699 assert output[1] == 'version' | 775 assert output[1] == 'version' |
700 self.version = output[2].strip('"') | 776 self.version = output[2].strip('"') |
701 | 777 self.javaCompliance = JavaCompliance(self.version) |
702 if self.debug: | 778 |
703 self.java_args += ['-Xdebug', '-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000'] | 779 if self.debug_port is not None: |
780 self.java_args += ['-Xdebug', '-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(self.debug_port)] | |
704 | 781 |
705 def format_cmd(self, args): | 782 def format_cmd(self, args): |
706 return [self.java] + self.java_args_pfx + self.java_args + self.java_args_sfx + args | 783 return [self.java] + self.java_args_pfx + self.java_args + self.java_args_sfx + args |
707 | 784 |
708 def check_get_env(key): | 785 def check_get_env(key): |
709 """ | 786 """ |
710 Gets an environment variable, aborting with a useful message if it is not set. | 787 Gets an environment variable, aborting with a useful message if it is not set. |
711 """ | 788 """ |
712 value = get_env(key) | 789 value = get_env(key) |
723 | 800 |
724 def log(msg=None): | 801 def log(msg=None): |
725 """ | 802 """ |
726 Write a message to the console. | 803 Write a message to the console. |
727 All script output goes through this method thus allowing a subclass | 804 All script output goes through this method thus allowing a subclass |
728 to redirect it. | 805 to redirect it. |
729 """ | 806 """ |
730 if msg is None: | 807 if msg is None: |
731 print | 808 print |
732 else: | 809 else: |
733 print msg | 810 print msg |
738 if part.startswith('@'): | 815 if part.startswith('@'): |
739 cp += classpath(part[1:]).split(os.pathsep) | 816 cp += classpath(part[1:]).split(os.pathsep) |
740 else: | 817 else: |
741 cp.append(part) | 818 cp.append(part) |
742 return os.pathsep.join(cp) | 819 return os.pathsep.join(cp) |
743 | 820 |
744 def expand_project_in_args(args): | 821 def expand_project_in_args(args): |
745 for i in range(len(args)): | 822 for i in range(len(args)): |
746 if args[i] == '-cp' or args[i] == '-classpath': | 823 if args[i] == '-cp' or args[i] == '-classpath': |
747 if i + 1 < len(args): | 824 if i + 1 < len(args): |
748 args[i + 1] = expand_project_in_class_path_arg(args[i + 1]) | 825 args[i + 1] = expand_project_in_class_path_arg(args[i + 1]) |
763 result = expandvars(value) | 840 result = expandvars(value) |
764 if '$' in result or '%' in result: | 841 if '$' in result or '%' in result: |
765 abort('Property contains an undefined environment variable: ' + value) | 842 abort('Property contains an undefined environment variable: ' + value) |
766 return result | 843 return result |
767 | 844 |
768 | 845 |
769 def abort(codeOrMessage): | 846 def abort(codeOrMessage): |
770 """ | 847 """ |
771 Aborts the program with a SystemExit exception. | 848 Aborts the program with a SystemExit exception. |
772 If 'codeOrMessage' is a plain integer, it specifies the system exit status; | 849 If 'codeOrMessage' is a plain integer, it specifies the system exit status; |
773 if it is None, the exit status is zero; if it has another type (such as a string), | 850 if it is None, the exit status is zero; if it has another type (such as a string), |
774 the object's value is printed and the exit status is one. | 851 the object's value is printed and the exit status is one. |
775 """ | 852 """ |
776 | 853 |
777 #import traceback | 854 #import traceback |
778 #traceback.print_stack() | 855 #traceback.print_stack() |
779 currentSubprocess = _currentSubprocess | 856 currentSubprocess = _currentSubprocess |
780 if currentSubprocess is not None: | 857 if currentSubprocess is not None: |
781 p, _ = currentSubprocess | 858 p, _ = currentSubprocess |
782 if get_os() == 'windows': | 859 if get_os() == 'windows': |
783 p.kill() | 860 p.kill() |
784 else: | 861 else: |
785 _kill_process_group(p.pid) | 862 _kill_process_group(p.pid) |
786 | 863 |
787 raise SystemExit(codeOrMessage) | 864 raise SystemExit(codeOrMessage) |
788 | 865 |
789 def download(path, urls, verbose=False): | 866 def download(path, urls, verbose=False): |
790 """ | 867 """ |
791 Attempts to downloads content for each URL in a list, stopping after the first successful download. | 868 Attempts to downloads content for each URL in a list, stopping after the first successful download. |
793 is written to the file indicated by 'path'. | 870 is written to the file indicated by 'path'. |
794 """ | 871 """ |
795 d = dirname(path) | 872 d = dirname(path) |
796 if d != '' and not exists(d): | 873 if d != '' and not exists(d): |
797 os.makedirs(d) | 874 os.makedirs(d) |
798 | 875 |
799 # Try it with the Java tool first since it can show a progress counter | 876 # Try it with the Java tool first since it can show a progress counter |
800 myDir = dirname(__file__) | 877 myDir = dirname(__file__) |
801 | 878 |
802 javaSource = join(myDir, 'URLConnectionDownload.java') | 879 javaSource = join(myDir, 'URLConnectionDownload.java') |
803 javaClass = join(myDir, 'URLConnectionDownload.class') | 880 javaClass = join(myDir, 'URLConnectionDownload.class') |
804 if not exists(javaClass) or getmtime(javaClass) < getmtime(javaSource): | 881 if not exists(javaClass) or getmtime(javaClass) < getmtime(javaSource): |
805 subprocess.check_call([java().javac, '-d', myDir, javaSource]) | 882 subprocess.check_call([java().javac, '-d', myDir, javaSource]) |
806 if run([java().java, '-cp', myDir, 'URLConnectionDownload', path] + urls) == 0: | 883 if run([java().java, '-cp', myDir, 'URLConnectionDownload', path] + urls) == 0: |
807 return | 884 return |
808 | 885 |
809 def url_open(url): | 886 def url_open(url): |
810 userAgent = 'Mozilla/5.0 (compatible)' | 887 userAgent = 'Mozilla/5.0 (compatible)' |
811 headers = { 'User-Agent' : userAgent } | 888 headers = { 'User-Agent' : userAgent } |
812 req = urllib2.Request(url, headers=headers) | 889 req = urllib2.Request(url, headers=headers) |
813 return urllib2.urlopen(req); | 890 return urllib2.urlopen(req); |
814 | 891 |
815 for url in urls: | 892 for url in urls: |
816 try: | 893 try: |
817 if (verbose): | 894 if (verbose): |
818 log('Downloading ' + url + ' to ' + path) | 895 log('Downloading ' + url + ' to ' + path) |
819 if url.startswith('zip:') or url.startswith('jar:'): | 896 if url.startswith('zip:') or url.startswith('jar:'): |
822 abort('Zip or jar URL does not contain "!/": ' + url) | 899 abort('Zip or jar URL does not contain "!/": ' + url) |
823 url, _, entry = url[len('zip:'):].partition('!/') | 900 url, _, entry = url[len('zip:'):].partition('!/') |
824 with contextlib.closing(url_open(url)) as f: | 901 with contextlib.closing(url_open(url)) as f: |
825 data = f.read() | 902 data = f.read() |
826 zipdata = StringIO.StringIO(f.read()) | 903 zipdata = StringIO.StringIO(f.read()) |
827 | 904 |
828 zf = zipfile.ZipFile(zipdata, 'r') | 905 zf = zipfile.ZipFile(zipdata, 'r') |
829 data = zf.read(entry) | 906 data = zf.read(entry) |
830 with open(path, 'wb') as f: | 907 with open(path, 'wb') as f: |
831 f.write(data) | 908 f.write(data) |
832 else: | 909 else: |
837 return | 914 return |
838 except IOError as e: | 915 except IOError as e: |
839 log('Error reading from ' + url + ': ' + str(e)) | 916 log('Error reading from ' + url + ': ' + str(e)) |
840 except zipfile.BadZipfile as e: | 917 except zipfile.BadZipfile as e: |
841 log('Error in zip file downloaded from ' + url + ': ' + str(e)) | 918 log('Error in zip file downloaded from ' + url + ': ' + str(e)) |
842 | 919 |
843 abort('Could not download to ' + path + ' from any of the following URLs:\n\n ' + | 920 abort('Could not download to ' + path + ' from any of the following URLs:\n\n ' + |
844 '\n '.join(urls) + '\n\nPlease use a web browser to do the download manually') | 921 '\n '.join(urls) + '\n\nPlease use a web browser to do the download manually') |
845 | 922 |
846 def update_file(path, content): | 923 def update_file(path, content): |
847 """ | 924 """ |
848 Updates a file with some given content if the content differs from what's in | 925 Updates a file with some given content if the content differs from what's in |
849 the file already. The return value indicates if the file was updated. | 926 the file already. The return value indicates if the file was updated. |
850 """ | 927 """ |
852 try: | 929 try: |
853 old = None | 930 old = None |
854 if existed: | 931 if existed: |
855 with open(path, 'rb') as f: | 932 with open(path, 'rb') as f: |
856 old = f.read() | 933 old = f.read() |
857 | 934 |
858 if old == content: | 935 if old == content: |
859 return False | 936 return False |
860 | 937 |
861 with open(path, 'wb') as f: | 938 with open(path, 'wb') as f: |
862 f.write(content) | 939 f.write(content) |
863 | 940 |
864 log(('modified ' if existed else 'created ') + path) | 941 log(('modified ' if existed else 'created ') + path) |
865 return True; | 942 return True; |
866 except IOError as e: | 943 except IOError as e: |
867 abort('Error while writing to ' + path + ': ' + str(e)); | 944 abort('Error while writing to ' + path + ': ' + str(e)); |
868 | 945 |
869 # Builtin commands | 946 # Builtin commands |
870 | 947 |
871 def build(args, parser=None): | 948 def build(args, parser=None): |
872 """compile the Java and C sources, linking the latter | 949 """compile the Java and C sources, linking the latter |
873 | 950 |
874 Compile all the Java source code using the appropriate compilers | 951 Compile all the Java source code using the appropriate compilers |
875 and linkers for the various source code types.""" | 952 and linkers for the various source code types.""" |
876 | 953 |
877 suppliedParser = parser is not None | 954 suppliedParser = parser is not None |
878 if not suppliedParser: | 955 if not suppliedParser: |
879 parser = ArgumentParser(prog='mx build') | 956 parser = ArgumentParser(prog='mx build') |
880 | 957 |
958 javaCompliance = java().javaCompliance | |
959 | |
881 parser = parser if parser is not None else ArgumentParser(prog='mx build') | 960 parser = parser if parser is not None else ArgumentParser(prog='mx build') |
882 parser.add_argument('-f', action='store_true', dest='force', help='force compilation even if class files are up to date') | 961 parser.add_argument('-f', action='store_true', dest='force', help='force compilation even if class files are up to date') |
883 parser.add_argument('-c', action='store_true', dest='clean', help='removes existing build output') | 962 parser.add_argument('-c', action='store_true', dest='clean', help='removes existing build output') |
884 parser.add_argument('--source', dest='compliance', help='Java compliance level', default='1.6') | 963 parser.add_argument('--source', dest='compliance', help='Java compliance level', default=str(javaCompliance)) |
885 parser.add_argument('--Wapi', action='store_true', dest='warnAPI', help='show warnings about using internal APIs') | 964 parser.add_argument('--Wapi', action='store_true', dest='warnAPI', help='show warnings about using internal APIs') |
965 parser.add_argument('--projects', action='store', help='comma separated projects to build (omit to build all projects)') | |
886 parser.add_argument('--no-java', action='store_false', dest='java', help='do not build Java projects') | 966 parser.add_argument('--no-java', action='store_false', dest='java', help='do not build Java projects') |
887 parser.add_argument('--no-native', action='store_false', dest='native', help='do not build native projects') | 967 parser.add_argument('--no-native', action='store_false', dest='native', help='do not build native projects') |
888 parser.add_argument('--jdt', help='Eclipse installation or path to ecj.jar for using the Eclipse batch compiler instead of javac', metavar='<path>') | 968 parser.add_argument('--jdt', help='Eclipse installation or path to ecj.jar for using the Eclipse batch compiler instead of javac', metavar='<path>') |
889 | 969 |
890 if suppliedParser: | 970 if suppliedParser: |
891 parser.add_argument('remainder', nargs=REMAINDER, metavar='...') | 971 parser.add_argument('remainder', nargs=REMAINDER, metavar='...') |
892 | 972 |
893 args = parser.parse_args(args) | 973 args = parser.parse_args(args) |
894 | 974 |
895 jdtJar = None | 975 jdtJar = None |
896 if args.jdt is not None: | 976 if args.jdt is not None: |
897 if args.jdt.endswith('.jar'): | 977 if args.jdt.endswith('.jar'): |
898 jdtJar=args.jdt | 978 jdtJar=args.jdt |
899 elif isdir(args.jdt): | 979 elif isdir(args.jdt): |
901 choices = [f for f in os.listdir(plugins) if fnmatch.fnmatch(f, 'org.eclipse.jdt.core_*.jar')] | 981 choices = [f for f in os.listdir(plugins) if fnmatch.fnmatch(f, 'org.eclipse.jdt.core_*.jar')] |
902 if len(choices) != 0: | 982 if len(choices) != 0: |
903 jdtJar = join(plugins, sorted(choices, reverse=True)[0]) | 983 jdtJar = join(plugins, sorted(choices, reverse=True)[0]) |
904 | 984 |
905 built = set() | 985 built = set() |
906 for p in sorted_deps(): | 986 |
907 | 987 projects = None |
988 if args.projects is not None: | |
989 projects = args.projects.split(',') | |
990 | |
991 for p in sorted_deps(projects): | |
908 if p.native: | 992 if p.native: |
909 if args.native: | 993 if args.native: |
910 log('Calling GNU make {0}...'.format(p.dir)) | 994 log('Calling GNU make {0}...'.format(p.dir)) |
911 | 995 |
912 if args.clean: | 996 if args.clean: |
913 run([gmake_cmd(), 'clean'], cwd=p.dir) | 997 run([gmake_cmd(), 'clean'], cwd=p.dir) |
914 | 998 |
915 run([gmake_cmd()], cwd=p.dir) | 999 run([gmake_cmd()], cwd=p.dir) |
916 built.add(p.name) | 1000 built.add(p.name) |
917 continue | 1001 continue |
918 else: | 1002 else: |
919 if not args.java: | 1003 if not args.java: |
920 continue | 1004 continue |
921 | 1005 |
922 | 1006 # skip building this Java project if its Java compliance level is "higher" than the configured JDK |
1007 if javaCompliance < p.javaCompliance: | |
1008 log('Excluding {0} from build (Java compliance level {1} required)'.format(p.name, p.javaCompliance)) | |
1009 continue | |
1010 | |
1011 | |
923 outputDir = p.output_dir() | 1012 outputDir = p.output_dir() |
924 if exists(outputDir): | 1013 if exists(outputDir): |
925 if args.clean: | 1014 if args.clean: |
926 log('Cleaning {0}...'.format(outputDir)) | 1015 log('Cleaning {0}...'.format(outputDir)) |
927 shutil.rmtree(outputDir) | 1016 shutil.rmtree(outputDir) |
934 mustBuild = args.force | 1023 mustBuild = args.force |
935 if not mustBuild: | 1024 if not mustBuild: |
936 for dep in p.all_deps([], False): | 1025 for dep in p.all_deps([], False): |
937 if dep.name in built: | 1026 if dep.name in built: |
938 mustBuild = True | 1027 mustBuild = True |
939 | 1028 |
1029 jasminAvailable = None | |
940 javafilelist = [] | 1030 javafilelist = [] |
941 for sourceDir in sourceDirs: | 1031 for sourceDir in sourceDirs: |
942 for root, _, files in os.walk(sourceDir): | 1032 for root, _, files in os.walk(sourceDir): |
943 javafiles = [join(root, name) for name in files if name.endswith('.java') and name != 'package-info.java'] | 1033 javafiles = [join(root, name) for name in files if name.endswith('.java') and name != 'package-info.java'] |
944 javafilelist += javafiles | 1034 javafilelist += javafiles |
945 | 1035 |
946 # Copy all non Java resources | 1036 # Copy all non Java resources or assemble Jasmin files |
947 nonjavafilelist = [join(root, name) for name in files if not name.endswith('.java')] | 1037 nonjavafilelist = [join(root, name) for name in files if not name.endswith('.java')] |
948 for src in nonjavafilelist: | 1038 for src in nonjavafilelist: |
949 dst = join(outputDir, src[len(sourceDir) + 1:]) | 1039 if src.endswith('.jasm'): |
950 if exists(dirname(dst)) and (not exists(dst) or os.path.getmtime(dst) != os.path.getmtime(src)): | 1040 className = None |
951 shutil.copyfile(src, dst) | 1041 with open(src) as f: |
952 | 1042 for line in f: |
1043 if line.startswith('.class '): | |
1044 className = line.split()[-1] | |
1045 break | |
1046 | |
1047 if className is not None: | |
1048 jasminOutputDir = p.jasmin_output_dir() | |
1049 classFile = join(jasminOutputDir, className.replace('/', os.sep) + '.class') | |
1050 if exists(dirname(classFile)) and (not exists(classFile) or os.path.getmtime(classFile) < os.path.getmtime(src)): | |
1051 if jasminAvailable is None: | |
1052 try: | |
1053 with open(os.devnull) as devnull: | |
1054 subprocess.call('jasmin', stdout=devnull, stderr=subprocess.STDOUT) | |
1055 jasminAvailable = True | |
1056 except OSError as e: | |
1057 jasminAvailable = False | |
1058 | |
1059 if jasminAvailable: | |
1060 log('Assembling Jasmin file ' + src) | |
1061 run(['jasmin', '-d', jasminOutputDir, src]) | |
1062 else: | |
1063 log('The jasmin executable could not be found - skipping ' + src) | |
1064 with file(classFile, 'a'): | |
1065 os.utime(classFile, None) | |
1066 | |
1067 else: | |
1068 log('could not file .class directive in Jasmin source: ' + src) | |
1069 else: | |
1070 dst = join(outputDir, src[len(sourceDir) + 1:]) | |
1071 if exists(dirname(dst)) and (not exists(dst) or os.path.getmtime(dst) != os.path.getmtime(src)): | |
1072 shutil.copyfile(src, dst) | |
1073 | |
953 if not mustBuild: | 1074 if not mustBuild: |
954 for javafile in javafiles: | 1075 for javafile in javafiles: |
955 classfile = outputDir + javafile[len(sourceDir):-len('java')] + 'class' | 1076 classfile = outputDir + javafile[len(sourceDir):-len('java')] + 'class' |
956 if not exists(classfile) or os.path.getmtime(javafile) > os.path.getmtime(classfile): | 1077 if not exists(classfile) or os.path.getmtime(javafile) > os.path.getmtime(classfile): |
957 mustBuild = True | 1078 mustBuild = True |
958 break | 1079 break |
959 | 1080 |
960 if not mustBuild: | 1081 if not mustBuild: |
961 log('[all class files for {0} are up to date - skipping]'.format(p.name)) | 1082 log('[all class files for {0} are up to date - skipping]'.format(p.name)) |
962 continue | 1083 continue |
963 | 1084 |
964 if len(javafilelist) == 0: | 1085 if len(javafilelist) == 0: |
965 log('[no Java sources for {0} - skipping]'.format(p.name)) | 1086 log('[no Java sources for {0} - skipping]'.format(p.name)) |
966 continue | 1087 continue |
967 | 1088 |
968 built.add(p.name) | 1089 built.add(p.name) |
969 | 1090 |
970 argfileName = join(p.dir, 'javafilelist.txt') | 1091 argfileName = join(p.dir, 'javafilelist.txt') |
971 argfile = open(argfileName, 'wb') | 1092 argfile = open(argfileName, 'wb') |
972 argfile.write('\n'.join(javafilelist)) | 1093 argfile.write('\n'.join(javafilelist)) |
973 argfile.close() | 1094 argfile.close() |
974 | 1095 |
975 try: | 1096 try: |
976 if jdtJar is None: | 1097 if jdtJar is None: |
977 log('Compiling Java sources for {0} with javac...'.format(p.name)) | 1098 log('Compiling Java sources for {0} with javac...'.format(p.name)) |
978 errFilt = None | 1099 errFilt = None |
979 if not args.warnAPI: | 1100 if not args.warnAPI: |
980 class Filter: | 1101 class Filter: |
981 """ | 1102 """ |
982 Class to errFilt the 'is Sun proprietary API and may be removed in a future release' | 1103 Class to errFilt the 'is Sun proprietary API and may be removed in a future release' |
983 warning when compiling the VM classes. | 1104 warning when compiling the VM classes. |
984 | 1105 |
985 """ | 1106 """ |
986 def __init__(self): | 1107 def __init__(self): |
987 self.c = 0 | 1108 self.c = 0 |
988 | 1109 |
989 def eat(self, line): | 1110 def eat(self, line): |
990 if 'proprietary API' in line: | 1111 if 'proprietary API' in line: |
991 self.c = 2 | 1112 self.c = 2 |
992 elif self.c != 0: | 1113 elif self.c != 0: |
993 self.c -= 1 | 1114 self.c -= 1 |
994 else: | 1115 else: |
995 log(line.rstrip()) | 1116 log(line.rstrip()) |
996 errFilt=Filter().eat | 1117 errFilt=Filter().eat |
997 | 1118 |
998 run([java().javac, '-g', '-J-Xmx1g', '-source', args.compliance, '-classpath', cp, '-d', outputDir, '@' + argfile.name], err=errFilt) | 1119 run([java().javac, '-g', '-J-Xmx1g', '-source', args.compliance, '-classpath', cp, '-d', outputDir, '@' + argfile.name], err=errFilt) |
999 else: | 1120 else: |
1000 log('Compiling Java sources for {0} with JDT...'.format(p.name)) | 1121 log('Compiling Java sources for {0} with JDT...'.format(p.name)) |
1001 jdtProperties = join(p.dir, '.settings', 'org.eclipse.jdt.core.prefs') | 1122 jdtProperties = join(p.dir, '.settings', 'org.eclipse.jdt.core.prefs') |
1002 if not exists(jdtProperties): | 1123 if not exists(jdtProperties): |
1007 '-cp', cp, '-g', | 1128 '-cp', cp, '-g', |
1008 '-warn:-unusedImport,-unchecked', | 1129 '-warn:-unusedImport,-unchecked', |
1009 '-d', outputDir, '@' + argfile.name]) | 1130 '-d', outputDir, '@' + argfile.name]) |
1010 finally: | 1131 finally: |
1011 os.remove(argfileName) | 1132 os.remove(argfileName) |
1012 | 1133 |
1013 if suppliedParser: | 1134 if suppliedParser: |
1014 return args | 1135 return args |
1015 return None | 1136 return None |
1016 | 1137 |
1017 def canonicalizeprojects(args): | 1138 def canonicalizeprojects(args): |
1018 """process all project files to canonicalize the dependencies | 1139 """process all project files to canonicalize the dependencies |
1019 | 1140 |
1020 The exit code of this command reflects how many files were updated.""" | 1141 The exit code of this command reflects how many files were updated.""" |
1021 | 1142 |
1022 changedFiles = 0 | 1143 changedFiles = 0 |
1023 for s in suites(): | 1144 for s in suites(): |
1024 projectsFile = join(s.dir, 'mx', 'projects') | 1145 projectsFile = join(s.dir, 'mx', 'projects') |
1025 if not exists(projectsFile): | 1146 if not exists(projectsFile): |
1026 continue | 1147 continue |
1037 out.write('project@' + m.group(1) + '@dependencies=' + ','.join(p.canonical_deps()) + '\n') | 1158 out.write('project@' + m.group(1) + '@dependencies=' + ','.join(p.canonical_deps()) + '\n') |
1038 content = out.getvalue() | 1159 content = out.getvalue() |
1039 if update_file(projectsFile, content): | 1160 if update_file(projectsFile, content): |
1040 changedFiles += 1 | 1161 changedFiles += 1 |
1041 return changedFiles; | 1162 return changedFiles; |
1042 | 1163 |
1043 def checkstyle(args): | 1164 def checkstyle(args): |
1044 """run Checkstyle on the Java sources | 1165 """run Checkstyle on the Java sources |
1045 | 1166 |
1046 Run Checkstyle over the Java sources. Any errors or warnings | 1167 Run Checkstyle over the Java sources. Any errors or warnings |
1047 produced by Checkstyle result in a non-zero exit code. | 1168 produced by Checkstyle result in a non-zero exit code. |
1048 | 1169 |
1049 If no projects are given, then all Java projects are checked.""" | 1170 If no projects are given, then all Java projects are checked.""" |
1050 | 1171 |
1051 for p in sorted_deps(): | 1172 for p in sorted_deps(): |
1052 if p.native: | 1173 if p.native: |
1053 continue | 1174 continue |
1054 sourceDirs = p.source_dirs() | 1175 sourceDirs = p.source_dirs() |
1055 dotCheckstyle = join(p.dir, '.checkstyle') | 1176 dotCheckstyle = join(p.dir, '.checkstyle') |
1056 | 1177 |
1057 if not exists(dotCheckstyle): | 1178 if not exists(dotCheckstyle): |
1058 continue | 1179 continue |
1059 | 1180 |
1060 for sourceDir in sourceDirs: | 1181 for sourceDir in sourceDirs: |
1061 javafilelist = [] | 1182 javafilelist = [] |
1062 for root, _, files in os.walk(sourceDir): | 1183 for root, _, files in os.walk(sourceDir): |
1063 javafilelist += [join(root, name) for name in files if name.endswith('.java') and name != 'package-info.java'] | 1184 javafilelist += [join(root, name) for name in files if name.endswith('.java') and name != 'package-info.java'] |
1064 if len(javafilelist) == 0: | 1185 if len(javafilelist) == 0: |
1073 if os.path.getmtime(f) > timestamp: | 1194 if os.path.getmtime(f) > timestamp: |
1074 mustCheck = True | 1195 mustCheck = True |
1075 break | 1196 break |
1076 else: | 1197 else: |
1077 mustCheck = True | 1198 mustCheck = True |
1078 | 1199 |
1079 if not mustCheck: | 1200 if not mustCheck: |
1080 log('[all Java sources in {0} already checked - skipping]'.format(sourceDir)) | 1201 log('[all Java sources in {0} already checked - skipping]'.format(sourceDir)) |
1081 continue | 1202 continue |
1082 | 1203 |
1083 if exists(timestampFile): | 1204 if exists(timestampFile): |
1084 os.utime(timestampFile, None) | 1205 os.utime(timestampFile, None) |
1085 else: | 1206 else: |
1086 file(timestampFile, 'a') | 1207 file(timestampFile, 'a') |
1087 | 1208 |
1088 dotCheckstyleXML = xml.dom.minidom.parse(dotCheckstyle) | 1209 dotCheckstyleXML = xml.dom.minidom.parse(dotCheckstyle) |
1089 localCheckConfig = dotCheckstyleXML.getElementsByTagName('local-check-config')[0] | 1210 localCheckConfig = dotCheckstyleXML.getElementsByTagName('local-check-config')[0] |
1090 configLocation = localCheckConfig.getAttribute('location') | 1211 configLocation = localCheckConfig.getAttribute('location') |
1091 configType = localCheckConfig.getAttribute('type') | 1212 configType = localCheckConfig.getAttribute('type') |
1092 if configType == 'project': | 1213 if configType == 'project': |
1100 else: | 1221 else: |
1101 config = join(p.dir, configLocation) | 1222 config = join(p.dir, configLocation) |
1102 else: | 1223 else: |
1103 log('[unknown Checkstyle configuration type "' + configType + '" in {0} - skipping]'.format(sourceDir)) | 1224 log('[unknown Checkstyle configuration type "' + configType + '" in {0} - skipping]'.format(sourceDir)) |
1104 continue | 1225 continue |
1105 | 1226 |
1106 exclude = join(p.dir, '.checkstyle.exclude') | 1227 exclude = join(p.dir, '.checkstyle.exclude') |
1107 | 1228 |
1108 if exists(exclude): | 1229 if exists(exclude): |
1109 with open(exclude) as f: | 1230 with open(exclude) as f: |
1110 # Convert patterns to OS separators | 1231 # Convert patterns to OS separators |
1111 patterns = [name.rstrip().replace('/', os.sep) for name in f.readlines()] | 1232 patterns = [name.rstrip().replace('/', os.sep) for name in f.readlines()] |
1112 def match(name): | 1233 def match(name): |
1113 for p in patterns: | 1234 for p in patterns: |
1114 if p in name: | 1235 if p in name: |
1115 log('excluding: ' + name) | 1236 if _opts.verbose: |
1237 log('excluding: ' + name) | |
1116 return True | 1238 return True |
1117 return False | 1239 return False |
1118 | 1240 |
1119 javafilelist = [name for name in javafilelist if not match(name)] | 1241 javafilelist = [name for name in javafilelist if not match(name)] |
1120 | 1242 |
1121 auditfileName = join(p.dir, 'checkstyleOutput.txt') | 1243 auditfileName = join(p.dir, 'checkstyleOutput.txt') |
1122 log('Running Checkstyle on {0} using {1}...'.format(sourceDir, config)) | 1244 log('Running Checkstyle on {0} using {1}...'.format(sourceDir, config)) |
1123 | 1245 |
1124 try: | 1246 try: |
1125 | 1247 |
1126 # Checkstyle is unable to read the filenames to process from a file, and the | 1248 # Checkstyle is unable to read the filenames to process from a file, and the |
1127 # CreateProcess function on Windows limits the length of a command line to | 1249 # CreateProcess function on Windows limits the length of a command line to |
1128 # 32,768 characters (http://msdn.microsoft.com/en-us/library/ms682425%28VS.85%29.aspx) | 1250 # 32,768 characters (http://msdn.microsoft.com/en-us/library/ms682425%28VS.85%29.aspx) |
1135 if (size + s < 30000): | 1257 if (size + s < 30000): |
1136 size += s | 1258 size += s |
1137 i += 1 | 1259 i += 1 |
1138 else: | 1260 else: |
1139 break | 1261 break |
1140 | 1262 |
1141 batch = javafilelist[:i] | 1263 batch = javafilelist[:i] |
1142 javafilelist = javafilelist[i:] | 1264 javafilelist = javafilelist[i:] |
1143 try: | 1265 try: |
1144 run_java(['-Xmx1g', '-jar', library('CHECKSTYLE').get_path(True), '-c', config, '-o', auditfileName] + batch) | 1266 run_java(['-Xmx1g', '-jar', library('CHECKSTYLE').get_path(True), '-c', config, '-o', auditfileName] + batch) |
1145 finally: | 1267 finally: |
1160 Removes all files created by a build, including Java class files, executables, and | 1282 Removes all files created by a build, including Java class files, executables, and |
1161 generated images. | 1283 generated images. |
1162 """ | 1284 """ |
1163 | 1285 |
1164 suppliedParser = parser is not None | 1286 suppliedParser = parser is not None |
1165 | 1287 |
1166 parser = parser if suppliedParser else ArgumentParser(prog='mx build'); | 1288 parser = parser if suppliedParser else ArgumentParser(prog='mx build'); |
1167 parser.add_argument('--no-native', action='store_false', dest='native', help='do not clean native projects') | 1289 parser.add_argument('--no-native', action='store_false', dest='native', help='do not clean native projects') |
1168 parser.add_argument('--no-java', action='store_false', dest='java', help='do not clean Java projects') | 1290 parser.add_argument('--no-java', action='store_false', dest='java', help='do not clean Java projects') |
1169 | 1291 |
1170 args = parser.parse_args(args) | 1292 args = parser.parse_args(args) |
1171 | 1293 |
1172 for p in projects(): | 1294 for p in projects(): |
1173 if p.native: | 1295 if p.native: |
1174 if args.native: | 1296 if args.native: |
1175 run([gmake_cmd(), '-C', p.dir, 'clean']) | 1297 run([gmake_cmd(), '-C', p.dir, 'clean']) |
1176 else: | 1298 else: |
1177 if args.java: | 1299 if args.java: |
1178 outputDir = p.output_dir() | 1300 outputDir = p.output_dir() |
1179 if outputDir != '' and exists(outputDir): | 1301 if outputDir != '' and exists(outputDir): |
1180 log('Removing {0}...'.format(outputDir)) | 1302 log('Removing {0}...'.format(outputDir)) |
1181 shutil.rmtree(outputDir) | 1303 shutil.rmtree(outputDir) |
1182 | 1304 |
1183 if suppliedParser: | 1305 if suppliedParser: |
1184 return args | 1306 return args |
1185 | 1307 |
1308 def about(args): | |
1309 """show the 'man page' for mx""" | |
1310 print __doc__ | |
1311 | |
1186 def help_(args): | 1312 def help_(args): |
1187 """show help for a given command | 1313 """show help for a given command |
1188 | 1314 |
1189 With no arguments, print a list of commands and short help for each command. | 1315 With no arguments, print a list of commands and short help for each command. |
1190 | 1316 |
1191 Given a command name, print help for that command.""" | 1317 Given a command name, print help for that command.""" |
1192 if len(args) == 0: | 1318 if len(args) == 0: |
1193 _argParser.print_help() | 1319 _argParser.print_help() |
1194 return | 1320 return |
1195 | 1321 |
1196 name = args[0] | 1322 name = args[0] |
1197 if not commands.has_key(name): | 1323 if not commands.has_key(name): |
1198 _argParser.error('unknown command: ' + name) | 1324 _argParser.error('unknown command: ' + name) |
1199 | 1325 |
1200 value = commands[name] | 1326 value = commands[name] |
1201 (func, usage) = value[:2] | 1327 (func, usage) = value[:2] |
1202 doc = func.__doc__ | 1328 doc = func.__doc__ |
1203 if len(value) > 2: | 1329 if len(value) > 2: |
1204 docArgs = value[2:] | 1330 docArgs = value[2:] |
1211 doc = doc.format(*fmtArgs) | 1337 doc = doc.format(*fmtArgs) |
1212 print 'mx {0} {1}\n\n{2}\n'.format(name, usage, doc) | 1338 print 'mx {0} {1}\n\n{2}\n'.format(name, usage, doc) |
1213 | 1339 |
1214 def projectgraph(args, suite=None): | 1340 def projectgraph(args, suite=None): |
1215 """create dot graph for project structure ("mx projectgraph | dot -Tpdf -oprojects.pdf")""" | 1341 """create dot graph for project structure ("mx projectgraph | dot -Tpdf -oprojects.pdf")""" |
1216 | 1342 |
1217 print 'digraph projects {' | 1343 print 'digraph projects {' |
1218 print 'rankdir=BT;' | 1344 print 'rankdir=BT;' |
1219 print 'node [shape=rect];' | 1345 print 'node [shape=rect];' |
1220 for p in projects(): | 1346 for p in projects(): |
1221 for dep in p.canonical_deps(): | 1347 for dep in p.canonical_deps(): |
1225 def eclipseinit(args, suite=None): | 1351 def eclipseinit(args, suite=None): |
1226 """(re)generate Eclipse project configurations""" | 1352 """(re)generate Eclipse project configurations""" |
1227 | 1353 |
1228 if suite is None: | 1354 if suite is None: |
1229 suite = _mainSuite | 1355 suite = _mainSuite |
1230 | 1356 |
1231 def println(out, obj): | 1357 def println(out, obj): |
1232 out.write(str(obj) + '\n') | 1358 out.write(str(obj) + '\n') |
1233 | 1359 |
1234 for p in projects(): | 1360 for p in projects(): |
1235 if p.native: | |
1236 continue | |
1237 | |
1238 if not exists(p.dir): | 1361 if not exists(p.dir): |
1239 os.makedirs(p.dir) | 1362 os.makedirs(p.dir) |
1240 | 1363 |
1364 if p.native: | |
1365 eclipseNativeSettingsDir = join(suite.dir, 'mx', 'eclipse-native-settings') | |
1366 if exists(eclipseNativeSettingsDir): | |
1367 for name in os.listdir(eclipseNativeSettingsDir): | |
1368 path = join(eclipseNativeSettingsDir, name) | |
1369 if isfile(path): | |
1370 with open(join(eclipseNativeSettingsDir, name)) as f: | |
1371 content = f.read() | |
1372 content = content.replace('${javaHome}', java().jdk) | |
1373 update_file(join(p.dir, name), content) | |
1374 continue | |
1375 | |
1241 out = StringIO.StringIO() | 1376 out = StringIO.StringIO() |
1242 | 1377 |
1243 println(out, '<?xml version="1.0" encoding="UTF-8"?>') | 1378 println(out, '<?xml version="1.0" encoding="UTF-8"?>') |
1244 println(out, '<classpath>') | 1379 println(out, '<classpath>') |
1245 for src in p.srcDirs: | 1380 for src in p.srcDirs: |
1246 srcDir = join(p.dir, src) | 1381 srcDir = join(p.dir, src) |
1247 if not exists(srcDir): | 1382 if not exists(srcDir): |
1248 os.mkdir(srcDir) | 1383 os.mkdir(srcDir) |
1249 println(out, '\t<classpathentry kind="src" path="' + src + '"/>') | 1384 println(out, '\t<classpathentry kind="src" path="' + src + '"/>') |
1250 | 1385 |
1251 # Every Java program depends on the JRE | 1386 # Every Java program depends on the JRE |
1252 println(out, '\t<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>') | 1387 println(out, '\t<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>') |
1253 | 1388 |
1254 for dep in p.all_deps([], True): | 1389 for dep in p.all_deps([], True): |
1255 if dep == p: | 1390 if dep == p: |
1256 continue; | 1391 continue; |
1257 | 1392 |
1258 if dep.isLibrary(): | 1393 if dep.isLibrary(): |
1259 if hasattr(dep, 'eclipse.container'): | 1394 if hasattr(dep, 'eclipse.container'): |
1260 println(out, '\t<classpathentry exported="true" kind="con" path="' + getattr(dep, 'eclipse.container') + '"/>') | 1395 println(out, '\t<classpathentry exported="true" kind="con" path="' + getattr(dep, 'eclipse.container') + '"/>') |
1261 elif hasattr(dep, 'eclipse.project'): | 1396 elif hasattr(dep, 'eclipse.project'): |
1262 println(out, '\t<classpathentry combineaccessrules="false" exported="true" kind="src" path="/' + getattr(dep, 'eclipse.project') + '"/>') | 1397 println(out, '\t<classpathentry combineaccessrules="false" exported="true" kind="src" path="/' + getattr(dep, 'eclipse.project') + '"/>') |
1265 if dep.mustExist: | 1400 if dep.mustExist: |
1266 dep.get_path(resolve=True) | 1401 dep.get_path(resolve=True) |
1267 if isabs(path): | 1402 if isabs(path): |
1268 println(out, '\t<classpathentry exported="true" kind="lib" path="' + path + '"/>') | 1403 println(out, '\t<classpathentry exported="true" kind="lib" path="' + path + '"/>') |
1269 else: | 1404 else: |
1270 println(out, '\t<classpathentry exported="true" kind="lib" path="' + join(suite.dir, path) + '"/>') | 1405 projRelPath = os.path.relpath(join(suite.dir, path), p.dir) |
1406 println(out, '\t<classpathentry exported="true" kind="lib" path="' + projRelPath + '"/>') | |
1271 else: | 1407 else: |
1272 println(out, '\t<classpathentry combineaccessrules="false" exported="true" kind="src" path="/' + dep.name + '"/>') | 1408 println(out, '\t<classpathentry combineaccessrules="false" exported="true" kind="src" path="/' + dep.name + '"/>') |
1273 | 1409 |
1274 println(out, '\t<classpathentry kind="output" path="' + getattr(p, 'eclipse.output', 'bin') + '"/>') | 1410 println(out, '\t<classpathentry kind="output" path="' + getattr(p, 'eclipse.output', 'bin') + '"/>') |
1275 println(out, '</classpath>') | 1411 println(out, '</classpath>') |
1276 update_file(join(p.dir, '.classpath'), out.getvalue()) | 1412 update_file(join(p.dir, '.classpath'), out.getvalue()) |
1277 out.close() | 1413 out.close() |
1278 | 1414 |
1279 csConfig = join(project(p.checkstyleProj).dir, '.checkstyle_checks.xml') | 1415 csConfig = join(project(p.checkstyleProj).dir, '.checkstyle_checks.xml') |
1280 if exists(csConfig): | 1416 if exists(csConfig): |
1281 out = StringIO.StringIO() | 1417 out = StringIO.StringIO() |
1282 | 1418 |
1283 dotCheckstyle = join(p.dir, ".checkstyle") | 1419 dotCheckstyle = join(p.dir, ".checkstyle") |
1284 checkstyleConfigPath = '/' + p.checkstyleProj + '/.checkstyle_checks.xml' | 1420 checkstyleConfigPath = '/' + p.checkstyleProj + '/.checkstyle_checks.xml' |
1285 println(out, '<?xml version="1.0" encoding="UTF-8"?>') | 1421 println(out, '<?xml version="1.0" encoding="UTF-8"?>') |
1286 println(out, '<fileset-config file-format-version="1.2.0" simple-config="true">') | 1422 println(out, '<fileset-config file-format-version="1.2.0" simple-config="true">') |
1287 println(out, '\t<local-check-config name="Checks" location="' + checkstyleConfigPath + '" type="project" description="">') | 1423 println(out, '\t<local-check-config name="Checks" location="' + checkstyleConfigPath + '" type="project" description="">') |
1303 line = line.strip() | 1439 line = line.strip() |
1304 exclDir = join(p.dir, line) | 1440 exclDir = join(p.dir, line) |
1305 assert isdir(exclDir), 'excluded source directory listed in ' + exclude + ' does not exist or is not a directory: ' + exclDir | 1441 assert isdir(exclDir), 'excluded source directory listed in ' + exclude + ' does not exist or is not a directory: ' + exclDir |
1306 println(out, '\t\t<filter-data value="' + line + '"/>') | 1442 println(out, '\t\t<filter-data value="' + line + '"/>') |
1307 println(out, '\t</filter>') | 1443 println(out, '\t</filter>') |
1308 | 1444 |
1309 println(out, '</fileset-config>') | 1445 println(out, '</fileset-config>') |
1310 update_file(dotCheckstyle, out.getvalue()) | 1446 update_file(dotCheckstyle, out.getvalue()) |
1311 out.close() | 1447 out.close() |
1312 | 1448 |
1313 | 1449 |
1314 out = StringIO.StringIO() | 1450 out = StringIO.StringIO() |
1315 | 1451 |
1316 println(out, '<?xml version="1.0" encoding="UTF-8"?>') | 1452 println(out, '<?xml version="1.0" encoding="UTF-8"?>') |
1317 println(out, '<projectDescription>') | 1453 println(out, '<projectDescription>') |
1318 println(out, '\t<name>' + p.name + '</name>') | 1454 println(out, '\t<name>' + p.name + '</name>') |
1319 println(out, '\t<comment></comment>') | 1455 println(out, '\t<comment></comment>') |
1320 println(out, '\t<projects>') | 1456 println(out, '\t<projects>') |
1351 for name in os.listdir(eclipseSettingsDir): | 1487 for name in os.listdir(eclipseSettingsDir): |
1352 path = join(eclipseSettingsDir, name) | 1488 path = join(eclipseSettingsDir, name) |
1353 if isfile(path): | 1489 if isfile(path): |
1354 with open(join(eclipseSettingsDir, name)) as f: | 1490 with open(join(eclipseSettingsDir, name)) as f: |
1355 content = f.read() | 1491 content = f.read() |
1492 content = content.replace('${javaCompliance}', str(p.javaCompliance)) | |
1356 update_file(join(settingsDir, name), content) | 1493 update_file(join(settingsDir, name), content) |
1357 | 1494 |
1358 def netbeansinit(args, suite=None): | 1495 def netbeansinit(args, suite=None): |
1359 """(re)generate NetBeans project configurations""" | 1496 """(re)generate NetBeans project configurations""" |
1360 | 1497 |
1361 if suite is None: | 1498 if suite is None: |
1362 suite = _mainSuite | 1499 suite = _mainSuite |
1363 | 1500 |
1364 def println(out, obj): | 1501 def println(out, obj): |
1365 out.write(str(obj) + '\n') | 1502 out.write(str(obj) + '\n') |
1366 | 1503 |
1367 updated = False | 1504 updated = False |
1368 for p in projects(): | 1505 for p in projects(): |
1369 if p.native: | 1506 if p.native: |
1370 continue | 1507 continue |
1371 | 1508 |
1372 if not exists(join(p.dir, 'nbproject')): | 1509 if not exists(join(p.dir, 'nbproject')): |
1373 os.makedirs(join(p.dir, 'nbproject')) | 1510 os.makedirs(join(p.dir, 'nbproject')) |
1374 | 1511 |
1375 out = StringIO.StringIO() | 1512 out = StringIO.StringIO() |
1376 | 1513 |
1377 println(out, '<?xml version="1.0" encoding="UTF-8"?>') | 1514 println(out, '<?xml version="1.0" encoding="UTF-8"?>') |
1378 println(out, '<project name="' + p.name + '" default="default" basedir=".">') | 1515 println(out, '<project name="' + p.name + '" default="default" basedir=".">') |
1379 println(out, '\t<description>Builds, tests, and runs the project ' + p.name + '.</description>') | 1516 println(out, '\t<description>Builds, tests, and runs the project ' + p.name + '.</description>') |
1380 println(out, '\t<import file="nbproject/build-impl.xml"/>') | 1517 println(out, '\t<import file="nbproject/build-impl.xml"/>') |
1381 println(out, '</project>') | 1518 println(out, '</project>') |
1382 updated = update_file(join(p.dir, 'build.xml'), out.getvalue()) or updated | 1519 updated = update_file(join(p.dir, 'build.xml'), out.getvalue()) or updated |
1383 out.close() | 1520 out.close() |
1384 | 1521 |
1385 out = StringIO.StringIO() | 1522 out = StringIO.StringIO() |
1386 println(out, '<?xml version="1.0" encoding="UTF-8"?>') | 1523 println(out, '<?xml version="1.0" encoding="UTF-8"?>') |
1387 println(out, '<project xmlns="http://www.netbeans.org/ns/project/1">') | 1524 println(out, '<project xmlns="http://www.netbeans.org/ns/project/1">') |
1388 println(out, ' <type>org.netbeans.modules.java.j2seproject</type>') | 1525 println(out, ' <type>org.netbeans.modules.java.j2seproject</type>') |
1389 println(out, ' <configuration>') | 1526 println(out, ' <configuration>') |
1395 println(out, ' </source-roots>') | 1532 println(out, ' </source-roots>') |
1396 println(out, ' <test-roots>') | 1533 println(out, ' <test-roots>') |
1397 println(out, ' <root id="test.src.dir"/>') | 1534 println(out, ' <root id="test.src.dir"/>') |
1398 println(out, ' </test-roots>') | 1535 println(out, ' </test-roots>') |
1399 println(out, ' </data>') | 1536 println(out, ' </data>') |
1400 | 1537 |
1401 firstDep = True | 1538 firstDep = True |
1402 for dep in p.all_deps([], True): | 1539 for dep in p.all_deps([], True): |
1403 if dep == p: | 1540 if dep == p: |
1404 continue; | 1541 continue; |
1405 | 1542 |
1406 if not dep.isLibrary(): | 1543 if not dep.isLibrary(): |
1407 n = dep.name.replace('.', '_') | 1544 n = dep.name.replace('.', '_') |
1408 if firstDep: | 1545 if firstDep: |
1409 println(out, ' <references xmlns="http://www.netbeans.org/ns/ant-project-references/1">') | 1546 println(out, ' <references xmlns="http://www.netbeans.org/ns/ant-project-references/1">') |
1410 firstDep = False | 1547 firstDep = False |
1411 | 1548 |
1412 println(out, ' <reference>') | 1549 println(out, ' <reference>') |
1413 println(out, ' <foreign-project>' + n + '</foreign-project>') | 1550 println(out, ' <foreign-project>' + n + '</foreign-project>') |
1414 println(out, ' <artifact-type>jar</artifact-type>') | 1551 println(out, ' <artifact-type>jar</artifact-type>') |
1415 println(out, ' <script>build.xml</script>') | 1552 println(out, ' <script>build.xml</script>') |
1416 println(out, ' <target>jar</target>') | 1553 println(out, ' <target>jar</target>') |
1417 println(out, ' <clean-target>clean</clean-target>') | 1554 println(out, ' <clean-target>clean</clean-target>') |
1418 println(out, ' <id>jar</id>') | 1555 println(out, ' <id>jar</id>') |
1419 println(out, ' </reference>') | 1556 println(out, ' </reference>') |
1420 | 1557 |
1421 if not firstDep: | 1558 if not firstDep: |
1422 println(out, ' </references>') | 1559 println(out, ' </references>') |
1423 | 1560 |
1424 println(out, ' </configuration>') | 1561 println(out, ' </configuration>') |
1425 println(out, '</project>') | 1562 println(out, '</project>') |
1426 updated = update_file(join(p.dir, 'nbproject', 'project.xml'), out.getvalue()) or updated | 1563 updated = update_file(join(p.dir, 'nbproject', 'project.xml'), out.getvalue()) or updated |
1427 out.close() | 1564 out.close() |
1428 | 1565 |
1429 out = StringIO.StringIO() | 1566 out = StringIO.StringIO() |
1430 | 1567 |
1431 jdkPlatform = 'JDK_' + java().version | 1568 jdkPlatform = 'JDK_' + java().version |
1432 | 1569 |
1433 content = """ | 1570 content = """ |
1434 annotation.processing.enabled=false | 1571 annotation.processing.enabled=false |
1435 annotation.processing.enabled.in.editor=false | 1572 annotation.processing.enabled.in.editor=false |
1436 annotation.processing.processors.list= | 1573 annotation.processing.processors.list= |
1437 annotation.processing.run.all.processors=true | 1574 annotation.processing.run.all.processors=true |
1515 if mainSrc: | 1652 if mainSrc: |
1516 println(out, 'src.dir=${' + ref + '}') | 1653 println(out, 'src.dir=${' + ref + '}') |
1517 mainSrc = False | 1654 mainSrc = False |
1518 else: | 1655 else: |
1519 println(out, 'src.' + src + '.dir=${' + ref + '}') | 1656 println(out, 'src.' + src + '.dir=${' + ref + '}') |
1520 | 1657 |
1521 javacClasspath = [] | 1658 javacClasspath = [] |
1522 for dep in p.all_deps([], True): | 1659 for dep in p.all_deps([], True): |
1523 if dep == p: | 1660 if dep == p: |
1524 continue; | 1661 continue; |
1525 | 1662 |
1526 if dep.isLibrary(): | 1663 if dep.isLibrary(): |
1527 if not dep.mustExist: | 1664 if not dep.mustExist: |
1528 continue | 1665 continue |
1529 path = dep.get_path(resolve=True) | 1666 path = dep.get_path(resolve=True) |
1530 if os.sep == '\\': | 1667 if os.sep == '\\': |
1531 path = path.replace('\\', '\\\\') | 1668 path = path.replace('\\', '\\\\') |
1532 ref = 'file.reference.' + dep.name + '-bin' | 1669 ref = 'file.reference.' + dep.name + '-bin' |
1533 println(out, ref + '=' + path) | 1670 println(out, ref + '=' + path) |
1534 | 1671 |
1535 else: | 1672 else: |
1536 n = dep.name.replace('.', '_') | 1673 n = dep.name.replace('.', '_') |
1537 relDepPath = os.path.relpath(dep.dir, p.dir).replace(os.sep, '/') | 1674 relDepPath = os.path.relpath(dep.dir, p.dir).replace(os.sep, '/') |
1538 ref = 'reference.' + n + '.jar' | 1675 ref = 'reference.' + n + '.jar' |
1539 println(out, 'project.' + n + '=' + relDepPath) | 1676 println(out, 'project.' + n + '=' + relDepPath) |
1540 println(out, ref + '=${project.' + n + '}/dist/' + dep.name + '.jar') | 1677 println(out, ref + '=${project.' + n + '}/dist/' + dep.name + '.jar') |
1541 | 1678 |
1542 javacClasspath.append('${' + ref + '}') | 1679 javacClasspath.append('${' + ref + '}') |
1543 | 1680 |
1544 println(out, 'javac.classpath=\\\n ' + (os.pathsep + '\\\n ').join(javacClasspath)) | 1681 println(out, 'javac.classpath=\\\n ' + (os.pathsep + '\\\n ').join(javacClasspath)) |
1545 | 1682 |
1546 | 1683 |
1547 updated = update_file(join(p.dir, 'nbproject', 'project.properties'), out.getvalue()) or updated | 1684 updated = update_file(join(p.dir, 'nbproject', 'project.properties'), out.getvalue()) or updated |
1548 out.close() | 1685 out.close() |
1549 | 1686 |
1550 if updated: | 1687 if updated: |
1551 log('If using NetBeans:') | 1688 log('If using NetBeans:') |
1552 log(' 1. Ensure that a platform named "JDK ' + java().version + '" is defined (Tools -> Java Platforms)') | 1689 log(' 1. Ensure that a platform named "JDK ' + java().version + '" is defined (Tools -> Java Platforms)') |
1553 log(' 2. Open/create a Project Group for the directory containing the projects (File -> Project Group -> New Group... -> Folder of Projects)') | 1690 log(' 2. Open/create a Project Group for the directory containing the projects (File -> Project Group -> New Group... -> Folder of Projects)') |
1554 | 1691 |
1555 def ideclean(args, suite=None): | 1692 def ideclean(args, suite=None): |
1556 """remove all Eclipse and NetBeans project configurations""" | 1693 """remove all Eclipse and NetBeans project configurations""" |
1557 | 1694 |
1558 def rm(path): | 1695 def rm(path): |
1559 if exists(path): | 1696 if exists(path): |
1560 os.remove(path) | 1697 os.remove(path) |
1561 | 1698 |
1562 for p in projects(): | 1699 for p in projects(): |
1563 if p.native: | 1700 if p.native: |
1564 continue | 1701 continue |
1565 | 1702 |
1566 shutil.rmtree(join(p.dir, '.settings'), ignore_errors=True) | 1703 shutil.rmtree(join(p.dir, '.settings'), ignore_errors=True) |
1567 shutil.rmtree(join(p.dir, 'nbproject'), ignore_errors=True) | 1704 shutil.rmtree(join(p.dir, 'nbproject'), ignore_errors=True) |
1568 rm(join(p.dir, '.classpath')) | 1705 rm(join(p.dir, '.classpath')) |
1569 rm(join(p.dir, '.project')) | 1706 rm(join(p.dir, '.project')) |
1570 rm(join(p.dir, 'build.xml')) | 1707 rm(join(p.dir, 'build.xml')) |
1571 | 1708 |
1572 def ideinit(args, suite=None): | 1709 def ideinit(args, suite=None): |
1573 """(re)generate Eclipse and NetBeans project configurations""" | 1710 """(re)generate Eclipse and NetBeans project configurations""" |
1574 eclipseinit(args, suite) | 1711 eclipseinit(args, suite) |
1575 netbeansinit(args, suite) | 1712 netbeansinit(args, suite) |
1576 | 1713 |
1578 """launch javap with a -classpath option denoting all available classes | 1715 """launch javap with a -classpath option denoting all available classes |
1579 | 1716 |
1580 Run the JDK javap class file disassembler with the following prepended options: | 1717 Run the JDK javap class file disassembler with the following prepended options: |
1581 | 1718 |
1582 -private -verbose -classpath <path to project classes>""" | 1719 -private -verbose -classpath <path to project classes>""" |
1583 | 1720 |
1584 javap = java().javap | 1721 javap = java().javap |
1585 if not exists(javap): | 1722 if not exists(javap): |
1586 abort('The javap executable does not exists: ' + javap) | 1723 abort('The javap executable does not exists: ' + javap) |
1587 else: | 1724 else: |
1588 run([javap, '-private', '-verbose', '-classpath', classpath()] + args) | 1725 run([javap, '-private', '-verbose', '-classpath', classpath()] + args) |
1600 """ | 1737 """ |
1601 Define how a single command-line argument. | 1738 Define how a single command-line argument. |
1602 """ | 1739 """ |
1603 assert _argParser is not None | 1740 assert _argParser is not None |
1604 _argParser.add_argument(*args, **kwargs) | 1741 _argParser.add_argument(*args, **kwargs) |
1605 | 1742 |
1606 # Table of commands in alphabetical order. | 1743 # Table of commands in alphabetical order. |
1607 # Keys are command names, value are lists: [<function>, <usage msg>, <format args to doc string of function>...] | 1744 # Keys are command names, value are lists: [<function>, <usage msg>, <format args to doc string of function>...] |
1608 # If any of the format args are instances of Callable, then they are called with an 'env' are before being | 1745 # If any of the format args are instances of Callable, then they are called with an 'env' are before being |
1609 # used in the call to str.format(). | 1746 # used in the call to str.format(). |
1610 # Extensions should update this table directly | 1747 # Extensions should update this table directly |
1611 commands = { | 1748 commands = { |
1749 'about': [about, ''], | |
1612 'build': [build, '[options]'], | 1750 'build': [build, '[options]'], |
1613 'checkstyle': [checkstyle, ''], | 1751 'checkstyle': [checkstyle, ''], |
1614 'canonicalizeprojects': [canonicalizeprojects, ''], | 1752 'canonicalizeprojects': [canonicalizeprojects, ''], |
1615 'clean': [clean, ''], | 1753 'clean': [clean, ''], |
1616 'eclipseinit': [eclipseinit, ''], | 1754 'eclipseinit': [eclipseinit, ''], |
1628 def main(): | 1766 def main(): |
1629 cwdMxDir = join(os.getcwd(), 'mx') | 1767 cwdMxDir = join(os.getcwd(), 'mx') |
1630 if exists(cwdMxDir) and isdir(cwdMxDir): | 1768 if exists(cwdMxDir) and isdir(cwdMxDir): |
1631 global _mainSuite | 1769 global _mainSuite |
1632 _mainSuite = _loadSuite(os.getcwd(), True) | 1770 _mainSuite = _loadSuite(os.getcwd(), True) |
1633 | 1771 |
1634 opts, commandAndArgs = _argParser._parse_cmd_line() | 1772 opts, commandAndArgs = _argParser._parse_cmd_line() |
1635 | 1773 |
1636 global _opts, _java | 1774 global _opts, _java |
1637 _opts = opts | 1775 _opts = opts |
1638 _java = JavaConfig(opts) | 1776 _java = JavaConfig(opts) |
1639 | 1777 |
1640 for s in suites(): | 1778 for s in suites(): |
1641 s._post_init(opts) | 1779 s._post_init(opts) |
1642 | 1780 |
1643 if len(commandAndArgs) == 0: | 1781 if len(commandAndArgs) == 0: |
1644 _argParser.print_help() | 1782 _argParser.print_help() |
1645 return | 1783 return |
1646 | 1784 |
1647 command = commandAndArgs[0] | 1785 command = commandAndArgs[0] |
1648 command_args = commandAndArgs[1:] | 1786 command_args = commandAndArgs[1:] |
1649 | 1787 |
1650 if not commands.has_key(command): | 1788 if not commands.has_key(command): |
1651 abort('mx: unknown command \'{0}\'\n{1}use "mx help" for more options'.format(command, _format_commands())) | 1789 abort('mx: unknown command \'{0}\'\n{1}use "mx help" for more options'.format(command, _format_commands())) |
1652 | 1790 |
1653 c, _ = commands[command][:2] | 1791 c, _ = commands[command][:2] |
1654 def term_handler(signum, frame): | 1792 def term_handler(signum, frame): |
1655 abort(1) | 1793 abort(1) |
1656 signal.signal(signal.SIGTERM, term_handler) | 1794 signal.signal(signal.SIGTERM, term_handler) |
1657 try: | 1795 try: |