comparison mxtool/mx.py @ 11514:dc3c8df55905

added support for pylint and fixed errors/warnings it found
author Doug Simon <doug.simon@oracle.com>
date Tue, 03 Sep 2013 16:33:41 +0200
parents 3110bea9a6b0
children 723796685546
comparison
equal deleted inserted replaced
11513:8d4e5e08d83f 11514:dc3c8df55905
123 "true" if the project is native. 123 "true" if the project is native.
124 124
125 javaCompliance 125 javaCompliance
126 The minimum JDK version (format: x.y) to which the project's 126 The minimum JDK version (format: x.y) to which the project's
127 sources comply (required for non-native projects). 127 sources comply (required for non-native projects).
128 128
129 workingSets 129 workingSets
130 A comma separated list of working set names. The project belongs 130 A comma separated list of working set names. The project belongs
131 to the given working sets, for which the eclipseinit command 131 to the given working sets, for which the eclipseinit command
132 will generate Eclipse configurations. 132 will generate Eclipse configurations.
133 133
143 import shutil, re, xml.dom.minidom 143 import shutil, re, xml.dom.minidom
144 from collections import Callable 144 from collections import Callable
145 from threading import Thread 145 from threading import Thread
146 from argparse import ArgumentParser, REMAINDER 146 from argparse import ArgumentParser, REMAINDER
147 from os.path import join, basename, dirname, exists, getmtime, isabs, expandvars, isdir, isfile 147 from os.path import join, basename, dirname, exists, getmtime, isabs, expandvars, isdir, isfile
148
149 DEFAULT_JAVA_ARGS = '-ea -Xss2m -Xmx1g'
150 148
151 _projects = dict() 149 _projects = dict()
152 _libs = dict() 150 _libs = dict()
153 _dists = dict() 151 _dists = dict()
154 _suites = dict() 152 _suites = dict()
167 self.path = path.replace('/', os.sep) 165 self.path = path.replace('/', os.sep)
168 if not isabs(self.path): 166 if not isabs(self.path):
169 self.path = join(suite.dir, self.path) 167 self.path = join(suite.dir, self.path)
170 self.deps = deps 168 self.deps = deps
171 self.update_listeners = set() 169 self.update_listeners = set()
172 170
173 def __str__(self): 171 def __str__(self):
174 return self.name 172 return self.name
175 173
176 def add_update_listener(self, listener): 174 def add_update_listener(self, listener):
177 self.update_listeners.add(listener) 175 self.update_listeners.add(listener)
178 176
179 def notify_updated(self): 177 def notify_updated(self):
180 for l in self.update_listeners: 178 for l in self.update_listeners:
181 l(self) 179 l(self)
182 180
183 """ 181 """
184 A dependency is a library or project specified in a suite. 182 A dependency is a library or project specified in a suite.
185 """ 183 """
186 class Dependency: 184 class Dependency:
187 def __init__(self, suite, name): 185 def __init__(self, suite, name):
200 def __hash__(self): 198 def __hash__(self):
201 return hash(self.name) 199 return hash(self.name)
202 200
203 def isLibrary(self): 201 def isLibrary(self):
204 return isinstance(self, Library) 202 return isinstance(self, Library)
205 203
206 def isProject(self): 204 def isProject(self):
207 return isinstance(self, Project) 205 return isinstance(self, Project)
208 206
209 class Project(Dependency): 207 class Project(Dependency):
210 def __init__(self, suite, name, srcDirs, deps, javaCompliance, workingSets, d): 208 def __init__(self, suite, name, srcDirs, deps, javaCompliance, workingSets, d):
214 self.checkstyleProj = name 212 self.checkstyleProj = name
215 self.javaCompliance = JavaCompliance(javaCompliance) if javaCompliance is not None else None 213 self.javaCompliance = JavaCompliance(javaCompliance) if javaCompliance is not None else None
216 self.native = False 214 self.native = False
217 self.workingSets = workingSets 215 self.workingSets = workingSets
218 self.dir = d 216 self.dir = d
219 217
220 # Create directories for projects that don't yet exist 218 # Create directories for projects that don't yet exist
221 if not exists(d): 219 if not exists(d):
222 os.mkdir(d) 220 os.mkdir(d)
223 for s in self.source_dirs(): 221 for s in self.source_dirs():
224 if not exists(s): 222 if not exists(s):
242 if not self in deps and includeSelf: 240 if not self in deps and includeSelf:
243 deps.append(self) 241 deps.append(self)
244 return deps 242 return deps
245 243
246 def _compute_max_dep_distances(self, name, distances, dist): 244 def _compute_max_dep_distances(self, name, distances, dist):
247 currentDist = distances.get(name); 245 currentDist = distances.get(name)
248 if currentDist is None or currentDist < dist: 246 if currentDist is None or currentDist < dist:
249 distances[name] = dist 247 distances[name] = dist
250 p = project(name, False) 248 p = project(name, False)
251 if p is not None: 249 if p is not None:
252 for dep in p.deps: 250 for dep in p.deps:
258 via other dependencies). 256 via other dependencies).
259 """ 257 """
260 distances = dict() 258 distances = dict()
261 result = set() 259 result = set()
262 self._compute_max_dep_distances(self.name, distances, 0) 260 self._compute_max_dep_distances(self.name, distances, 0)
263 for n,d in distances.iteritems(): 261 for n, d in distances.iteritems():
264 assert d > 0 or n == self.name 262 assert d > 0 or n == self.name
265 if d == 1: 263 if d == 1:
266 result.add(n) 264 result.add(n)
267 265
268 if len(result) == len(self.deps) and frozenset(self.deps) == result: 266 if len(result) == len(self.deps) and frozenset(self.deps) == result:
269 return self.deps 267 return self.deps
270 return result; 268 return result
271 269
272 def max_depth(self): 270 def max_depth(self):
273 """ 271 """
274 Get the maximum canonical distance between this project and its most distant dependency. 272 Get the maximum canonical distance between this project and its most distant dependency.
275 """ 273 """
276 distances = dict() 274 distances = dict()
277 self._compute_max_dep_distances(self.name, distances, 0) 275 self._compute_max_dep_distances(self.name, distances, 0)
278 return max(distances.values()) 276 return max(distances.values())
279 277
280 def source_dirs(self): 278 def source_dirs(self):
281 """ 279 """
282 Get the directories in which the sources of this project are found. 280 Get the directories in which the sources of this project are found.
283 """ 281 """
335 pkg = match.group(1) 333 pkg = match.group(1)
336 if function(line.strip()): 334 if function(line.strip()):
337 matchFound = True 335 matchFound = True
338 if pkg and matchFound: 336 if pkg and matchFound:
339 break 337 break
340 338
341 if matchFound: 339 if matchFound:
342 basename = name[:-len('.java')] 340 simpleClassName = name[:-len('.java')]
343 assert pkg is not None 341 assert pkg is not None
344 if pkgRoot is None or pkg.startswith(pkgRoot): 342 if pkgRoot is None or pkg.startswith(pkgRoot):
345 pkgOutputDir = join(outputDir, pkg.replace('.', os.path.sep)) 343 pkgOutputDir = join(outputDir, pkg.replace('.', os.path.sep))
346 if exists(pkgOutputDir): 344 if exists(pkgOutputDir):
347 for e in os.listdir(pkgOutputDir): 345 for e in os.listdir(pkgOutputDir):
348 if includeInnerClasses: 346 if includeInnerClasses:
349 if e.endswith('.class') and (e.startswith(basename) or e.startswith(basename + '$')): 347 if e.endswith('.class') and (e.startswith(simpleClassName) or e.startswith(simpleClassName + '$')):
350 className = pkg + '.' + e[:-len('.class')] 348 className = pkg + '.' + e[:-len('.class')]
351 result[className] = source 349 result[className] = source
352 elif e == basename + '.class': 350 elif e == simpleClassName + '.class':
353 className = pkg + '.' + basename 351 className = pkg + '.' + simpleClassName
354 result[className] = source 352 result[className] = source
355 return result 353 return result
356 354
357 def _init_packages_and_imports(self): 355 def _init_packages_and_imports(self):
358 if not hasattr(self, '_defined_java_packages'): 356 if not hasattr(self, '_defined_java_packages'):
359 packages = set() 357 packages = set()
360 extendedPackages = set() 358 extendedPackages = set()
361 depPackages = set() 359 depPackages = set()
365 importRe = re.compile(r'import\s+(?:static\s+)?([^;]+);') 363 importRe = re.compile(r'import\s+(?:static\s+)?([^;]+);')
366 for sourceDir in self.source_dirs(): 364 for sourceDir in self.source_dirs():
367 for root, _, files in os.walk(sourceDir): 365 for root, _, files in os.walk(sourceDir):
368 javaSources = [name for name in files if name.endswith('.java')] 366 javaSources = [name for name in files if name.endswith('.java')]
369 if len(javaSources) != 0: 367 if len(javaSources) != 0:
370 pkg = root[len(sourceDir) + 1:].replace(os.sep,'.') 368 pkg = root[len(sourceDir) + 1:].replace(os.sep, '.')
371 if not pkg in depPackages: 369 if not pkg in depPackages:
372 packages.add(pkg) 370 packages.add(pkg)
373 else: 371 else:
374 # A project extends a package already defined by one of it dependencies 372 # A project extends a package already defined by one of it dependencies
375 extendedPackages.add(pkg) 373 extendedPackages.add(pkg)
376 imports.add(pkg) 374 imports.add(pkg)
377 375
378 for n in javaSources: 376 for n in javaSources:
379 with open(join(root, n)) as fp: 377 with open(join(root, n)) as fp:
380 content = fp.read() 378 content = fp.read()
381 imports.update(importRe.findall(content)) 379 imports.update(importRe.findall(content))
382 self._defined_java_packages = frozenset(packages) 380 self._defined_java_packages = frozenset(packages)
383 self._extended_java_packages = frozenset(extendedPackages) 381 self._extended_java_packages = frozenset(extendedPackages)
384 382
385 importedPackages = set() 383 importedPackages = set()
386 for imp in imports: 384 for imp in imports:
387 name = imp 385 name = imp
388 while not name in depPackages and len(name) > 0: 386 while not name in depPackages and len(name) > 0:
389 lastDot = name.rfind('.') 387 lastDot = name.rfind('.')
392 break 390 break
393 name = name[0:lastDot] 391 name = name[0:lastDot]
394 if name is not None: 392 if name is not None:
395 importedPackages.add(name) 393 importedPackages.add(name)
396 self._imported_java_packages = frozenset(importedPackages) 394 self._imported_java_packages = frozenset(importedPackages)
397 395
398 def defined_java_packages(self): 396 def defined_java_packages(self):
399 """Get the immutable set of Java packages defined by the Java sources of this project""" 397 """Get the immutable set of Java packages defined by the Java sources of this project"""
400 self._init_packages_and_imports() 398 self._init_packages_and_imports()
401 return self._defined_java_packages 399 return self._defined_java_packages
402 400
403 def extended_java_packages(self): 401 def extended_java_packages(self):
404 """Get the immutable set of Java packages extended by the Java sources of this project""" 402 """Get the immutable set of Java packages extended by the Java sources of this project"""
405 self._init_packages_and_imports() 403 self._init_packages_and_imports()
406 return self._extended_java_packages 404 return self._extended_java_packages
407 405
415 if not hasattr(self, '_annotationProcessors'): 413 if not hasattr(self, '_annotationProcessors'):
416 ap = set() 414 ap = set()
417 if hasattr(self, '_declaredAnnotationProcessors'): 415 if hasattr(self, '_declaredAnnotationProcessors'):
418 ap = set(self._declaredAnnotationProcessors) 416 ap = set(self._declaredAnnotationProcessors)
419 417
420 # find dependencies that auto-inject themselves as annotation processors to all dependents 418 # find dependencies that auto-inject themselves as annotation processors to all dependents
421 allDeps = self.all_deps([], includeLibs=False, includeSelf=False, includeAnnotationProcessors=False) 419 allDeps = self.all_deps([], includeLibs=False, includeSelf=False, includeAnnotationProcessors=False)
422 for p in allDeps: 420 for p in allDeps:
423 if hasattr(p, 'annotationProcessorForDependents') and p.annotationProcessorForDependents.lower() == 'true': 421 if hasattr(p, 'annotationProcessorForDependents') and p.annotationProcessorForDependents.lower() == 'true':
424 ap.add(p.name) 422 ap.add(p.name)
425 self._annotationProcessors = list(ap) 423 self._annotationProcessors = list(ap)
440 def get_path(self, resolve): 438 def get_path(self, resolve):
441 path = self.path 439 path = self.path
442 if not isabs(path): 440 if not isabs(path):
443 path = join(self.suite.dir, path) 441 path = join(self.suite.dir, path)
444 if resolve and self.mustExist and not exists(path): 442 if resolve and self.mustExist and not exists(path):
445 assert not len(self.urls) == 0, 'cannot find required library ' + self.name + ' ' + path; 443 assert not len(self.urls) == 0, 'cannot find required library ' + self.name + ' ' + path
446 print('Downloading ' + self.name + ' from ' + str(self.urls)) 444 print('Downloading ' + self.name + ' from ' + str(self.urls))
447 download(path, self.urls) 445 download(path, self.urls)
448 return path 446 return path
449 447
450 def get_source_path(self, resolve): 448 def get_source_path(self, resolve):
460 458
461 def append_to_classpath(self, cp, resolve): 459 def append_to_classpath(self, cp, resolve):
462 path = self.get_path(resolve) 460 path = self.get_path(resolve)
463 if exists(path) or not resolve: 461 if exists(path) or not resolve:
464 cp.append(path) 462 cp.append(path)
465 463
466 def all_deps(self, deps, includeLibs, includeSelf=True, includeAnnotationProcessors=False): 464 def all_deps(self, deps, includeLibs, includeSelf=True, includeAnnotationProcessors=False):
467 if not includeLibs or not includeSelf: 465 if not includeLibs or not includeSelf:
468 return deps 466 return deps
469 deps.append(self) 467 deps.append(self)
470 return deps 468 return deps
480 self.primary = primary 478 self.primary = primary
481 mxDir = join(d, 'mx') 479 mxDir = join(d, 'mx')
482 self._load_env(mxDir) 480 self._load_env(mxDir)
483 self._load_commands(mxDir) 481 self._load_commands(mxDir)
484 self._load_includes(mxDir) 482 self._load_includes(mxDir)
485 self.name = d # re-initialized in _load_projects 483 self.name = d # re-initialized in _load_projects
486 484
487 def __str__(self): 485 def __str__(self):
488 return self.name 486 return self.name
489 487
490 def _load_projects(self, mxDir): 488 def _load_projects(self, mxDir):
491 libsMap = dict() 489 libsMap = dict()
492 projsMap = dict() 490 projsMap = dict()
493 distsMap = dict() 491 distsMap = dict()
494 projectsFile = join(mxDir, 'projects') 492 projectsFile = join(mxDir, 'projects')
534 532
535 for name, attrs in projsMap.iteritems(): 533 for name, attrs in projsMap.iteritems():
536 srcDirs = pop_list(attrs, 'sourceDirs') 534 srcDirs = pop_list(attrs, 'sourceDirs')
537 deps = pop_list(attrs, 'dependencies') 535 deps = pop_list(attrs, 'dependencies')
538 ap = pop_list(attrs, 'annotationProcessors') 536 ap = pop_list(attrs, 'annotationProcessors')
539 #deps += ap 537 # deps += ap
540 javaCompliance = attrs.pop('javaCompliance', None) 538 javaCompliance = attrs.pop('javaCompliance', None)
541 subDir = attrs.pop('subDir', None) 539 subDir = attrs.pop('subDir', None)
542 if subDir is None: 540 if subDir is None:
543 d = join(self.dir, name) 541 d = join(self.dir, name)
544 else: 542 else:
568 path = attrs.pop('path') 566 path = attrs.pop('path')
569 deps = pop_list(attrs, 'dependencies') 567 deps = pop_list(attrs, 'dependencies')
570 d = Distribution(self, name, path, deps) 568 d = Distribution(self, name, path, deps)
571 d.__dict__.update(attrs) 569 d.__dict__.update(attrs)
572 self.dists.append(d) 570 self.dists.append(d)
573 571
574 if self.name is None: 572 if self.name is None:
575 abort('Missing "suite=<name>" in ' + projectsFile) 573 abort('Missing "suite=<name>" in ' + projectsFile)
576 574
577 def _load_commands(self, mxDir): 575 def _load_commands(self, mxDir):
578 commands = join(mxDir, 'commands.py') 576 commandsPath = join(mxDir, 'commands.py')
579 if exists(commands): 577 if exists(commandsPath):
580 # temporarily extend the Python path 578 # temporarily extend the Python path
581 sys.path.insert(0, mxDir) 579 sys.path.insert(0, mxDir)
582 mod = __import__('commands') 580 mod = __import__('commands')
583 581
584 self.commands = sys.modules.pop('commands') 582 self.commands = sys.modules.pop('commands')
585 sys.modules[join(mxDir, 'commands')] = self.commands 583 sys.modules[join(mxDir, 'commands')] = self.commands
586 584
587 # revert the Python path 585 # revert the Python path
588 del sys.path[0] 586 del sys.path[0]
589 587
590 if not hasattr(mod, 'mx_init'): 588 if not hasattr(mod, 'mx_init'):
591 abort(commands + ' must define an mx_init(env) function') 589 abort(commandsPath + ' must define an mx_init(env) function')
592 if hasattr(mod, 'mx_post_parse_cmd_line'): 590 if hasattr(mod, 'mx_post_parse_cmd_line'):
593 self.mx_post_parse_cmd_line = mod.mx_post_parse_cmd_line 591 self.mx_post_parse_cmd_line = mod.mx_post_parse_cmd_line
594 592
595 mod.mx_init() 593 mod.mx_init()
596 self.commands = mod 594 self.commands = mod
630 existing = _libs.get(l.name) 628 existing = _libs.get(l.name)
631 if existing is not None: 629 if existing is not None:
632 abort('cannot redefine library ' + l.name) 630 abort('cannot redefine library ' + l.name)
633 _libs[l.name] = l 631 _libs[l.name] = l
634 for d in self.dists: 632 for d in self.dists:
635 existing = _dists.get(l.name) 633 existing = _dists.get(d.name)
636 if existing is not None: 634 if existing is not None:
637 abort('cannot redefine distribution ' + d.name) 635 abort('cannot redefine distribution ' + d.name)
638 _dists[d.name] = d 636 _dists[d.name] = d
639 if hasattr(self, 'mx_post_parse_cmd_line'): 637 if hasattr(self, 'mx_post_parse_cmd_line'):
640 self.mx_post_parse_cmd_line(opts) 638 self.mx_post_parse_cmd_line(opts)
641 639
642 class XMLElement(xml.dom.minidom.Element): 640 class XMLElement(xml.dom.minidom.Element):
643 def writexml(self, writer, indent="", addindent="", newl=""): 641 def writexml(self, writer, indent="", addindent="", newl=""):
644 writer.write(indent+"<" + self.tagName) 642 writer.write(indent + "<" + self.tagName)
645 643
646 attrs = self._get_attributes() 644 attrs = self._get_attributes()
647 a_names = attrs.keys() 645 a_names = attrs.keys()
648 a_names.sort() 646 a_names.sort()
649 647
655 if not self.ownerDocument.padTextNodeWithoutSiblings and len(self.childNodes) == 1 and isinstance(self.childNodes[0], xml.dom.minidom.Text): 653 if not self.ownerDocument.padTextNodeWithoutSiblings and len(self.childNodes) == 1 and isinstance(self.childNodes[0], xml.dom.minidom.Text):
656 # if the only child of an Element node is a Text node, then the 654 # if the only child of an Element node is a Text node, then the
657 # text is printed without any indentation or new line padding 655 # text is printed without any indentation or new line padding
658 writer.write(">") 656 writer.write(">")
659 self.childNodes[0].writexml(writer) 657 self.childNodes[0].writexml(writer)
660 writer.write("</%s>%s" % (self.tagName,newl)) 658 writer.write("</%s>%s" % (self.tagName, newl))
661 else: 659 else:
662 writer.write(">%s"%(newl)) 660 writer.write(">%s" % (newl))
663 for node in self.childNodes: 661 for node in self.childNodes:
664 node.writexml(writer,indent+addindent,addindent,newl) 662 node.writexml(writer, indent + addindent, addindent, newl)
665 writer.write("%s</%s>%s" % (indent,self.tagName,newl)) 663 writer.write("%s</%s>%s" % (indent, self.tagName, newl))
666 else: 664 else:
667 writer.write("/>%s"%(newl)) 665 writer.write("/>%s" % (newl))
668 666
669 class XMLDoc(xml.dom.minidom.Document): 667 class XMLDoc(xml.dom.minidom.Document):
670 668
671 def __init__(self): 669 def __init__(self):
672 xml.dom.minidom.Document.__init__(self) 670 xml.dom.minidom.Document.__init__(self)
680 return e 678 return e
681 679
682 def comment(self, txt): 680 def comment(self, txt):
683 self.current.appendChild(self.createComment(txt)) 681 self.current.appendChild(self.createComment(txt))
684 682
685 def open(self, tag, attributes={}, data=None): 683 def open(self, tag, attributes=None, data=None):
684 if attributes is None:
685 attributes = {}
686 element = self.createElement(tag) 686 element = self.createElement(tag)
687 for key, value in attributes.items(): 687 for key, value in attributes.items():
688 element.setAttribute(key, value) 688 element.setAttribute(key, value)
689 self.current.appendChild(element) 689 self.current.appendChild(element)
690 self.current = element 690 self.current = element
696 assert self.current != self 696 assert self.current != self
697 assert tag == self.current.tagName, str(tag) + ' != ' + self.current.tagName 697 assert tag == self.current.tagName, str(tag) + ' != ' + self.current.tagName
698 self.current = self.current.parentNode 698 self.current = self.current.parentNode
699 return self 699 return self
700 700
701 def element(self, tag, attributes={}, data=None): 701 def element(self, tag, attributes=None, data=None):
702 if attributes is None:
703 attributes = {}
702 return self.open(tag, attributes, data).close(tag) 704 return self.open(tag, attributes, data).close(tag)
703 705
704 def xml(self, indent='', newl='', escape=False, standalone=None): 706 def xml(self, indent='', newl='', escape=False, standalone=None):
705 assert self.current == self 707 assert self.current == self
706 result = self.toprettyxml(indent, newl, encoding="UTF-8") 708 result = self.toprettyxml(indent, newl, encoding="UTF-8")
886 return deps 888 return deps
887 889
888 def _handle_missing_java_home(): 890 def _handle_missing_java_home():
889 if not sys.stdout.isatty(): 891 if not sys.stdout.isatty():
890 abort('Could not find bootstrap JDK. Use --java-home option or ensure JAVA_HOME environment variable is set.') 892 abort('Could not find bootstrap JDK. Use --java-home option or ensure JAVA_HOME environment variable is set.')
891 893
892 candidateJdks = [] 894 candidateJdks = []
893 if get_os() == 'darwin': 895 if get_os() == 'darwin':
894 base = '/Library/Java/JavaVirtualMachines' 896 base = '/Library/Java/JavaVirtualMachines'
895 candidateJdks = [join(base, n, 'Contents/Home') for n in os.listdir(base) if exists(join(base, n, 'Contents/Home'))] 897 candidateJdks = [join(base, n, 'Contents/Home') for n in os.listdir(base) if exists(join(base, n, 'Contents/Home'))]
896 elif get_os() == 'linux': 898 elif get_os() == 'linux':
906 javaHome = None 908 javaHome = None
907 if len(candidateJdks) != 0: 909 if len(candidateJdks) != 0:
908 javaHome = select_items(candidateJdks + ['<other>'], allowMultiple=False) 910 javaHome = select_items(candidateJdks + ['<other>'], allowMultiple=False)
909 if javaHome == '<other>': 911 if javaHome == '<other>':
910 javaHome = None 912 javaHome = None
911 913
912 while javaHome is None: 914 while javaHome is None:
913 javaHome = raw_input('Enter path of bootstrap JDK: ') 915 javaHome = raw_input('Enter path of bootstrap JDK: ')
914 rtJarPath = join(javaHome, 'jre', 'lib', 'rt.jar') 916 rtJarPath = join(javaHome, 'jre', 'lib', 'rt.jar')
915 if not exists(rtJarPath): 917 if not exists(rtJarPath):
916 log('Does not appear to be a valid JDK as ' + rtJarPath + ' does not exist') 918 log('Does not appear to be a valid JDK as ' + rtJarPath + ' does not exist')
917 javaHome = None 919 javaHome = None
918 else: 920 else:
919 break 921 break
920 922
921 envPath = join(_mainSuite.dir, 'mx', 'env') 923 envPath = join(_mainSuite.dir, 'mx', 'env')
922 if ask_yes_no('Persist this setting by adding "JAVA_HOME=' + javaHome + '" to ' + envPath, 'y'): 924 if ask_yes_no('Persist this setting by adding "JAVA_HOME=' + javaHome + '" to ' + envPath, 'y'):
923 with open(envPath, 'a') as fp: 925 with open(envPath, 'a') as fp:
924 print >> fp, 'JAVA_HOME=' + javaHome 926 print >> fp, 'JAVA_HOME=' + javaHome
925 927
926 return javaHome 928 return javaHome
927 929
928 class ArgParser(ArgumentParser): 930 class ArgParser(ArgumentParser):
929 931
930 # Override parent to append the list of available commands 932 # Override parent to append the list of available commands
940 self.add_argument('-V', action='store_true', dest='very_verbose', help='enable very verbose output') 942 self.add_argument('-V', action='store_true', dest='very_verbose', help='enable very verbose output')
941 self.add_argument('--dbg', type=int, dest='java_dbg_port', help='make Java processes wait on <port> for a debugger', metavar='<port>') 943 self.add_argument('--dbg', type=int, dest='java_dbg_port', help='make Java processes wait on <port> for a debugger', metavar='<port>')
942 self.add_argument('-d', action='store_const', const=8000, dest='java_dbg_port', help='alias for "-dbg 8000"') 944 self.add_argument('-d', action='store_const', const=8000, dest='java_dbg_port', help='alias for "-dbg 8000"')
943 self.add_argument('--cp-pfx', dest='cp_prefix', help='class path prefix', metavar='<arg>') 945 self.add_argument('--cp-pfx', dest='cp_prefix', help='class path prefix', metavar='<arg>')
944 self.add_argument('--cp-sfx', dest='cp_suffix', help='class path suffix', metavar='<arg>') 946 self.add_argument('--cp-sfx', dest='cp_suffix', help='class path suffix', metavar='<arg>')
945 self.add_argument('--J', dest='java_args', help='Java VM arguments (e.g. --J @-dsa)', metavar='@<args>', default=DEFAULT_JAVA_ARGS) 947 self.add_argument('--J', dest='java_args', help='Java VM arguments (e.g. --J @-dsa)', metavar='@<args>', default='-ea -Xss2m -Xmx1g')
946 self.add_argument('--Jp', action='append', dest='java_args_pfx', help='prefix Java VM arguments (e.g. --Jp @-dsa)', metavar='@<args>', default=[]) 948 self.add_argument('--Jp', action='append', dest='java_args_pfx', help='prefix Java VM arguments (e.g. --Jp @-dsa)', metavar='@<args>', default=[])
947 self.add_argument('--Ja', action='append', dest='java_args_sfx', help='suffix Java VM arguments (e.g. --Ja @-dsa)', metavar='@<args>', default=[]) 949 self.add_argument('--Ja', action='append', dest='java_args_sfx', help='suffix Java VM arguments (e.g. --Ja @-dsa)', metavar='@<args>', default=[])
948 self.add_argument('--user-home', help='users home directory', metavar='<path>', default=os.path.expanduser('~')) 950 self.add_argument('--user-home', help='users home directory', metavar='<path>', default=os.path.expanduser('~'))
949 self.add_argument('--java-home', help='bootstrap JDK installation directory (must be JDK 6 or later)', metavar='<path>') 951 self.add_argument('--java-home', help='bootstrap JDK installation directory (must be JDK 6 or later)', metavar='<path>')
950 self.add_argument('--ignore-project', action='append', dest='ignored_projects', help='name of project to ignore', metavar='<name>', default=[]) 952 self.add_argument('--ignore-project', action='append', dest='ignored_projects', help='name of project to ignore', metavar='<name>', default=[])
985 commandAndArgs = opts.__dict__.pop('commandAndArgs') 987 commandAndArgs = opts.__dict__.pop('commandAndArgs')
986 return opts, commandAndArgs 988 return opts, commandAndArgs
987 989
988 def _format_commands(): 990 def _format_commands():
989 msg = '\navailable commands:\n\n' 991 msg = '\navailable commands:\n\n'
990 for cmd in sorted(commands.iterkeys()): 992 for cmd in sorted(_commands.iterkeys()):
991 c, _ = commands[cmd][:2] 993 c, _ = _commands[cmd][:2]
992 doc = c.__doc__ 994 doc = c.__doc__
993 if doc is None: 995 if doc is None:
994 doc = '' 996 doc = ''
995 msg += ' {0:<20} {1}\n'.format(cmd, doc.split('\n', 1)[0]) 997 msg += ' {0:<20} {1}\n'.format(cmd, doc.split('\n', 1)[0])
996 return msg + '\n' 998 return msg + '\n'
1073 for arg in args: 1075 for arg in args:
1074 assert isinstance(arg, types.StringTypes), 'argument is not a string: ' + str(arg) 1076 assert isinstance(arg, types.StringTypes), 'argument is not a string: ' + str(arg)
1075 1077
1076 if env is None: 1078 if env is None:
1077 env = os.environ 1079 env = os.environ
1078 1080
1079 if _opts.verbose: 1081 if _opts.verbose:
1080 if _opts.very_verbose: 1082 if _opts.very_verbose:
1081 log('Environment variables:') 1083 log('Environment variables:')
1082 for key in sorted(env.keys()): 1084 for key in sorted(env.keys()):
1083 log(' ' + key + '=' + env[key]) 1085 log(' ' + key + '=' + env[key])
1106 else: 1108 else:
1107 def redirect(stream, f): 1109 def redirect(stream, f):
1108 for line in iter(stream.readline, ''): 1110 for line in iter(stream.readline, ''):
1109 f(line) 1111 f(line)
1110 stream.close() 1112 stream.close()
1111 stdout=out if not callable(out) else subprocess.PIPE 1113 stdout = out if not callable(out) else subprocess.PIPE
1112 stderr=err if not callable(err) else subprocess.PIPE 1114 stderr = err if not callable(err) else subprocess.PIPE
1113 p = subprocess.Popen(args, cwd=cwd, stdout=stdout, stderr=stderr, preexec_fn=preexec_fn, creationflags=creationflags, env=env) 1115 p = subprocess.Popen(args, cwd=cwd, stdout=stdout, stderr=stderr, preexec_fn=preexec_fn, creationflags=creationflags, env=env)
1114 _currentSubprocess = (p, args) 1116 _currentSubprocess = (p, args)
1115 if callable(out): 1117 if callable(out):
1116 t = Thread(target=redirect, args=(p.stdout, out)) 1118 t = Thread(target=redirect, args=(p.stdout, out))
1117 t.daemon = True # thread dies with the program 1119 t.daemon = True # thread dies with the program
1118 t.start() 1120 t.start()
1119 if callable(err): 1121 if callable(err):
1120 t = Thread(target=redirect, args=(p.stderr, err)) 1122 t = Thread(target=redirect, args=(p.stderr, err))
1121 t.daemon = True # thread dies with the program 1123 t.daemon = True # thread dies with the program
1122 t.start() 1124 t.start()
1123 if timeout is None or timeout == 0: 1125 if timeout is None or timeout == 0:
1124 retcode = waitOn(p) 1126 retcode = waitOn(p)
1125 else: 1127 else:
1126 if get_os() == 'windows': 1128 if get_os() == 'windows':
1139 if retcode and nonZeroIsFatal: 1141 if retcode and nonZeroIsFatal:
1140 if _opts.verbose: 1142 if _opts.verbose:
1141 if _opts.very_verbose: 1143 if _opts.very_verbose:
1142 raise subprocess.CalledProcessError(retcode, ' '.join(args)) 1144 raise subprocess.CalledProcessError(retcode, ' '.join(args))
1143 else: 1145 else:
1144 log('[exit code: ' + str(retcode)+ ']') 1146 log('[exit code: ' + str(retcode) + ']')
1145 abort(retcode) 1147 abort(retcode)
1146 1148
1147 return retcode 1149 return retcode
1148 1150
1149 def exe_suffix(name): 1151 def exe_suffix(name):
1156 1158
1157 def add_lib_prefix(name): 1159 def add_lib_prefix(name):
1158 """ 1160 """
1159 Adds the platform specific library prefix to a name 1161 Adds the platform specific library prefix to a name
1160 """ 1162 """
1161 os = get_os(); 1163 os = get_os()
1162 if os == 'linux' or os == 'solaris' or os == 'darwin': 1164 if os == 'linux' or os == 'solaris' or os == 'darwin':
1163 return 'lib' + name 1165 return 'lib' + name
1164 return name 1166 return name
1165 1167
1166 def add_lib_suffix(name): 1168 def add_lib_suffix(name):
1167 """ 1169 """
1168 Adds the platform specific library suffix to a name 1170 Adds the platform specific library suffix to a name
1169 """ 1171 """
1170 os = get_os(); 1172 os = get_os()
1171 if os == 'windows': 1173 if os == 'windows':
1172 return name + '.dll' 1174 return name + '.dll'
1173 if os == 'linux' or os == 'solaris': 1175 if os == 'linux' or os == 'solaris':
1174 return name + '.so' 1176 return name + '.so'
1175 if os == 'darwin': 1177 if os == 'darwin':
1179 """ 1181 """
1180 A JavaCompliance simplifies comparing Java compliance values extracted from a JDK version string. 1182 A JavaCompliance simplifies comparing Java compliance values extracted from a JDK version string.
1181 """ 1183 """
1182 class JavaCompliance: 1184 class JavaCompliance:
1183 def __init__(self, ver): 1185 def __init__(self, ver):
1184 m = re.match('1\.(\d+).*', ver) 1186 m = re.match(r'1\.(\d+).*', ver)
1185 assert m is not None, 'not a recognized version string: ' + ver 1187 assert m is not None, 'not a recognized version string: ' + ver
1186 self.value = int(m.group(1)) 1188 self.value = int(m.group(1))
1187 1189
1188 def __str__ (self): 1190 def __str__ (self):
1189 return '1.' + str(self.value) 1191 return '1.' + str(self.value)
1191 def __cmp__ (self, other): 1193 def __cmp__ (self, other):
1192 if isinstance(other, types.StringType): 1194 if isinstance(other, types.StringType):
1193 other = JavaCompliance(other) 1195 other = JavaCompliance(other)
1194 1196
1195 return cmp(self.value, other.value) 1197 return cmp(self.value, other.value)
1196 1198
1197 """ 1199 """
1198 A Java version as defined in JSR-56 1200 A Java version as defined in JSR-56
1199 """ 1201 """
1200 class JavaVersion: 1202 class JavaVersion:
1201 def __init__(self, versionString): 1203 def __init__(self, versionString):
1202 validChar = '[\x21-\x25\x27-\x29\x2c\x2f-\x5e\x60-\x7f]' 1204 validChar = r'[\x21-\x25\x27-\x29\x2c\x2f-\x5e\x60-\x7f]'
1203 separator = '[.\-_]' 1205 separator = r'[.\-_]'
1204 m = re.match(validChar + '+(' + separator + validChar + '+)*', versionString) 1206 m = re.match(validChar + '+(' + separator + validChar + '+)*', versionString)
1205 assert m is not None, 'not a recognized version string: ' + versionString 1207 assert m is not None, 'not a recognized version string: ' + versionString
1206 self.versionString = versionString; 1208 self.versionString = versionString
1207 self.parts = [int(f) if f.isdigit() else f for f in re.split(separator, versionString)] 1209 self.parts = [int(f) if f.isdigit() else f for f in re.split(separator, versionString)]
1208 1210
1209 def __str__(self): 1211 def __str__(self):
1210 return self.versionString 1212 return self.versionString
1211 1213
1212 def __cmp__(self, other): 1214 def __cmp__(self, other):
1213 return cmp(self.parts, other.parts) 1215 return cmp(self.parts, other.parts)
1214 1216
1215 """ 1217 """
1216 A JavaConfig object encapsulates info on how Java commands are run. 1218 A JavaConfig object encapsulates info on how Java commands are run.
1217 """ 1219 """
1218 class JavaConfig: 1220 class JavaConfig:
1219 def __init__(self, opts): 1221 def __init__(self, opts):
1220 self.jdk = opts.java_home 1222 self.jdk = opts.java_home
1221 self.debug_port = opts.java_dbg_port 1223 self.debug_port = opts.java_dbg_port
1222 self.jar = exe_suffix(join(self.jdk, 'bin', 'jar')) 1224 self.jar = exe_suffix(join(self.jdk, 'bin', 'jar'))
1223 self.java = exe_suffix(join(self.jdk, 'bin', 'java')) 1225 self.java = exe_suffix(join(self.jdk, 'bin', 'java'))
1224 self.javac = exe_suffix(join(self.jdk, 'bin', 'javac')) 1226 self.javac = exe_suffix(join(self.jdk, 'bin', 'javac'))
1225 self.javap = exe_suffix(join(self.jdk, 'bin', 'javap')) 1227 self.javap = exe_suffix(join(self.jdk, 'bin', 'javap'))
1226 self.javadoc = exe_suffix(join(self.jdk, 'bin', 'javadoc')) 1228 self.javadoc = exe_suffix(join(self.jdk, 'bin', 'javadoc'))
1227 self._bootclasspath = None 1229 self._bootclasspath = None
1228 1230
1296 return value 1298 return value
1297 1299
1298 def logv(msg=None): 1300 def logv(msg=None):
1299 if _opts.verbose: 1301 if _opts.verbose:
1300 log(msg) 1302 log(msg)
1301 1303
1302 def log(msg=None): 1304 def log(msg=None):
1303 """ 1305 """
1304 Write a message to the console. 1306 Write a message to the console.
1305 All script output goes through this method thus allowing a subclass 1307 All script output goes through this method thus allowing a subclass
1306 to redirect it. 1308 to redirect it.
1330 def gmake_cmd(): 1332 def gmake_cmd():
1331 for a in ['make', 'gmake', 'gnumake']: 1333 for a in ['make', 'gmake', 'gnumake']:
1332 try: 1334 try:
1333 output = subprocess.check_output([a, '--version']) 1335 output = subprocess.check_output([a, '--version'])
1334 if 'GNU' in output: 1336 if 'GNU' in output:
1335 return a; 1337 return a
1336 except: 1338 except:
1337 pass 1339 pass
1338 abort('Could not find a GNU make executable on the current path.') 1340 abort('Could not find a GNU make executable on the current path.')
1339 1341
1340 def expandvars_in_property(value): 1342 def expandvars_in_property(value):
1341 result = expandvars(value) 1343 result = expandvars(value)
1342 if '$' in result or '%' in result: 1344 if '$' in result or '%' in result:
1343 abort('Property contains an undefined environment variable: ' + value) 1345 abort('Property contains an undefined environment variable: ' + value)
1344 return result 1346 return result
1345 1347
1346 1348
1347 def abort(codeOrMessage): 1349 def abort(codeOrMessage):
1348 """ 1350 """
1349 Aborts the program with a SystemExit exception. 1351 Aborts the program with a SystemExit exception.
1350 If 'codeOrMessage' is a plain integer, it specifies the system exit status; 1352 If 'codeOrMessage' is a plain integer, it specifies the system exit status;
1351 if it is None, the exit status is zero; if it has another type (such as a string), 1353 if it is None, the exit status is zero; if it has another type (such as a string),
1352 the object's value is printed and the exit status is one. 1354 the object's value is printed and the exit status is one.
1353 """ 1355 """
1354 1356
1355 #import traceback 1357 # import traceback
1356 #traceback.print_stack() 1358 # traceback.print_stack()
1357 currentSubprocess = _currentSubprocess 1359 currentSubprocess = _currentSubprocess
1358 if currentSubprocess is not None: 1360 if currentSubprocess is not None:
1359 p, _ = currentSubprocess 1361 p, _ = currentSubprocess
1360 if get_os() == 'windows': 1362 if get_os() == 'windows':
1361 p.kill() 1363 p.kill()
1362 else: 1364 else:
1363 _kill_process_group(p.pid) 1365 _kill_process_group(p.pid)
1364 1366
1365 raise SystemExit(codeOrMessage) 1367 raise SystemExit(codeOrMessage)
1366 1368
1367 def download(path, urls, verbose=False): 1369 def download(path, urls, verbose=False):
1368 """ 1370 """
1369 Attempts to downloads content for each URL in a list, stopping after the first successful download. 1371 Attempts to downloads content for each URL in a list, stopping after the first successful download.
1449 1451
1450 with open(path, 'wb') as f: 1452 with open(path, 'wb') as f:
1451 f.write(content) 1453 f.write(content)
1452 1454
1453 log(('modified ' if existed else 'created ') + path) 1455 log(('modified ' if existed else 'created ') + path)
1454 return True; 1456 return True
1455 except IOError as e: 1457 except IOError as e:
1456 abort('Error while writing to ' + path + ': ' + str(e)); 1458 abort('Error while writing to ' + path + ': ' + str(e))
1457 1459
1458 # Builtin commands 1460 # Builtin commands
1459 1461
1460 def build(args, parser=None): 1462 def build(args, parser=None):
1461 """compile the Java and C sources, linking the latter 1463 """compile the Java and C sources, linking the latter
1485 1487
1486 if suppliedParser: 1488 if suppliedParser:
1487 parser.add_argument('remainder', nargs=REMAINDER, metavar='...') 1489 parser.add_argument('remainder', nargs=REMAINDER, metavar='...')
1488 1490
1489 args = parser.parse_args(args) 1491 args = parser.parse_args(args)
1490 1492
1491 jdtJar = None 1493 jdtJar = None
1492 if args.jdt is not None: 1494 if args.jdt is not None:
1493 if args.jdt.endswith('.jar'): 1495 if args.jdt.endswith('.jar'):
1494 jdtJar=args.jdt 1496 jdtJar = args.jdt
1495 if not exists(jdtJar) and os.path.abspath(jdtJar) == os.path.abspath(defaultEcjPath): 1497 if not exists(jdtJar) and os.path.abspath(jdtJar) == os.path.abspath(defaultEcjPath):
1496 # Silently ignore JDT if default location is used but not ecj.jar exists there 1498 # Silently ignore JDT if default location is used but not ecj.jar exists there
1497 jdtJar = None 1499 jdtJar = None
1498 1500
1499 built = set() 1501 built = set()
1504 1506
1505 if args.only is not None: 1507 if args.only is not None:
1506 sortedProjects = [project(name) for name in args.only.split(',')] 1508 sortedProjects = [project(name) for name in args.only.split(',')]
1507 else: 1509 else:
1508 sortedProjects = sorted_deps(projects, includeAnnotationProcessors=True) 1510 sortedProjects = sorted_deps(projects, includeAnnotationProcessors=True)
1509 1511
1510 for p in sortedProjects: 1512 for p in sortedProjects:
1511 if p.native: 1513 if p.native:
1512 if args.native: 1514 if args.native:
1513 log('Calling GNU make {0}...'.format(p.dir)) 1515 log('Calling GNU make {0}...'.format(p.dir))
1514 1516
1519 built.add(p.name) 1521 built.add(p.name)
1520 continue 1522 continue
1521 else: 1523 else:
1522 if not args.java: 1524 if not args.java:
1523 continue 1525 continue
1524 if exists(join(p.dir, 'plugin.xml')): # eclipse plugin project 1526 if exists(join(p.dir, 'plugin.xml')): # eclipse plugin project
1525 continue 1527 continue
1526 1528
1527 # skip building this Java project if its Java compliance level is "higher" than the configured JDK 1529 # skip building this Java project if its Java compliance level is "higher" than the configured JDK
1528 if javaCompliance < p.javaCompliance: 1530 if javaCompliance < p.javaCompliance:
1529 log('Excluding {0} from build (Java compliance level {1} required)'.format(p.name, p.javaCompliance)) 1531 log('Excluding {0} from build (Java compliance level {1} required)'.format(p.name, p.javaCompliance))
1618 processorArgs = [] 1620 processorArgs = []
1619 1621
1620 ap = p.annotation_processors() 1622 ap = p.annotation_processors()
1621 if len(ap) > 0: 1623 if len(ap) > 0:
1622 processorPath = classpath(ap, resolve=True) 1624 processorPath = classpath(ap, resolve=True)
1623 genDir = p.source_gen_dir(); 1625 genDir = p.source_gen_dir()
1624 if exists(genDir): 1626 if exists(genDir):
1625 shutil.rmtree(genDir) 1627 shutil.rmtree(genDir)
1626 os.mkdir(genDir) 1628 os.mkdir(genDir)
1627 processorArgs += ['-processorpath', join(processorPath), '-s', genDir] 1629 processorArgs += ['-processorpath', join(processorPath), '-s', genDir]
1628 else: 1630 else:
1629 processorArgs += ['-proc:none'] 1631 processorArgs += ['-proc:none']
1630 1632
1631 toBeDeleted = [argfileName] 1633 toBeDeleted = [argfileName]
1632 try: 1634 try:
1633 compliance = str(p.javaCompliance) if p.javaCompliance is not None else args.compliance 1635 compliance = str(p.javaCompliance) if p.javaCompliance is not None else args.compliance
1634 if jdtJar is None: 1636 if jdtJar is None:
1635 log('Compiling Java sources for {0} with javac...'.format(p.name)) 1637 log('Compiling Java sources for {0} with javac...'.format(p.name))
1636 1638
1637 1639
1638 javacCmd = [java().javac, '-g', '-J-Xmx1g', '-source', compliance, '-classpath', cp, '-d', outputDir] 1640 javacCmd = [java().javac, '-g', '-J-Xmx1g', '-source', compliance, '-classpath', cp, '-d', outputDir]
1639 if java().debug_port is not None: 1641 if java().debug_port is not None:
1640 javacCmd += ['-J-Xdebug', '-J-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(java().debug_port)] 1642 javacCmd += ['-J-Xdebug', '-J-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(java().debug_port)]
1641 javacCmd += processorArgs 1643 javacCmd += processorArgs
1642 javacCmd += ['@' + argfile.name] 1644 javacCmd += ['@' + argfile.name]
1643 1645
1644 if not args.warnAPI: 1646 if not args.warnAPI:
1645 javacCmd.append('-XDignore.symbol.file') 1647 javacCmd.append('-XDignore.symbol.file')
1646 run(javacCmd) 1648 run(javacCmd)
1647 else: 1649 else:
1648 log('Compiling Java sources for {0} with JDT...'.format(p.name)) 1650 log('Compiling Java sources for {0} with JDT...'.format(p.name))
1649 1651
1650 jdtArgs = [java().java, '-Xmx1g'] 1652 jdtArgs = [java().java, '-Xmx1g']
1651 if java().debug_port is not None: 1653 if java().debug_port is not None:
1652 jdtArgs += ['-Xdebug', '-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(java().debug_port)] 1654 jdtArgs += ['-Xdebug', '-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(java().debug_port)]
1653 1655
1654 jdtArgs += [ '-jar', jdtJar, 1656 jdtArgs += [ '-jar', jdtJar,
1655 '-' + compliance, 1657 '-' + compliance,
1656 '-cp', cp, '-g', '-enableJavadoc', 1658 '-cp', cp, '-g', '-enableJavadoc',
1657 '-d', outputDir] 1659 '-d', outputDir]
1658 jdtArgs += processorArgs 1660 jdtArgs += processorArgs
1659 1661
1660 1662
1661 jdtProperties = join(p.dir, '.settings', 'org.eclipse.jdt.core.prefs') 1663 jdtProperties = join(p.dir, '.settings', 'org.eclipse.jdt.core.prefs')
1662 rootJdtProperties = join(p.suite.dir, 'mx', 'eclipse-settings', 'org.eclipse.jdt.core.prefs') 1664 rootJdtProperties = join(p.suite.dir, 'mx', 'eclipse-settings', 'org.eclipse.jdt.core.prefs')
1663 if not exists(jdtProperties) or os.path.getmtime(jdtProperties) < os.path.getmtime(rootJdtProperties): 1665 if not exists(jdtProperties) or os.path.getmtime(jdtProperties) < os.path.getmtime(rootJdtProperties):
1664 # Try to fix a missing properties file by running eclipseinit 1666 # Try to fix a missing properties file by running eclipseinit
1665 eclipseinit([], buildProcessorJars=False) 1667 eclipseinit([], buildProcessorJars=False)
1676 toBeDeleted.append(jdtPropertiesTmp) 1678 toBeDeleted.append(jdtPropertiesTmp)
1677 jdtArgs += ['-properties', jdtPropertiesTmp] 1679 jdtArgs += ['-properties', jdtPropertiesTmp]
1678 else: 1680 else:
1679 jdtArgs += ['-properties', jdtProperties] 1681 jdtArgs += ['-properties', jdtProperties]
1680 jdtArgs.append('@' + argfile.name) 1682 jdtArgs.append('@' + argfile.name)
1681 1683
1682 run(jdtArgs) 1684 run(jdtArgs)
1683 finally: 1685 finally:
1684 for n in toBeDeleted: 1686 for n in toBeDeleted:
1685 os.remove(n) 1687 os.remove(n)
1686 1688
1687 for dist in _dists.values(): 1689 for dist in _dists.values():
1688 archive(['@' + dist.name]) 1690 archive(['@' + dist.name])
1689 1691
1690 if suppliedParser: 1692 if suppliedParser:
1691 return args 1693 return args
1698 1700
1699 parser = ArgumentParser(prog='mx eclipseformat') 1701 parser = ArgumentParser(prog='mx eclipseformat')
1700 parser.add_argument('-e', '--eclipse-exe', help='location of the Eclipse executable') 1702 parser.add_argument('-e', '--eclipse-exe', help='location of the Eclipse executable')
1701 parser.add_argument('-C', '--no-backup', action='store_false', dest='backup', help='do not save backup of modified files') 1703 parser.add_argument('-C', '--no-backup', action='store_false', dest='backup', help='do not save backup of modified files')
1702 parser.add_argument('--projects', action='store', help='comma separated projects to process (omit to process all projects)') 1704 parser.add_argument('--projects', action='store', help='comma separated projects to process (omit to process all projects)')
1703 1705
1704 args = parser.parse_args(args) 1706 args = parser.parse_args(args)
1705 if args.eclipse_exe is None: 1707 if args.eclipse_exe is None:
1706 args.eclipse_exe = os.environ.get('ECLIPSE_EXE') 1708 args.eclipse_exe = os.environ.get('ECLIPSE_EXE')
1707 if args.eclipse_exe is None: 1709 if args.eclipse_exe is None:
1708 abort('Could not find Eclipse executable. Use -e option or ensure ECLIPSE_EXE environment variable is set.') 1710 abort('Could not find Eclipse executable. Use -e option or ensure ECLIPSE_EXE environment variable is set.')
1709 1711
1710 # Maybe an Eclipse installation dir was specified - look for the executable in it 1712 # Maybe an Eclipse installation dir was specified - look for the executable in it
1711 if join(args.eclipse_exe, exe_suffix('eclipse')): 1713 if join(args.eclipse_exe, exe_suffix('eclipse')):
1712 args.eclipse_exe = join(args.eclipse_exe, exe_suffix('eclipse')) 1714 args.eclipse_exe = join(args.eclipse_exe, exe_suffix('eclipse'))
1713 1715
1714 if not os.path.isfile(args.eclipse_exe) or not os.access(args.eclipse_exe, os.X_OK): 1716 if not os.path.isfile(args.eclipse_exe) or not os.access(args.eclipse_exe, os.X_OK):
1715 abort('Not an executable file: ' + args.eclipse_exe) 1717 abort('Not an executable file: ' + args.eclipse_exe)
1716 1718
1717 eclipseinit([], buildProcessorJars=False) 1719 eclipseinit([], buildProcessorJars=False)
1718 1720
1723 1725
1724 class Batch: 1726 class Batch:
1725 def __init__(self, settingsFile): 1727 def __init__(self, settingsFile):
1726 self.path = settingsFile 1728 self.path = settingsFile
1727 self.javafiles = list() 1729 self.javafiles = list()
1728 1730
1729 def settings(self): 1731 def settings(self):
1730 with open(self.path) as fp: 1732 with open(self.path) as fp:
1731 return fp.read() 1733 return fp.read()
1732 1734
1733 class FileInfo: 1735 class FileInfo:
1742 content = fp.read() 1744 content = fp.read()
1743 if self.content != content: 1745 if self.content != content:
1744 self.content = content 1746 self.content = content
1745 return True 1747 return True
1746 os.utime(self.path, self.times) 1748 os.utime(self.path, self.times)
1747 1749
1748 modified = list() 1750 modified = list()
1749 batches = dict() # all sources with the same formatting settings are formatted together 1751 batches = dict() # all sources with the same formatting settings are formatted together
1750 for p in projects: 1752 for p in projects:
1751 if p.native: 1753 if p.native:
1752 continue 1754 continue
1753 sourceDirs = p.source_dirs() 1755 sourceDirs = p.source_dirs()
1754 1756
1755 batch = Batch(join(p.dir, '.settings', 'org.eclipse.jdt.core.prefs')) 1757 batch = Batch(join(p.dir, '.settings', 'org.eclipse.jdt.core.prefs'))
1756 1758
1757 if not exists(batch.path): 1759 if not exists(batch.path):
1758 if _opts.verbose: 1760 if _opts.verbose:
1759 log('[no Eclipse Code Formatter preferences at {0} - skipping]'.format(batch.path)) 1761 log('[no Eclipse Code Formatter preferences at {0} - skipping]'.format(batch.path))
1774 for batch in batches.itervalues(): 1776 for batch in batches.itervalues():
1775 run([args.eclipse_exe, '-nosplash', '-application', 'org.eclipse.jdt.core.JavaCodeFormatter', '-config', batch.path] + [f.path for f in batch.javafiles]) 1777 run([args.eclipse_exe, '-nosplash', '-application', 'org.eclipse.jdt.core.JavaCodeFormatter', '-config', batch.path] + [f.path for f in batch.javafiles])
1776 for fi in batch.javafiles: 1778 for fi in batch.javafiles:
1777 if fi.update(): 1779 if fi.update():
1778 modified.append(fi) 1780 modified.append(fi)
1779 1781
1780 log('{0} files were modified'.format(len(modified))) 1782 log('{0} files were modified'.format(len(modified)))
1781 if len(modified) != 0: 1783 if len(modified) != 0:
1782 if args.backup: 1784 if args.backup:
1783 backup = os.path.abspath('eclipseformat.backup.zip') 1785 backup = os.path.abspath('eclipseformat.backup.zip')
1784 arcbase = _mainSuite.dir 1786 arcbase = _mainSuite.dir
1790 log('Wrote backup of {0} modified files to {1}'.format(len(modified), backup)) 1792 log('Wrote backup of {0} modified files to {1}'.format(len(modified), backup))
1791 return 1 1793 return 1
1792 return 0 1794 return 0
1793 1795
1794 def processorjars(): 1796 def processorjars():
1795 1797
1796 projs = set() 1798 projs = set()
1797 for p in sorted_deps(): 1799 for p in sorted_deps():
1798 if _isAnnotationProcessorDependency(p): 1800 if _isAnnotationProcessorDependency(p):
1799 projs.add(p) 1801 projs.add(p)
1800 1802
1801 if len(projs) < 0: 1803 if len(projs) < 0:
1802 return 1804 return
1803 1805
1804 pnames = [p.name for p in projs] 1806 pnames = [p.name for p in projs]
1805 build(['--projects', ",".join(pnames)]) 1807 build(['--projects', ",".join(pnames)])
1806 archive(pnames) 1808 archive(pnames)
1807 1809
1808 def archive(args): 1810 def archive(args):
1809 """create jar files for projects and distributions""" 1811 """create jar files for projects and distributions"""
1810 parser = ArgumentParser(prog='mx archive'); 1812 parser = ArgumentParser(prog='mx archive')
1811 parser.add_argument('names', nargs=REMAINDER, metavar='[<project>|@<distribution>]...') 1813 parser.add_argument('names', nargs=REMAINDER, metavar='[<project>|@<distribution>]...')
1812 args = parser.parse_args(args) 1814 args = parser.parse_args(args)
1813 1815
1814 for name in args.names: 1816 for name in args.names:
1815 if name.startswith('@'): 1817 if name.startswith('@'):
1816 dname = name[1:] 1818 dname = name[1:]
1817 d = distribution(dname) 1819 d = distribution(dname)
1818 fd, tmp = tempfile.mkstemp(suffix='', prefix=basename(d.path) + '.', dir=dirname(d.path)) 1820 fd, tmp = tempfile.mkstemp(suffix='', prefix=basename(d.path) + '.', dir=dirname(d.path))
1819 services = tempfile.mkdtemp(suffix='', prefix=basename(d.path) + '.', dir=dirname(d.path)) 1821 services = tempfile.mkdtemp(suffix='', prefix=basename(d.path) + '.', dir=dirname(d.path))
1820 1822
1821 def overwriteCheck(zf, arcname, source): 1823 def overwriteCheck(zf, arcname, source):
1822 if arcname in zf.namelist(): 1824 if arcname in zf.namelist():
1823 log('warning: ' + d.path + ': overwriting ' + arcname + ' [source: ' + source + ']') 1825 log('warning: ' + d.path + ': overwriting ' + arcname + ' [source: ' + source + ']')
1824 1826
1825 try: 1827 try:
1826 zf = zipfile.ZipFile(tmp, 'w') 1828 zf = zipfile.ZipFile(tmp, 'w')
1827 for dep in sorted_deps(d.deps, includeLibs=True): 1829 for dep in sorted_deps(d.deps, includeLibs=True):
1828 if dep.isLibrary(): 1830 if dep.isLibrary():
1829 l = dep 1831 l = dep
1844 p = dep 1846 p = dep
1845 # skip a Java project if its Java compliance level is "higher" than the configured JDK 1847 # skip a Java project if its Java compliance level is "higher" than the configured JDK
1846 if java().javaCompliance < p.javaCompliance: 1848 if java().javaCompliance < p.javaCompliance:
1847 log('Excluding {0} from {2} (Java compliance level {1} required)'.format(p.name, p.javaCompliance, d.path)) 1849 log('Excluding {0} from {2} (Java compliance level {1} required)'.format(p.name, p.javaCompliance, d.path))
1848 continue 1850 continue
1849 1851
1850 logv('[' + d.path + ': adding project ' + p.name + ']') 1852 logv('[' + d.path + ': adding project ' + p.name + ']')
1851 outputDir = p.output_dir() 1853 outputDir = p.output_dir()
1852 for root, _, files in os.walk(outputDir): 1854 for root, _, files in os.walk(outputDir):
1853 relpath = root[len(outputDir) + 1:] 1855 relpath = root[len(outputDir) + 1:]
1854 if relpath == join('META-INF', 'services'): 1856 if relpath == join('META-INF', 'services'):
1874 zf.close() 1876 zf.close()
1875 os.close(fd) 1877 os.close(fd)
1876 shutil.rmtree(services) 1878 shutil.rmtree(services)
1877 # Atomic on Unix 1879 # Atomic on Unix
1878 shutil.move(tmp, d.path) 1880 shutil.move(tmp, d.path)
1879 #print time.time(), 'move:', tmp, '->', d.path 1881 # print time.time(), 'move:', tmp, '->', d.path
1880 d.notify_updated() 1882 d.notify_updated()
1881 finally: 1883 finally:
1882 if exists(tmp): 1884 if exists(tmp):
1883 os.remove(tmp) 1885 os.remove(tmp)
1884 if exists(services): 1886 if exists(services):
1922 m = pattern.match(line) 1924 m = pattern.match(line)
1923 if m is None: 1925 if m is None:
1924 out.write(line + '\n') 1926 out.write(line + '\n')
1925 else: 1927 else:
1926 p = project(m.group(1)) 1928 p = project(m.group(1))
1927 1929
1928 for pkg in p.defined_java_packages(): 1930 for pkg in p.defined_java_packages():
1929 if not pkg.startswith(p.name): 1931 if not pkg.startswith(p.name):
1930 abort('package in {0} does not have prefix matching project name: {1}'.format(p, pkg)) 1932 abort('package in {0} does not have prefix matching project name: {1}'.format(p, pkg))
1931 1933
1932 ignoredDeps = set([name for name in p.deps if project(name, False) is not None]) 1934 ignoredDeps = set([name for name in p.deps if project(name, False) is not None])
1933 for pkg in p.imported_java_packages(): 1935 for pkg in p.imported_java_packages():
1934 for name in p.deps: 1936 for name in p.deps:
1935 dep = project(name, False) 1937 dep = project(name, False)
1936 if dep is None: 1938 if dep is None:
1939 if pkg in dep.defined_java_packages(): 1941 if pkg in dep.defined_java_packages():
1940 ignoredDeps.discard(name) 1942 ignoredDeps.discard(name)
1941 if pkg in dep.extended_java_packages(): 1943 if pkg in dep.extended_java_packages():
1942 ignoredDeps.discard(name) 1944 ignoredDeps.discard(name)
1943 if len(ignoredDeps) != 0: 1945 if len(ignoredDeps) != 0:
1944 candidates = set(); 1946 candidates = set()
1945 # Compute dependencies based on projects required by p 1947 # Compute dependencies based on projects required by p
1946 for d in sorted_deps(): 1948 for d in sorted_deps():
1947 if not d.defined_java_packages().isdisjoint(p.imported_java_packages()): 1949 if not d.defined_java_packages().isdisjoint(p.imported_java_packages()):
1948 candidates.add(d) 1950 candidates.add(d)
1949 # Remove non-canonical candidates 1951 # Remove non-canonical candidates
1950 for c in list(candidates): 1952 for c in list(candidates):
1951 candidates.difference_update(c.all_deps([], False, False)) 1953 candidates.difference_update(c.all_deps([], False, False))
1952 candidates = [d.name for d in candidates] 1954 candidates = [d.name for d in candidates]
1953 1955
1954 abort('{0}:{1}: {2} does not use any packages defined in these projects: {3}\nComputed project dependencies: {4}'.format( 1956 abort('{0}:{1}: {2} does not use any packages defined in these projects: {3}\nComputed project dependencies: {4}'.format(
1955 projectsFile, lineNo, p, ', '.join(ignoredDeps), ','.join(candidates))) 1957 projectsFile, lineNo, p, ', '.join(ignoredDeps), ','.join(candidates)))
1956 1958
1957 out.write('project@' + m.group(1) + '@dependencies=' + ','.join(p.canonical_deps()) + '\n') 1959 out.write('project@' + m.group(1) + '@dependencies=' + ','.join(p.canonical_deps()) + '\n')
1958 lineNo = lineNo + 1 1960 lineNo = lineNo + 1
1959 content = out.getvalue() 1961 content = out.getvalue()
1960 if update_file(projectsFile, content): 1962 if update_file(projectsFile, content):
1961 changedFiles += 1 1963 changedFiles += 1
1962 return changedFiles; 1964 return changedFiles
1963 1965
1964 def checkstyle(args): 1966 def checkstyle(args):
1965 """run Checkstyle on the Java sources 1967 """run Checkstyle on the Java sources
1966 1968
1967 Run Checkstyle over the Java sources. Any errors or warnings 1969 Run Checkstyle over the Java sources. Any errors or warnings
1969 1971
1970 parser = ArgumentParser(prog='mx checkstyle') 1972 parser = ArgumentParser(prog='mx checkstyle')
1971 1973
1972 parser.add_argument('-f', action='store_true', dest='force', help='force checking (disables timestamp checking)') 1974 parser.add_argument('-f', action='store_true', dest='force', help='force checking (disables timestamp checking)')
1973 args = parser.parse_args(args) 1975 args = parser.parse_args(args)
1974 1976
1975 totalErrors = 0 1977 totalErrors = 0
1976 for p in sorted_deps(): 1978 for p in sorted_deps():
1977 if p.native: 1979 if p.native:
1978 continue 1980 continue
1979 sourceDirs = p.source_dirs() 1981 sourceDirs = p.source_dirs()
1980 dotCheckstyle = join(p.dir, '.checkstyle') 1982 dotCheckstyle = join(p.dir, '.checkstyle')
1981 1983
1982 if not exists(dotCheckstyle): 1984 if not exists(dotCheckstyle):
1983 continue 1985 continue
1984 1986
1985 # skip checking this Java project if its Java compliance level is "higher" than the configured JDK 1987 # skip checking this Java project if its Java compliance level is "higher" than the configured JDK
1986 if java().javaCompliance < p.javaCompliance: 1988 if java().javaCompliance < p.javaCompliance:
1987 log('Excluding {0} from checking (Java compliance level {1} required)'.format(p.name, p.javaCompliance)) 1989 log('Excluding {0} from checking (Java compliance level {1} required)'.format(p.name, p.javaCompliance))
1988 continue 1990 continue
1989 1991
2072 try: 2074 try:
2073 run_java(['-Xmx1g', '-jar', library('CHECKSTYLE').get_path(True), '-f', 'xml', '-c', config, '-o', auditfileName] + batch, nonZeroIsFatal=False) 2075 run_java(['-Xmx1g', '-jar', library('CHECKSTYLE').get_path(True), '-f', 'xml', '-c', config, '-o', auditfileName] + batch, nonZeroIsFatal=False)
2074 finally: 2076 finally:
2075 if exists(auditfileName): 2077 if exists(auditfileName):
2076 errors = [] 2078 errors = []
2077 source = None 2079 source = [None]
2078 def start_element(name, attrs): 2080 def start_element(name, attrs):
2079 if name == 'file': 2081 if name == 'file':
2080 global source 2082 source[0] = attrs['name']
2081 source = attrs['name']
2082 elif name == 'error': 2083 elif name == 'error':
2083 errors.append('{}:{}: {}'.format(source, attrs['line'], attrs['message'])) 2084 errors.append('{}:{}: {}'.format(source[0], attrs['line'], attrs['message']))
2084 2085
2085 p = xml.parsers.expat.ParserCreate() 2086 p = xml.parsers.expat.ParserCreate()
2086 p.StartElementHandler = start_element 2087 p.StartElementHandler = start_element
2087 with open(auditfileName) as fp: 2088 with open(auditfileName) as fp:
2088 p.ParseFile(fp) 2089 p.ParseFile(fp)
2106 generated images. 2107 generated images.
2107 """ 2108 """
2108 2109
2109 suppliedParser = parser is not None 2110 suppliedParser = parser is not None
2110 2111
2111 parser = parser if suppliedParser else ArgumentParser(prog='mx build'); 2112 parser = parser if suppliedParser else ArgumentParser(prog='mx build')
2112 parser.add_argument('--no-native', action='store_false', dest='native', help='do not clean native projects') 2113 parser.add_argument('--no-native', action='store_false', dest='native', help='do not clean native projects')
2113 parser.add_argument('--no-java', action='store_false', dest='java', help='do not clean Java projects') 2114 parser.add_argument('--no-java', action='store_false', dest='java', help='do not clean Java projects')
2114 2115
2115 args = parser.parse_args(args) 2116 args = parser.parse_args(args)
2116 2117
2118 if p.native: 2119 if p.native:
2119 if args.native: 2120 if args.native:
2120 run([gmake_cmd(), '-C', p.dir, 'clean']) 2121 run([gmake_cmd(), '-C', p.dir, 'clean'])
2121 else: 2122 else:
2122 if args.java: 2123 if args.java:
2123 genDir = p.source_gen_dir(); 2124 genDir = p.source_gen_dir()
2124 if genDir != '' and exists(genDir): 2125 if genDir != '' and exists(genDir):
2125 log('Clearing {0}...'.format(genDir)) 2126 log('Clearing {0}...'.format(genDir))
2126 for f in os.listdir(genDir): 2127 for f in os.listdir(genDir):
2127 shutil.rmtree(join(genDir, f)) 2128 shutil.rmtree(join(genDir, f))
2128 2129
2129 2130
2130 outputDir = p.output_dir() 2131 outputDir = p.output_dir()
2131 if outputDir != '' and exists(outputDir): 2132 if outputDir != '' and exists(outputDir):
2132 log('Removing {0}...'.format(outputDir)) 2133 log('Removing {0}...'.format(outputDir))
2133 shutil.rmtree(outputDir) 2134 shutil.rmtree(outputDir)
2134 2135
2148 if len(args) == 0: 2149 if len(args) == 0:
2149 _argParser.print_help() 2150 _argParser.print_help()
2150 return 2151 return
2151 2152
2152 name = args[0] 2153 name = args[0]
2153 if not commands.has_key(name): 2154 if not _commands.has_key(name):
2154 hits = [c for c in commands.iterkeys() if c.startswith(name)] 2155 hits = [c for c in _commands.iterkeys() if c.startswith(name)]
2155 if len(hits) == 1: 2156 if len(hits) == 1:
2156 name = hits[0] 2157 name = hits[0]
2157 elif len(hits) == 0: 2158 elif len(hits) == 0:
2158 abort('mx: unknown command \'{0}\'\n{1}use "mx help" for more options'.format(name, _format_commands())) 2159 abort('mx: unknown command \'{0}\'\n{1}use "mx help" for more options'.format(name, _format_commands()))
2159 else: 2160 else:
2160 abort('mx: command \'{0}\' is ambiguous\n {1}'.format(name, ' '.join(hits))) 2161 abort('mx: command \'{0}\' is ambiguous\n {1}'.format(name, ' '.join(hits)))
2161 2162
2162 value = commands[name] 2163 value = _commands[name]
2163 (func, usage) = value[:2] 2164 (func, usage) = value[:2]
2164 doc = func.__doc__ 2165 doc = func.__doc__
2165 if len(value) > 2: 2166 if len(value) > 2:
2166 docArgs = value[2:] 2167 docArgs = value[2:]
2167 fmtArgs = [] 2168 fmtArgs = []
2204 2205
2205 slm.close('sourceContainers') 2206 slm.close('sourceContainers')
2206 slm.close('sourceLookupDirector') 2207 slm.close('sourceLookupDirector')
2207 return slm 2208 return slm
2208 2209
2209 def make_eclipse_attach(hostname, port, name=None, deps=[]): 2210 def make_eclipse_attach(hostname, port, name=None, deps=None):
2210 """ 2211 """
2211 Creates an Eclipse launch configuration file for attaching to a Java process. 2212 Creates an Eclipse launch configuration file for attaching to a Java process.
2212 """ 2213 """
2214 if deps is None:
2215 deps = []
2213 slm = _source_locator_memento(deps) 2216 slm = _source_locator_memento(deps)
2214 launch = XMLDoc() 2217 launch = XMLDoc()
2215 launch.open('launchConfiguration', {'type' : 'org.eclipse.jdt.launching.remoteJavaApplication'}) 2218 launch.open('launchConfiguration', {'type' : 'org.eclipse.jdt.launching.remoteJavaApplication'})
2216 launch.element('stringAttribute', {'key' : 'org.eclipse.debug.core.source_locator_id', 'value' : 'org.eclipse.jdt.launching.sourceLocator.JavaSourceLookupDirector'}) 2219 launch.element('stringAttribute', {'key' : 'org.eclipse.debug.core.source_locator_id', 'value' : 'org.eclipse.jdt.launching.sourceLocator.JavaSourceLookupDirector'})
2217 launch.element('stringAttribute', {'key' : 'org.eclipse.debug.core.source_locator_memento', 'value' : '%s'}) 2220 launch.element('stringAttribute', {'key' : 'org.eclipse.debug.core.source_locator_memento', 'value' : '%s'})
2230 eclipseLaunches = join('mx', 'eclipse-launches') 2233 eclipseLaunches = join('mx', 'eclipse-launches')
2231 if not exists(eclipseLaunches): 2234 if not exists(eclipseLaunches):
2232 os.makedirs(eclipseLaunches) 2235 os.makedirs(eclipseLaunches)
2233 return update_file(join(eclipseLaunches, name + '.launch'), launch) 2236 return update_file(join(eclipseLaunches, name + '.launch'), launch)
2234 2237
2235 def make_eclipse_launch(javaArgs, jre, name=None, deps=[]): 2238 def make_eclipse_launch(javaArgs, jre, name=None, deps=None):
2236 """ 2239 """
2237 Creates an Eclipse launch configuration file for running/debugging a Java command. 2240 Creates an Eclipse launch configuration file for running/debugging a Java command.
2238 """ 2241 """
2242 if deps is None:
2243 deps = []
2239 mainClass = None 2244 mainClass = None
2240 vmArgs = [] 2245 vmArgs = []
2241 appArgs = [] 2246 appArgs = []
2242 cp = None 2247 cp = None
2243 argsCopy = list(reversed(javaArgs)) 2248 argsCopy = list(reversed(javaArgs))
2300 def eclipseinit(args, suite=None, buildProcessorJars=True): 2305 def eclipseinit(args, suite=None, buildProcessorJars=True):
2301 """(re)generate Eclipse project configurations and working sets""" 2306 """(re)generate Eclipse project configurations and working sets"""
2302 2307
2303 if suite is None: 2308 if suite is None:
2304 suite = _mainSuite 2309 suite = _mainSuite
2305 2310
2306 if buildProcessorJars: 2311 if buildProcessorJars:
2307 processorjars() 2312 processorjars()
2308 2313
2309 projToDist = dict() 2314 projToDist = dict()
2310 for dist in _dists.values(): 2315 for dist in _dists.values():
2327 if not exists(srcDir): 2332 if not exists(srcDir):
2328 os.mkdir(srcDir) 2333 os.mkdir(srcDir)
2329 out.element('classpathentry', {'kind' : 'src', 'path' : src}) 2334 out.element('classpathentry', {'kind' : 'src', 'path' : src})
2330 2335
2331 if len(p.annotation_processors()) > 0: 2336 if len(p.annotation_processors()) > 0:
2332 genDir = p.source_gen_dir(); 2337 genDir = p.source_gen_dir()
2333 if not exists(genDir): 2338 if not exists(genDir):
2334 os.mkdir(genDir) 2339 os.mkdir(genDir)
2335 out.element('classpathentry', {'kind' : 'src', 'path' : 'src_gen'}) 2340 out.element('classpathentry', {'kind' : 'src', 'path' : 'src_gen'})
2336 2341
2337 # Every Java program depends on the JRE 2342 # Every Java program depends on the JRE
2338 out.element('classpathentry', {'kind' : 'con', 'path' : 'org.eclipse.jdt.launching.JRE_CONTAINER'}) 2343 out.element('classpathentry', {'kind' : 'con', 'path' : 'org.eclipse.jdt.launching.JRE_CONTAINER'})
2339 2344
2340 if exists(join(p.dir, 'plugin.xml')): # eclipse plugin project 2345 if exists(join(p.dir, 'plugin.xml')): # eclipse plugin project
2341 out.element('classpathentry', {'kind' : 'con', 'path' : 'org.eclipse.pde.core.requiredPlugins'}) 2346 out.element('classpathentry', {'kind' : 'con', 'path' : 'org.eclipse.pde.core.requiredPlugins'})
2342 2347
2343 for dep in p.all_deps([], True): 2348 for dep in p.all_deps([], True):
2344 if dep == p: 2349 if dep == p:
2345 continue; 2350 continue
2346 2351
2347 if dep.isLibrary(): 2352 if dep.isLibrary():
2348 if hasattr(dep, 'eclipse.container'): 2353 if hasattr(dep, 'eclipse.container'):
2349 out.element('classpathentry', {'exported' : 'true', 'kind' : 'con', 'path' : getattr(dep, 'eclipse.container')}) 2354 out.element('classpathentry', {'exported' : 'true', 'kind' : 'con', 'path' : getattr(dep, 'eclipse.container')})
2350 elif hasattr(dep, 'eclipse.project'): 2355 elif hasattr(dep, 'eclipse.project'):
2417 if exists(csConfig): 2422 if exists(csConfig):
2418 out.open('buildCommand') 2423 out.open('buildCommand')
2419 out.element('name', data='net.sf.eclipsecs.core.CheckstyleBuilder') 2424 out.element('name', data='net.sf.eclipsecs.core.CheckstyleBuilder')
2420 out.element('arguments', data='') 2425 out.element('arguments', data='')
2421 out.close('buildCommand') 2426 out.close('buildCommand')
2422 if exists(join(p.dir, 'plugin.xml')): # eclipse plugin project 2427 if exists(join(p.dir, 'plugin.xml')): # eclipse plugin project
2423 for buildCommand in ['org.eclipse.pde.ManifestBuilder', 'org.eclipse.pde.SchemaBuilder']: 2428 for buildCommand in ['org.eclipse.pde.ManifestBuilder', 'org.eclipse.pde.SchemaBuilder']:
2424 out.open('buildCommand') 2429 out.open('buildCommand')
2425 out.element('name', data=buildCommand) 2430 out.element('name', data=buildCommand)
2426 out.element('arguments', data='') 2431 out.element('arguments', data='')
2427 out.close('buildCommand') 2432 out.close('buildCommand')
2428 2433
2429 if _isAnnotationProcessorDependency(p): 2434 if _isAnnotationProcessorDependency(p):
2430 _genEclipseBuilder(out, p, 'Jar.launch', 'archive ' + p.name, refresh = False, async = False, xmlIndent='', xmlStandalone='no') 2435 _genEclipseBuilder(out, p, 'Jar.launch', 'archive ' + p.name, refresh=False, async=False, xmlIndent='', xmlStandalone='no')
2431 _genEclipseBuilder(out, p, 'Refresh.launch', '', refresh = True, async = True) 2436 _genEclipseBuilder(out, p, 'Refresh.launch', '', refresh=True, async=True)
2432 2437
2433 if projToDist.has_key(p.name): 2438 if projToDist.has_key(p.name):
2434 dist, distDeps = projToDist[p.name] 2439 dist, distDeps = projToDist[p.name]
2435 _genEclipseBuilder(out, p, 'Create' + dist.name + 'Dist.launch', 'archive @' + dist.name, refresh=False, async=True) 2440 _genEclipseBuilder(out, p, 'Create' + dist.name + 'Dist.launch', 'archive @' + dist.name, refresh=False, async=True)
2436 2441
2437 out.close('buildSpec') 2442 out.close('buildSpec')
2438 out.open('natures') 2443 out.open('natures')
2439 out.element('nature', data='org.eclipse.jdt.core.javanature') 2444 out.element('nature', data='org.eclipse.jdt.core.javanature')
2440 if exists(csConfig): 2445 if exists(csConfig):
2441 out.element('nature', data='net.sf.eclipsecs.core.CheckstyleNature') 2446 out.element('nature', data='net.sf.eclipsecs.core.CheckstyleNature')
2442 if exists(join(p.dir, 'plugin.xml')): # eclipse plugin project 2447 if exists(join(p.dir, 'plugin.xml')): # eclipse plugin project
2443 out.element('nature', data='org.eclipse.pde.PluginNature') 2448 out.element('nature', data='org.eclipse.pde.PluginNature')
2444 out.close('natures') 2449 out.close('natures')
2445 out.close('projectDescription') 2450 out.close('projectDescription')
2446 update_file(join(p.dir, '.project'), out.xml(indent='\t', newl='\n')) 2451 update_file(join(p.dir, '.project'), out.xml(indent='\t', newl='\n'))
2447 2452
2460 content = f.read() 2465 content = f.read()
2461 content = content.replace('${javaCompliance}', str(p.javaCompliance)) 2466 content = content.replace('${javaCompliance}', str(p.javaCompliance))
2462 if len(p.annotation_processors()) > 0: 2467 if len(p.annotation_processors()) > 0:
2463 content = content.replace('org.eclipse.jdt.core.compiler.processAnnotations=disabled', 'org.eclipse.jdt.core.compiler.processAnnotations=enabled') 2468 content = content.replace('org.eclipse.jdt.core.compiler.processAnnotations=disabled', 'org.eclipse.jdt.core.compiler.processAnnotations=enabled')
2464 update_file(join(settingsDir, name), content) 2469 update_file(join(settingsDir, name), content)
2465 2470
2466 if len(p.annotation_processors()) > 0: 2471 if len(p.annotation_processors()) > 0:
2467 out = XMLDoc() 2472 out = XMLDoc()
2468 out.open('factorypath') 2473 out.open('factorypath')
2469 out.element('factorypathentry', {'kind' : 'PLUGIN', 'id' : 'org.eclipse.jst.ws.annotations.core', 'enabled' : 'true', 'runInBatchMode' : 'false'}) 2474 out.element('factorypathentry', {'kind' : 'PLUGIN', 'id' : 'org.eclipse.jst.ws.annotations.core', 'enabled' : 'true', 'runInBatchMode' : 'false'})
2470 for ap in p.annotation_processors(): 2475 for ap in p.annotation_processors():
2493 Determines if a given project is part of an annotation processor. 2498 Determines if a given project is part of an annotation processor.
2494 """ 2499 """
2495 return p in sorted_deps(annotation_processors()) 2500 return p in sorted_deps(annotation_processors())
2496 2501
2497 def _genEclipseBuilder(dotProjectDoc, p, name, mxCommand, refresh=True, async=False, logToConsole=False, xmlIndent='\t', xmlStandalone=None): 2502 def _genEclipseBuilder(dotProjectDoc, p, name, mxCommand, refresh=True, async=False, logToConsole=False, xmlIndent='\t', xmlStandalone=None):
2498 launchOut = XMLDoc(); 2503 launchOut = XMLDoc()
2499 consoleOn = 'true' if logToConsole else 'false' 2504 consoleOn = 'true' if logToConsole else 'false'
2500 launchOut.open('launchConfiguration', {'type' : 'org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType'}) 2505 launchOut.open('launchConfiguration', {'type' : 'org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType'})
2501 launchOut.element('booleanAttribute', {'key' : 'org.eclipse.debug.core.capture_output', 'value': consoleOn}) 2506 launchOut.element('booleanAttribute', {'key' : 'org.eclipse.debug.core.capture_output', 'value': consoleOn})
2502 launchOut.open('mapAttribute', {'key' : 'org.eclipse.debug.core.environmentVariables'}) 2507 launchOut.open('mapAttribute', {'key' : 'org.eclipse.debug.core.environmentVariables'})
2503 launchOut.element('mapEntry', {'key' : 'JAVA_HOME', 'value' : java().jdk}) 2508 launchOut.element('mapEntry', {'key' : 'JAVA_HOME', 'value' : java().jdk})
2504 launchOut.close('mapAttribute') 2509 launchOut.close('mapAttribute')
2505 2510
2506 if refresh: 2511 if refresh:
2507 launchOut.element('stringAttribute', {'key' : 'org.eclipse.debug.core.ATTR_REFRESH_SCOPE', 'value': '${project}'}) 2512 launchOut.element('stringAttribute', {'key' : 'org.eclipse.debug.core.ATTR_REFRESH_SCOPE', 'value': '${project}'})
2508 launchOut.element('booleanAttribute', {'key' : 'org.eclipse.debug.ui.ATTR_CONSOLE_OUTPUT_ON', 'value': consoleOn}) 2513 launchOut.element('booleanAttribute', {'key' : 'org.eclipse.debug.ui.ATTR_CONSOLE_OUTPUT_ON', 'value': consoleOn})
2509 launchOut.element('booleanAttribute', {'key' : 'org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND', 'value': 'true' if async else 'false'}) 2514 launchOut.element('booleanAttribute', {'key' : 'org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND', 'value': 'true' if async else 'false'})
2510 2515
2511 baseDir = dirname(dirname(os.path.abspath(__file__))) 2516 baseDir = dirname(dirname(os.path.abspath(__file__)))
2512 2517
2513 cmd = 'mx.sh' 2518 cmd = 'mx.sh'
2514 if get_os() == 'windows': 2519 if get_os() == 'windows':
2515 cmd = 'mx.cmd' 2520 cmd = 'mx.cmd'
2516 launchOut.element('stringAttribute', {'key' : 'org.eclipse.ui.externaltools.ATTR_LOCATION', 'value': join(baseDir, cmd) }) 2521 launchOut.element('stringAttribute', {'key' : 'org.eclipse.ui.externaltools.ATTR_LOCATION', 'value': join(baseDir, cmd) })
2517 launchOut.element('stringAttribute', {'key' : 'org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS', 'value': 'auto,full,incremental'}) 2522 launchOut.element('stringAttribute', {'key' : 'org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS', 'value': 'auto,full,incremental'})
2518 launchOut.element('stringAttribute', {'key' : 'org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS', 'value': mxCommand}) 2523 launchOut.element('stringAttribute', {'key' : 'org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS', 'value': mxCommand})
2519 launchOut.element('booleanAttribute', {'key' : 'org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED','value': 'true'}) 2524 launchOut.element('booleanAttribute', {'key' : 'org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED', 'value': 'true'})
2520 launchOut.element('stringAttribute', {'key' : 'org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY', 'value': p.suite.dir}) 2525 launchOut.element('stringAttribute', {'key' : 'org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY', 'value': p.suite.dir})
2521 2526
2522 2527
2523 launchOut.close('launchConfiguration') 2528 launchOut.close('launchConfiguration')
2524 2529
2525 externalToolDir = join(p.dir, '.externalToolBuilders') 2530 externalToolDir = join(p.dir, '.externalToolBuilders')
2526 2531
2527 if not exists(externalToolDir): 2532 if not exists(externalToolDir):
2528 os.makedirs(externalToolDir) 2533 os.makedirs(externalToolDir)
2529 update_file(join(externalToolDir, name), launchOut.xml(indent=xmlIndent, standalone=xmlStandalone, newl='\n')) 2534 update_file(join(externalToolDir, name), launchOut.xml(indent=xmlIndent, standalone=xmlStandalone, newl='\n'))
2530 2535
2531 dotProjectDoc.open('buildCommand') 2536 dotProjectDoc.open('buildCommand')
2532 dotProjectDoc.element('name', data='org.eclipse.ui.externaltools.ExternalToolBuilder') 2537 dotProjectDoc.element('name', data='org.eclipse.ui.externaltools.ExternalToolBuilder')
2533 dotProjectDoc.element('triggers', data='auto,full,incremental,') 2538 dotProjectDoc.element('triggers', data='auto,full,incremental,')
2534 dotProjectDoc.open('arguments') 2539 dotProjectDoc.open('arguments')
2535 dotProjectDoc.open('dictionary') 2540 dotProjectDoc.open('dictionary')
2536 dotProjectDoc.element('key', data = 'LaunchConfigHandle') 2541 dotProjectDoc.element('key', data='LaunchConfigHandle')
2537 dotProjectDoc.element('value', data = '<project>/.externalToolBuilders/' + name) 2542 dotProjectDoc.element('value', data='<project>/.externalToolBuilders/' + name)
2538 dotProjectDoc.close('dictionary') 2543 dotProjectDoc.close('dictionary')
2539 dotProjectDoc.open('dictionary') 2544 dotProjectDoc.open('dictionary')
2540 dotProjectDoc.element('key', data = 'incclean') 2545 dotProjectDoc.element('key', data='incclean')
2541 dotProjectDoc.element('value', data = 'true') 2546 dotProjectDoc.element('value', data='true')
2542 dotProjectDoc.close('dictionary') 2547 dotProjectDoc.close('dictionary')
2543 dotProjectDoc.close('arguments') 2548 dotProjectDoc.close('arguments')
2544 dotProjectDoc.close('buildCommand') 2549 dotProjectDoc.close('buildCommand')
2545 2550
2546 def generate_eclipse_workingsets(suite): 2551 def generate_eclipse_workingsets(suite):
2547 """ 2552 """
2548 Populate the workspace's working set configuration with working sets generated from project data. 2553 Populate the workspace's working set configuration with working sets generated from project data.
2549 If the workspace already contains working set definitions, the existing ones will be retained and extended. 2554 If the workspace already contains working set definitions, the existing ones will be retained and extended.
2550 In case mx/env does not contain a WORKSPACE definition pointing to the workspace root directory, the Graal project root directory will be assumed. 2555 In case mx/env does not contain a WORKSPACE definition pointing to the workspace root directory, the Graal project root directory will be assumed.
2551 If no workspace root directory can be identified, the Graal project root directory is used and the user has to place the workingsets.xml file by hand. 2556 If no workspace root directory can be identified, the Graal project root directory is used and the user has to place the workingsets.xml file by hand.
2552 """ 2557 """
2553 2558
2554 # identify the location where to look for workingsets.xml 2559 # identify the location where to look for workingsets.xml
2555 wsfilename = 'workingsets.xml' 2560 wsfilename = 'workingsets.xml'
2556 wsroot = suite.dir 2561 wsroot = suite.dir
2557 if os.environ.has_key('WORKSPACE'): 2562 if os.environ.has_key('WORKSPACE'):
2558 wsroot = os.environ['WORKSPACE'] 2563 wsroot = os.environ['WORKSPACE']
2559 wsdir = join(wsroot, '.metadata/.plugins/org.eclipse.ui.workbench') 2564 wsdir = join(wsroot, '.metadata/.plugins/org.eclipse.ui.workbench')
2560 if not exists(wsdir): 2565 if not exists(wsdir):
2561 wsdir = wsroot 2566 wsdir = wsroot
2562 wspath = join(wsdir, wsfilename) 2567 wspath = join(wsdir, wsfilename)
2563 2568
2564 # gather working set info from project data 2569 # gather working set info from project data
2565 workingSets = dict() 2570 workingSets = dict()
2566 for p in projects(): 2571 for p in projects():
2567 if p.workingSets is None: 2572 if p.workingSets is None:
2568 continue 2573 continue
2569 for w in p.workingSets.split(","): 2574 for w in p.workingSets.split(","):
2570 if not workingSets.has_key(w): 2575 if not workingSets.has_key(w):
2571 workingSets[w] = [p.name] 2576 workingSets[w] = [p.name]
2572 else: 2577 else:
2573 workingSets[w].append(p.name) 2578 workingSets[w].append(p.name)
2574 2579
2575 if exists(wspath): 2580 if exists(wspath):
2576 wsdoc = _copy_workingset_xml(wspath, workingSets) 2581 wsdoc = _copy_workingset_xml(wspath, workingSets)
2577 else: 2582 else:
2578 wsdoc = _make_workingset_xml(workingSets) 2583 wsdoc = _make_workingset_xml(workingSets)
2579 2584
2580 update_file(wspath, wsdoc.xml(newl='\n')) 2585 update_file(wspath, wsdoc.xml(newl='\n'))
2581 2586
2582 def _make_workingset_xml(workingSets): 2587 def _make_workingset_xml(workingSets):
2583 wsdoc = XMLDoc() 2588 wsdoc = XMLDoc()
2584 wsdoc.open('workingSetManager') 2589 wsdoc.open('workingSetManager')
2585 2590
2586 for w in sorted(workingSets.keys()): 2591 for w in sorted(workingSets.keys()):
2587 _workingset_open(wsdoc, w) 2592 _workingset_open(wsdoc, w)
2588 for p in workingSets[w]: 2593 for p in workingSets[w]:
2589 _workingset_element(wsdoc, p) 2594 _workingset_element(wsdoc, p)
2590 wsdoc.close('workingSet') 2595 wsdoc.close('workingSet')
2591 2596
2592 wsdoc.close('workingSetManager') 2597 wsdoc.close('workingSetManager')
2593 return wsdoc 2598 return wsdoc
2594 2599
2595 def _copy_workingset_xml(wspath, workingSets): 2600 def _copy_workingset_xml(wspath, workingSets):
2596 target = XMLDoc() 2601 target = XMLDoc()
2597 target.open('workingSetManager') 2602 target.open('workingSetManager')
2598 2603
2599 parser = xml.parsers.expat.ParserCreate() 2604 parser = xml.parsers.expat.ParserCreate()
2600 2605
2601 class ParserState(object): 2606 class ParserState(object):
2602 def __init__(self): 2607 def __init__(self):
2603 self.current_ws_name = 'none yet' 2608 self.current_ws_name = 'none yet'
2604 self.current_ws = None 2609 self.current_ws = None
2605 self.seen_ws = list() 2610 self.seen_ws = list()
2606 self.seen_projects = list() 2611 self.seen_projects = list()
2607 2612
2608 ps = ParserState() 2613 ps = ParserState()
2609 2614
2610 # parsing logic 2615 # parsing logic
2611 def _ws_start(name, attributes): 2616 def _ws_start(name, attributes):
2612 if name == 'workingSet': 2617 if name == 'workingSet':
2613 ps.current_ws_name = attributes['name'] 2618 ps.current_ws_name = attributes['name']
2614 if workingSets.has_key(ps.current_ws_name): 2619 if workingSets.has_key(ps.current_ws_name):
2617 ps.seen_projects = list() 2622 ps.seen_projects = list()
2618 else: 2623 else:
2619 ps.current_ws = None 2624 ps.current_ws = None
2620 target.open(name, attributes) 2625 target.open(name, attributes)
2621 parser.StartElementHandler = _ws_item 2626 parser.StartElementHandler = _ws_item
2622 2627
2623 def _ws_end(name): 2628 def _ws_end(name):
2624 if name == 'workingSet': 2629 if name == 'workingSet':
2625 if not ps.current_ws is None: 2630 if not ps.current_ws is None:
2626 for p in ps.current_ws: 2631 for p in ps.current_ws:
2627 if not p in ps.seen_projects: 2632 if not p in ps.seen_projects:
2634 if not w in ps.seen_ws: 2639 if not w in ps.seen_ws:
2635 _workingset_open(target, w) 2640 _workingset_open(target, w)
2636 for p in workingSets[w]: 2641 for p in workingSets[w]:
2637 _workingset_element(target, p) 2642 _workingset_element(target, p)
2638 target.close('workingSet') 2643 target.close('workingSet')
2639 2644
2640 def _ws_item(name, attributes): 2645 def _ws_item(name, attributes):
2641 if name == 'item': 2646 if name == 'item':
2642 if ps.current_ws is None: 2647 if ps.current_ws is None:
2643 target.element(name, attributes) 2648 target.element(name, attributes)
2644 else: 2649 else:
2645 p_name = attributes['elementID'][1:] # strip off the leading '=' 2650 p_name = attributes['elementID'][1:] # strip off the leading '='
2646 _workingset_element(target, p_name) 2651 _workingset_element(target, p_name)
2647 ps.seen_projects.append(p_name) 2652 ps.seen_projects.append(p_name)
2648 2653
2649 # process document 2654 # process document
2650 parser.StartElementHandler = _ws_start 2655 parser.StartElementHandler = _ws_start
2651 parser.EndElementHandler = _ws_end 2656 parser.EndElementHandler = _ws_end
2652 with open(wspath, 'r') as wsfile: 2657 with open(wspath, 'r') as wsfile:
2653 parser.ParseFile(wsfile) 2658 parser.ParseFile(wsfile)
2654 2659
2655 target.close('workingSetManager') 2660 target.close('workingSetManager')
2656 return target 2661 return target
2657 2662
2658 def _workingset_open(wsdoc, ws): 2663 def _workingset_open(wsdoc, ws):
2659 wsdoc.open('workingSet', {'editPageID': 'org.eclipse.jdt.ui.JavaWorkingSetPage', 'factoryID': 'org.eclipse.ui.internal.WorkingSetFactory', 'id': 'wsid_' + ws, 'label': ws, 'name': ws}) 2664 wsdoc.open('workingSet', {'editPageID': 'org.eclipse.jdt.ui.JavaWorkingSetPage', 'factoryID': 'org.eclipse.ui.internal.WorkingSetFactory', 'id': 'wsid_' + ws, 'label': ws, 'name': ws})
2660 2665
2661 def _workingset_element(wsdoc, p): 2666 def _workingset_element(wsdoc, p):
2662 wsdoc.element('item', {'elementID': '=' + p, 'factoryID': 'org.eclipse.jdt.ui.PersistableJavaElementFactory'}) 2667 wsdoc.element('item', {'elementID': '=' + p, 'factoryID': 'org.eclipse.jdt.ui.PersistableJavaElementFactory'})
2663 2668
2664 def netbeansinit(args, suite=None): 2669 def netbeansinit(args, suite=None):
2665 """(re)generate NetBeans project configurations""" 2670 """(re)generate NetBeans project configurations"""
2666 2671
2667 if suite is None: 2672 if suite is None:
2668 suite = _mainSuite 2673 suite = _mainSuite
2669
2670 def println(out, obj):
2671 out.write(str(obj) + '\n')
2672 2674
2673 updated = False 2675 updated = False
2674 for p in projects(): 2676 for p in projects():
2675 if p.native: 2677 if p.native:
2676 continue 2678 continue
2677 2679
2678 if exists(join(p.dir, 'plugin.xml')): # eclipse plugin project 2680 if exists(join(p.dir, 'plugin.xml')): # eclipse plugin project
2679 continue 2681 continue
2680 2682
2681 if not exists(join(p.dir, 'nbproject')): 2683 if not exists(join(p.dir, 'nbproject')):
2682 os.makedirs(join(p.dir, 'nbproject')) 2684 os.makedirs(join(p.dir, 'nbproject'))
2683 2685
2713 out.close('data') 2715 out.close('data')
2714 2716
2715 firstDep = True 2717 firstDep = True
2716 for dep in p.all_deps([], True): 2718 for dep in p.all_deps([], True):
2717 if dep == p: 2719 if dep == p:
2718 continue; 2720 continue
2719 2721
2720 if not dep.isLibrary(): 2722 if not dep.isLibrary():
2721 n = dep.name.replace('.', '_') 2723 n = dep.name.replace('.', '_')
2722 if firstDep: 2724 if firstDep:
2723 out.open('references', {'xmlns' : 'http://www.netbeans.org/ns/ant-project-references/1'}) 2725 out.open('references', {'xmlns' : 'http://www.netbeans.org/ns/ant-project-references/1'})
2832 mainSrc = False 2834 mainSrc = False
2833 else: 2835 else:
2834 print >> out, 'src.' + src + '.dir=${' + ref + '}' 2836 print >> out, 'src.' + src + '.dir=${' + ref + '}'
2835 2837
2836 javacClasspath = [] 2838 javacClasspath = []
2837 2839
2838 deps = p.all_deps([], True) 2840 deps = p.all_deps([], True)
2839 annotationProcessorOnlyDeps = [] 2841 annotationProcessorOnlyDeps = []
2840 if len(p.annotation_processors()) > 0: 2842 if len(p.annotation_processors()) > 0:
2841 for ap in p.annotation_processors(): 2843 for ap in p.annotation_processors():
2842 apDep = dependency(ap) 2844 apDep = dependency(ap)
2843 if not apDep in deps: 2845 if not apDep in deps:
2844 deps.append(apDep) 2846 deps.append(apDep)
2845 annotationProcessorOnlyDeps.append(apDep) 2847 annotationProcessorOnlyDeps.append(apDep)
2846 2848
2847 annotationProcessorReferences = []; 2849 annotationProcessorReferences = []
2848 2850
2849 for dep in deps: 2851 for dep in deps:
2850 if dep == p: 2852 if dep == p:
2851 continue; 2853 continue
2852 2854
2853 if dep.isLibrary(): 2855 if dep.isLibrary():
2854 if not dep.mustExist: 2856 if not dep.mustExist:
2855 continue 2857 continue
2856 path = dep.get_path(resolve=True) 2858 path = dep.get_path(resolve=True)
2868 2870
2869 if not dep in annotationProcessorOnlyDeps: 2871 if not dep in annotationProcessorOnlyDeps:
2870 javacClasspath.append('${' + ref + '}') 2872 javacClasspath.append('${' + ref + '}')
2871 else: 2873 else:
2872 annotationProcessorReferences.append('${' + ref + '}') 2874 annotationProcessorReferences.append('${' + ref + '}')
2873 annotationProcessorReferences += ":\\\n ${" + ref + "}" 2875 annotationProcessorReferences += ":\\\n ${" + ref + "}"
2874 2876
2875 print >> out, 'javac.classpath=\\\n ' + (os.pathsep + '\\\n ').join(javacClasspath) 2877 print >> out, 'javac.classpath=\\\n ' + (os.pathsep + '\\\n ').join(javacClasspath)
2876 print >> out, 'javac.test.processorpath=${javac.test.classpath}\\\n ' + (os.pathsep + '\\\n ').join(annotationProcessorReferences) 2878 print >> out, 'javac.test.processorpath=${javac.test.classpath}\\\n ' + (os.pathsep + '\\\n ').join(annotationProcessorReferences)
2877 print >> out, 'javac.processorpath=${javac.classpath}\\\n ' + (os.pathsep + '\\\n ').join(annotationProcessorReferences) 2879 print >> out, 'javac.processorpath=${javac.classpath}\\\n ' + (os.pathsep + '\\\n ').join(annotationProcessorReferences)
2878 2880
2879 updated = update_file(join(p.dir, 'nbproject', 'project.properties'), out.getvalue()) or updated 2881 updated = update_file(join(p.dir, 'nbproject', 'project.properties'), out.getvalue()) or updated
2880 out.close() 2882 out.close()
2881 2883
2882 if updated: 2884 if updated:
2883 log('If using NetBeans:') 2885 log('If using NetBeans:')
2904 rm(join(p.dir, 'eclipse-build.xml')) 2906 rm(join(p.dir, 'eclipse-build.xml'))
2905 try: 2907 try:
2906 rm(join(p.dir, p.name + '.jar')) 2908 rm(join(p.dir, p.name + '.jar'))
2907 except: 2909 except:
2908 log("Error removing {0}".format(p.name + '.jar')) 2910 log("Error removing {0}".format(p.name + '.jar'))
2909 2911
2910 2912
2911 def ideinit(args, suite=None): 2913 def ideinit(args, suite=None):
2912 """(re)generate Eclipse and NetBeans project configurations""" 2914 """(re)generate Eclipse and NetBeans project configurations"""
2913 eclipseinit(args, suite) 2915 eclipseinit(args, suite)
2914 netbeansinit(args, suite) 2916 netbeansinit(args, suite)
2987 assess_candidate(d, projects) 2989 assess_candidate(d, projects)
2988 if not assess_candidate(p, projects): 2990 if not assess_candidate(p, projects):
2989 logv('[package-list file exists - skipping {0}]'.format(p.name)) 2991 logv('[package-list file exists - skipping {0}]'.format(p.name))
2990 2992
2991 2993
2992 def find_packages(sourceDirs, pkgs=set()): 2994 def find_packages(sourceDirs, pkgs=None):
2995 if pkgs is None:
2996 pkgs = set()
2993 for sourceDir in sourceDirs: 2997 for sourceDir in sourceDirs:
2994 for root, _, files in os.walk(sourceDir): 2998 for root, _, files in os.walk(sourceDir):
2995 if len([name for name in files if name.endswith('.java')]) != 0: 2999 if len([name for name in files if name.endswith('.java')]) != 0:
2996 pkg = root[len(sourceDir) + 1:].replace(os.sep,'.') 3000 pkg = root[len(sourceDir) + 1:].replace(os.sep, '.')
2997 if len(packages) == 0 or pkg in packages: 3001 if len(packages) == 0 or pkg in packages:
2998 if len(exclude_packages) == 0 or not pkg in exclude_packages: 3002 if len(exclude_packages) == 0 or not pkg in exclude_packages:
2999 pkgs.add(pkg) 3003 pkgs.add(pkg)
3000 return pkgs 3004 return pkgs
3001 3005
3009 3013
3010 if not args.unified: 3014 if not args.unified:
3011 for p in projects: 3015 for p in projects:
3012 # The project must be built to ensure javadoc can find class files for all referenced classes 3016 # The project must be built to ensure javadoc can find class files for all referenced classes
3013 build(['--no-native', '--projects', p.name]) 3017 build(['--no-native', '--projects', p.name])
3014 3018
3015 pkgs = find_packages(p.source_dirs(), set()) 3019 pkgs = find_packages(p.source_dirs(), set())
3016 deps = p.all_deps([], includeLibs=False, includeSelf=False) 3020 deps = p.all_deps([], includeLibs=False, includeSelf=False)
3017 links = ['-link', 'http://docs.oracle.com/javase/' + str(p.javaCompliance.value) + '/docs/api/'] 3021 links = ['-link', 'http://docs.oracle.com/javase/' + str(p.javaCompliance.value) + '/docs/api/']
3018 out = outDir(p) 3022 out = outDir(p)
3019 for d in deps: 3023 for d in deps:
3047 list(pkgs)) 3051 list(pkgs))
3048 log('Generated {2} for {0} in {1}'.format(p.name, out, docDir)) 3052 log('Generated {2} for {0} in {1}'.format(p.name, out, docDir))
3049 finally: 3053 finally:
3050 if delOverviewFile: 3054 if delOverviewFile:
3051 os.remove(overviewFile) 3055 os.remove(overviewFile)
3052 3056
3053 else: 3057 else:
3054 # The projects must be built to ensure javadoc can find class files for all referenced classes 3058 # The projects must be built to ensure javadoc can find class files for all referenced classes
3055 build(['--no-native']) 3059 build(['--no-native'])
3056 3060
3057 pkgs = set() 3061 pkgs = set()
3058 sp = [] 3062 sp = []
3059 names = [] 3063 names = []
3060 for p in projects: 3064 for p in projects:
3061 find_packages(p.source_dirs(), pkgs) 3065 find_packages(p.source_dirs(), pkgs)
3105 else: 3109 else:
3106 rindex = lindex + len(self.ldelim) 3110 rindex = lindex + len(self.ldelim)
3107 rdelimLen = 0 3111 rdelimLen = 0
3108 old = content[lindex:rindex + rdelimLen] 3112 old = content[lindex:rindex + rdelimLen]
3109 return content.replace(old, repl) 3113 return content.replace(old, repl)
3110 3114
3111 # Post-process an overview-summary.html file to move the 3115 # Post-process an overview-summary.html file to move the
3112 # complete overview to the top of the page 3116 # complete overview to the top of the page
3113 def _fix_overview_summary(path, topLink): 3117 def _fix_overview_summary(path, topLink):
3114 """ 3118 """
3115 Processes an "overview-summary.html" generated by javadoc to put the complete 3119 Processes an "overview-summary.html" generated by javadoc to put the complete
3137 <!-- ======= START OF BOTTOM NAVBAR ====== -->""") 3141 <!-- ======= START OF BOTTOM NAVBAR ====== -->""")
3138 3142
3139 assert chunk1.text, 'Could not find header section in ' + path 3143 assert chunk1.text, 'Could not find header section in ' + path
3140 assert chunk2.text, 'Could not find footer section in ' + path 3144 assert chunk2.text, 'Could not find footer section in ' + path
3141 3145
3142 content = chunk1.replace(content, '<div class="header"><div class="subTitle"><div class="block">' + topLink + chunk2.text +'</div></div></div>') 3146 content = chunk1.replace(content, '<div class="header"><div class="subTitle"><div class="block">' + topLink + chunk2.text + '</div></div></div>')
3143 content = chunk2.replace(content, '') 3147 content = chunk2.replace(content, '')
3144 3148
3145 with open(path, 'w') as fp: 3149 with open(path, 'w') as fp:
3146 fp.write(content) 3150 fp.write(content)
3147 3151
3169 <!-- ======= START OF BOTTOM NAVBAR ====== -->""") 3173 <!-- ======= START OF BOTTOM NAVBAR ====== -->""")
3170 3174
3171 if chunk1.text: 3175 if chunk1.text:
3172 if chunk2.text: 3176 if chunk2.text:
3173 repl = re.sub(r'<h2 title=(.*) Description</h2>', r'<h1 title=\1</h1>', chunk2.text, 1) 3177 repl = re.sub(r'<h2 title=(.*) Description</h2>', r'<h1 title=\1</h1>', chunk2.text, 1)
3174 content = chunk1.replace(content, '<div class="header">' + repl +'</div></div>') 3178 content = chunk1.replace(content, '<div class="header">' + repl + '</div></div>')
3175 content = chunk2.replace(content, '') 3179 content = chunk2.replace(content, '')
3176 3180
3177 with open(path, 'w') as fp: 3181 with open(path, 'w') as fp:
3178 fp.write(content) 3182 fp.write(content)
3179 else: 3183 else:
3180 log('warning: Could not find package description detail section in ' + path) 3184 log('warning: Could not find package description detail section in ' + path)
3181 3185
3233 <caption><span>Projects</span><span class="tabEnd">&nbsp;</span></caption> 3237 <caption><span>Projects</span><span class="tabEnd">&nbsp;</span></caption>
3234 <tr><th class="colFirst" scope="col">Project</th><th class="colLast" scope="col">&nbsp;</th></tr> 3238 <tr><th class="colFirst" scope="col">Project</th><th class="colLast" scope="col">&nbsp;</th></tr>
3235 <tbody>""" 3239 <tbody>"""
3236 color = 'row' 3240 color = 'row'
3237 for p in projects: 3241 for p in projects:
3238 print >> fp2, '<tr class="{1}Color"><td class="colFirst"><a href="../{0}/javadoc/index.html", target = "_top">{0}</a></td><td class="colLast">&nbsp;</td></tr>'.format(p.name, color) 3242 print >> fp2, '<tr class="{1}Color"><td class="colFirst"><a href="../{0}/javadoc/index.html",target = "_top">{0}</a></td><td class="colLast">&nbsp;</td></tr>'.format(p.name, color)
3239 color = 'row' if color == 'alt' else 'alt' 3243 color = 'row' if color == 'alt' else 'alt'
3240 3244
3241 print >> fp2, '</tbody></table></div>' 3245 print >> fp2, '</tbody></table></div>'
3242 print >> fp2, content[idx:] 3246 print >> fp2, content[idx:]
3243 3247
3244 title = args.title if args.title is not None else args.name 3248 title = args.title if args.title is not None else args.name
3245 javadoc(['--base', tmpbase, 3249 javadoc(['--base', tmpbase,
3246 '--unified', 3250 '--unified',
3247 '--arg', '@-windowtitle', '--arg', '@' + title, 3251 '--arg', '@-windowtitle', '--arg', '@' + title,
3248 '--arg', '@-doctitle', '--arg', '@' + title, 3252 '--arg', '@-doctitle', '--arg', '@' + title,
3254 dotErr = None 3258 dotErr = None
3255 try: 3259 try:
3256 if not 'version' in subprocess.check_output(['dot', '-V'], stderr=subprocess.STDOUT): 3260 if not 'version' in subprocess.check_output(['dot', '-V'], stderr=subprocess.STDOUT):
3257 dotErr = 'dot -V does not print a string containing "version"' 3261 dotErr = 'dot -V does not print a string containing "version"'
3258 except subprocess.CalledProcessError as e: 3262 except subprocess.CalledProcessError as e:
3259 dotErr = 'error calling "dot -V": {}'.format(e) 3263 dotErr = 'error calling "dot -V": {}'.format(e)
3260 except OSError as e: 3264 except OSError as e:
3261 dotErr = 'error calling "dot -V": {}'.format(e) 3265 dotErr = 'error calling "dot -V": {}'.format(e)
3262 3266
3263 if dotErr != None: 3267 if dotErr != None:
3264 abort('cannot generate dependency graph: ' + dotErr) 3268 abort('cannot generate dependency graph: ' + dotErr)
3265 3269
3266 dot = join(tmpbase, 'all', str(args.dot_output_base) + '.dot') 3270 dot = join(tmpbase, 'all', str(args.dot_output_base) + '.dot')
3267 svg = join(tmpbase, 'all', str(args.dot_output_base) + '.svg') 3271 svg = join(tmpbase, 'all', str(args.dot_output_base) + '.svg')
3271 dim = len(projects) 3275 dim = len(projects)
3272 print >> fp, 'digraph projects {' 3276 print >> fp, 'digraph projects {'
3273 print >> fp, 'rankdir=BT;' 3277 print >> fp, 'rankdir=BT;'
3274 print >> fp, 'size = "' + str(dim) + ',' + str(dim) + '";' 3278 print >> fp, 'size = "' + str(dim) + ',' + str(dim) + '";'
3275 print >> fp, 'node [shape=rect, fontcolor="blue"];' 3279 print >> fp, 'node [shape=rect, fontcolor="blue"];'
3276 #print >> fp, 'edge [color="green"];' 3280 # print >> fp, 'edge [color="green"];'
3277 for p in projects: 3281 for p in projects:
3278 print >> fp, '"' + p.name + '" [URL = "../' + p.name + '/javadoc/index.html", target = "_top"]' 3282 print >> fp, '"' + p.name + '" [URL = "../' + p.name + '/javadoc/index.html", target = "_top"]'
3279 for dep in p.canonical_deps(): 3283 for dep in p.canonical_deps():
3280 if dep in [proj.name for proj in projects]: 3284 if dep in [proj.name for proj in projects]:
3281 print >> fp, '"' + p.name + '" -> "' + dep + '"' 3285 print >> fp, '"' + p.name + '" -> "' + dep + '"'
3282 depths = dict() 3286 depths = dict()
3283 for p in projects: 3287 for p in projects:
3284 d = p.max_depth() 3288 d = p.max_depth()
3285 depths.setdefault(d, list()).append(p.name) 3289 depths.setdefault(d, list()).append(p.name)
3286 print >> fp, '}' 3290 print >> fp, '}'
3287 3291
3288 run(['dot', '-Tsvg', '-o' + svg, '-Tjpg', '-o' + jpg, dot]) 3292 run(['dot', '-Tsvg', '-o' + svg, '-Tjpg', '-o' + jpg, dot])
3289 3293
3290 # Post-process generated SVG to remove title elements which most browsers 3294 # Post-process generated SVG to remove title elements which most browsers
3291 # render as redundant (and annoying) tooltips. 3295 # render as redundant (and annoying) tooltips.
3292 with open(svg, 'r') as fp: 3296 with open(svg, 'r') as fp:
3293 content = fp.read() 3297 content = fp.read()
3294 content = re.sub('<title>.*</title>', '', content) 3298 content = re.sub('<title>.*</title>', '', content)
3295 content = re.sub('xlink:title="[^"]*"', '', content) 3299 content = re.sub('xlink:title="[^"]*"', '', content)
3296 with open(svg, 'w') as fp: 3300 with open(svg, 'w') as fp:
3297 fp.write(content) 3301 fp.write(content)
3298 3302
3299 # Create HTML that embeds the svg file in an <object> frame 3303 # Create HTML that embeds the svg file in an <object> frame
3300 with open(html, 'w') as fp: 3304 with open(html, 'w') as fp:
3301 print >> fp, '<html><body><object data="{}.svg" type="image/svg+xml"></object></body></html>'.format(args.dot_output_base) 3305 print >> fp, '<html><body><object data="{}.svg" type="image/svg+xml"></object></body></html>'.format(args.dot_output_base)
3302 3306
3303 top = join(tmpbase, 'all', 'overview-summary.html') 3307 top = join(tmpbase, 'all', 'overview-summary.html')
3344 return matches 3348 return matches
3345 3349
3346 def select_items(items, descriptions=None, allowMultiple=True): 3350 def select_items(items, descriptions=None, allowMultiple=True):
3347 """ 3351 """
3348 Presents a command line interface for selecting one or more (if allowMultiple is true) items. 3352 Presents a command line interface for selecting one or more (if allowMultiple is true) items.
3349 3353
3350 """ 3354 """
3351 if len(items) <= 1: 3355 if len(items) <= 1:
3352 return items 3356 return items
3353 else: 3357 else:
3354 if allowMultiple: 3358 if allowMultiple:
3368 try: 3372 try:
3369 s = [int(x) for x in s] 3373 s = [int(x) for x in s]
3370 except: 3374 except:
3371 log('Selection contains non-numeric characters: "' + ' '.join(s) + '"') 3375 log('Selection contains non-numeric characters: "' + ' '.join(s) + '"')
3372 continue 3376 continue
3373 3377
3374 if allowMultiple and 0 in s: 3378 if allowMultiple and 0 in s:
3375 return items 3379 return items
3376 3380
3377 indexes = [] 3381 indexes = []
3378 for n in s: 3382 for n in s:
3379 if n not in range(1, len(items) + 1): 3383 if n not in range(1, len(items) + 1):
3380 log('Invalid selection: ' + str(n)) 3384 log('Invalid selection: ' + str(n))
3381 continue 3385 continue
3388 return None 3392 return None
3389 3393
3390 def javap(args): 3394 def javap(args):
3391 """disassemble classes matching given pattern with javap""" 3395 """disassemble classes matching given pattern with javap"""
3392 3396
3393 javap = java().javap 3397 javapExe = java().javap
3394 if not exists(javap): 3398 if not exists(javapExe):
3395 abort('The javap executable does not exists: ' + javap) 3399 abort('The javap executable does not exists: ' + javapExe)
3396 else: 3400 else:
3397 candidates = findclass(args, logToConsole=False) 3401 candidates = findclass(args, logToConsole=False)
3398 if len(candidates) == 0: 3402 if len(candidates) == 0:
3399 log('no matches') 3403 log('no matches')
3400 selection = select_items(candidates) 3404 selection = select_items(candidates)
3401 run([javap, '-private', '-verbose', '-classpath', classpath()] + selection) 3405 run([javapExe, '-private', '-verbose', '-classpath', classpath()] + selection)
3402 3406
3403 def show_projects(args): 3407 def show_projects(args):
3404 """show all loaded projects""" 3408 """show all loaded projects"""
3405 for s in suites(): 3409 for s in suites():
3406 projectsFile = join(s.dir, 'mx', 'projects') 3410 projectsFile = join(s.dir, 'mx', 'projects')
3407 if exists(projectsFile): 3411 if exists(projectsFile):
3408 log(projectsFile) 3412 log(projectsFile)
3409 for p in s.projects: 3413 for p in s.projects:
3410 log('\t' + p.name) 3414 log('\t' + p.name)
3411 3415
3412 def ask_yes_no(question, default=None): 3416 def ask_yes_no(question, default=None):
3413 """""" 3417 """"""
3414 assert not default or default == 'y' or default == 'n' 3418 assert not default or default == 'y' or default == 'n'
3415 if not sys.stdout.isatty(): 3419 if not sys.stdout.isatty():
3416 if default: 3420 if default:
3435 # Table of commands in alphabetical order. 3439 # Table of commands in alphabetical order.
3436 # Keys are command names, value are lists: [<function>, <usage msg>, <format args to doc string of function>...] 3440 # Keys are command names, value are lists: [<function>, <usage msg>, <format args to doc string of function>...]
3437 # If any of the format args are instances of Callable, then they are called with an 'env' are before being 3441 # If any of the format args are instances of Callable, then they are called with an 'env' are before being
3438 # used in the call to str.format(). 3442 # used in the call to str.format().
3439 # Extensions should update this table directly 3443 # Extensions should update this table directly
3440 commands = { 3444 _commands = {
3441 'about': [about, ''], 3445 'about': [about, ''],
3442 'build': [build, '[options]'], 3446 'build': [build, '[options]'],
3443 'checkstyle': [checkstyle, ''], 3447 'checkstyle': [checkstyle, ''],
3444 'canonicalizeprojects': [canonicalizeprojects, ''], 3448 'canonicalizeprojects': [canonicalizeprojects, ''],
3445 'clean': [clean, ''], 3449 'clean': [clean, ''],
3500 return 3504 return
3501 3505
3502 command = commandAndArgs[0] 3506 command = commandAndArgs[0]
3503 command_args = commandAndArgs[1:] 3507 command_args = commandAndArgs[1:]
3504 3508
3505 if not commands.has_key(command): 3509 if not _commands.has_key(command):
3506 hits = [c for c in commands.iterkeys() if c.startswith(command)] 3510 hits = [c for c in _commands.iterkeys() if c.startswith(command)]
3507 if len(hits) == 1: 3511 if len(hits) == 1:
3508 command = hits[0] 3512 command = hits[0]
3509 elif len(hits) == 0: 3513 elif len(hits) == 0:
3510 abort('mx: unknown command \'{0}\'\n{1}use "mx help" for more options'.format(command, _format_commands())) 3514 abort('mx: unknown command \'{0}\'\n{1}use "mx help" for more options'.format(command, _format_commands()))
3511 else: 3515 else:
3512 abort('mx: command \'{0}\' is ambiguous\n {1}'.format(command, ' '.join(hits))) 3516 abort('mx: command \'{0}\' is ambiguous\n {1}'.format(command, ' '.join(hits)))
3513 3517
3514 c, _ = commands[command][:2] 3518 c, _ = _commands[command][:2]
3515 def term_handler(signum, frame): 3519 def term_handler(signum, frame):
3516 abort(1) 3520 abort(1)
3517 signal.signal(signal.SIGTERM, term_handler) 3521 signal.signal(signal.SIGTERM, term_handler)
3518 try: 3522 try:
3519 if opts.timeout != 0: 3523 if opts.timeout != 0: