comparison mxtool/mx.py @ 5455:271e83dcfcef

added findclass command to mx tool
author Doug Simon <doug.simon@oracle.com>
date Wed, 30 May 2012 18:07:38 +0200
parents bfc9aeb1264c
children 9911227e6dd3
comparison
equal deleted inserted replaced
5454:3d2ad5c8db10 5455:271e83dcfcef
122 by extension commands. 122 by extension commands.
123 123
124 Property values can use environment variables with Bash syntax (e.g. ${HOME}). 124 Property values can use environment variables with Bash syntax (e.g. ${HOME}).
125 """ 125 """
126 126
127 import sys, os, errno, time, subprocess, shlex, types, urllib2, contextlib, StringIO, zipfile, signal, xml.sax.saxutils 127 import sys, os, errno, time, subprocess, shlex, types, urllib2, contextlib, StringIO, zipfile, signal, xml.sax.saxutils, tempfile
128 import shutil, fnmatch, re, xml.dom.minidom 128 import shutil, fnmatch, re, xml.dom.minidom
129 from collections import Callable 129 from collections import Callable
130 from threading import Thread 130 from threading import Thread
131 from argparse import ArgumentParser, REMAINDER 131 from argparse import ArgumentParser, REMAINDER
132 from os.path import join, basename, dirname, exists, getmtime, isabs, expandvars, isdir, isfile 132 from os.path import join, basename, dirname, exists, getmtime, isabs, expandvars, isdir, isfile
402 _libs[l.name] = l 402 _libs[l.name] = l
403 403
404 class XMLElement(xml.dom.minidom.Element): 404 class XMLElement(xml.dom.minidom.Element):
405 def writexml(self, writer, indent="", addindent="", newl=""): 405 def writexml(self, writer, indent="", addindent="", newl=""):
406 writer.write(indent+"<" + self.tagName) 406 writer.write(indent+"<" + self.tagName)
407 407
408 attrs = self._get_attributes() 408 attrs = self._get_attributes()
409 a_names = attrs.keys() 409 a_names = attrs.keys()
410 a_names.sort() 410 a_names.sort()
411 411
412 for a_name in a_names: 412 for a_name in a_names:
413 writer.write(" %s=\"" % a_name) 413 writer.write(" %s=\"" % a_name)
414 xml.dom.minidom._write_data(writer, attrs[a_name].value) 414 xml.dom.minidom._write_data(writer, attrs[a_name].value)
415 writer.write("\"") 415 writer.write("\"")
416 if self.childNodes: 416 if self.childNodes:
417 if not self.ownerDocument.padTextNodeWithoutSiblings and len(self.childNodes) == 1 and isinstance(self.childNodes[0], xml.dom.minidom.Text): 417 if not self.ownerDocument.padTextNodeWithoutSiblings and len(self.childNodes) == 1 and isinstance(self.childNodes[0], xml.dom.minidom.Text):
418 # if the only child of an Element node is a Text node, then the 418 # if the only child of an Element node is a Text node, then the
419 # text is printed without any indentation or new line padding 419 # text is printed without any indentation or new line padding
420 writer.write(">") 420 writer.write(">")
421 self.childNodes[0].writexml(writer) 421 self.childNodes[0].writexml(writer)
422 writer.write("</%s>%s" % (self.tagName,newl)) 422 writer.write("</%s>%s" % (self.tagName,newl))
423 else: 423 else:
424 writer.write(">%s"%(newl)) 424 writer.write(">%s"%(newl))
438 def createElement(self, tagName): 438 def createElement(self, tagName):
439 # overwritten to create XMLElement 439 # overwritten to create XMLElement
440 e = XMLElement(tagName) 440 e = XMLElement(tagName)
441 e.ownerDocument = self 441 e.ownerDocument = self
442 return e 442 return e
443 443
444 def open(self, tag, attributes={}, data=None): 444 def open(self, tag, attributes={}, data=None):
445 element = self.createElement(tag) 445 element = self.createElement(tag)
446 for key, value in attributes.items(): 446 for key, value in attributes.items():
447 element.setAttribute(key, value) 447 element.setAttribute(key, value)
448 self.current.appendChild(element) 448 self.current.appendChild(element)
451 element.appendChild(self.createTextNode(data)) 451 element.appendChild(self.createTextNode(data))
452 return self 452 return self
453 453
454 def close(self, tag): 454 def close(self, tag):
455 assert self.current != self 455 assert self.current != self
456 assert tag == self.current.tagName, str(tag) + ' != ' + self.current.tagName 456 assert tag == self.current.tagName, str(tag) + ' != ' + self.current.tagName
457 self.current = self.current.parentNode 457 self.current = self.current.parentNode
458 return self 458 return self
459 459
460 def element(self, tag, attributes={}, data=None): 460 def element(self, tag, attributes={}, data=None):
461 return self.open(tag, attributes, data).close(tag) 461 return self.open(tag, attributes, data).close(tag)
462 462
463 def xml(self, indent='', newl='', escape=False): 463 def xml(self, indent='', newl='', escape=False):
464 assert self.current == self 464 assert self.current == self
465 result = self.toprettyxml(indent, newl, encoding="UTF-8") 465 result = self.toprettyxml(indent, newl, encoding="UTF-8")
466 if escape: 466 if escape:
467 entities = { '"': "&quot;", "'": "&apos;", '\n': '&#10;' } 467 entities = { '"': "&quot;", "'": "&apos;", '\n': '&#10;' }
532 d.append_to_classpath(cp, resolve) 532 d.append_to_classpath(cp, resolve)
533 if _opts.cp_suffix is not None: 533 if _opts.cp_suffix is not None:
534 cp += [_opts.cp_suffix] 534 cp += [_opts.cp_suffix]
535 return os.pathsep.join(cp) 535 return os.pathsep.join(cp)
536 536
537 def classpath(names=None, resolve=True, includeSelf=True): 537 def classpath(names=None, resolve=True, includeSelf=True, includeBootClasspath=False):
538 """ 538 """
539 Get the class path for a list of given projects, resolving each entry in the 539 Get the class path for a list of given projects, resolving each entry in the
540 path (e.g. downloading a missing library) if 'resolve' is true. 540 path (e.g. downloading a missing library) if 'resolve' is true.
541 """ 541 """
542 if names is None: 542 if names is None:
543 return _as_classpath(sorted_deps(includeLibs=True), resolve) 543 result = _as_classpath(sorted_deps(includeLibs=True), resolve)
544 deps = []
545 if isinstance(names, types.StringTypes):
546 project(names).all_deps(deps, True, includeSelf)
547 else: 544 else:
548 for n in names: 545 deps = []
549 project(n).all_deps(deps, True, includeSelf) 546 if isinstance(names, types.StringTypes):
550 return _as_classpath(deps, resolve) 547 project(names).all_deps(deps, True, includeSelf)
548 else:
549 for n in names:
550 project(n).all_deps(deps, True, includeSelf)
551 result = _as_classpath(deps, resolve)
552 if includeBootClasspath:
553 result = os.pathsep.join([java().bootclasspath(), result])
554 return result
555
556 def classpath_walk(names=None, resolve=True, includeSelf=True, includeBootClasspath=False):
557 """
558 Walks the resources available in a given classpath, yielding a tuple for each resource
559 where the first member of the tuple is a directory path or ZipFile object for a
560 classpath entry and the second member is the qualified path of the resource relative
561 to the classpath entry.
562 """
563 cp = classpath(names, resolve, includeSelf, includeBootClasspath)
564 for entry in cp.split(os.pathsep):
565 if not exists(entry):
566 continue
567 if isdir(entry):
568 for root, dirs, files in os.walk(entry):
569 for d in dirs:
570 entryPath = join(root[len(entry) + 1:], d)
571 yield entry, entryPath
572 for f in files:
573 entryPath = join(root[len(entry) + 1:], f)
574 yield entry, entryPath
575 elif entry.endswith('.jar') or entry.endswith('.zip'):
576 with zipfile.ZipFile(entry, 'r') as zf:
577 for zi in zf.infolist():
578 entryPath = zi.filename
579 yield zf, entryPath
551 580
552 def sorted_deps(projectNames=None, includeLibs=False): 581 def sorted_deps(projectNames=None, includeLibs=False):
553 """ 582 """
554 Gets projects and libraries sorted such that dependencies 583 Gets projects and libraries sorted such that dependencies
555 are before the projects that depend on them. Unless 'includeLibs' is 584 are before the projects that depend on them. Unless 'includeLibs' is
828 self.debug_port = opts.java_dbg_port 857 self.debug_port = opts.java_dbg_port
829 self.java = exe_suffix(join(self.jdk, 'bin', 'java')) 858 self.java = exe_suffix(join(self.jdk, 'bin', 'java'))
830 self.javac = exe_suffix(join(self.jdk, 'bin', 'javac')) 859 self.javac = exe_suffix(join(self.jdk, 'bin', 'javac'))
831 self.javap = exe_suffix(join(self.jdk, 'bin', 'javap')) 860 self.javap = exe_suffix(join(self.jdk, 'bin', 'javap'))
832 self.javadoc = exe_suffix(join(self.jdk, 'bin', 'javadoc')) 861 self.javadoc = exe_suffix(join(self.jdk, 'bin', 'javadoc'))
862 self._bootclasspath = None
833 863
834 if not exists(self.java): 864 if not exists(self.java):
835 abort('Java launcher derived from JAVA_HOME does not exist: ' + self.java) 865 abort('Java launcher derived from JAVA_HOME does not exist: ' + self.java)
836 866
837 def delAtAndSplit(s): 867 def delAtAndSplit(s):
860 if self.debug_port is not None: 890 if self.debug_port is not None:
861 self.java_args += ['-Xdebug', '-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(self.debug_port)] 891 self.java_args += ['-Xdebug', '-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(self.debug_port)]
862 892
863 def format_cmd(self, args): 893 def format_cmd(self, args):
864 return [self.java] + self.java_args_pfx + self.java_args + self.java_args_sfx + args 894 return [self.java] + self.java_args_pfx + self.java_args + self.java_args_sfx + args
895
896 def bootclasspath(self):
897 if self._bootclasspath is None:
898 tmpDir = tempfile.mkdtemp()
899 try:
900 src = join(tmpDir, 'bootclasspath.java')
901 with open(src, 'w') as fp:
902 print >> fp, """
903 public class bootclasspath {
904 public static void main(String[] args) {
905 String s = System.getProperty("sun.boot.class.path");
906 if (s != null) {
907 System.out.println(s);
908 }
909 }
910 }"""
911 subprocess.check_call([self.javac, '-d', tmpDir, src])
912 self._bootclasspath = subprocess.check_output([self.java, '-cp', tmpDir, 'bootclasspath'])
913 finally:
914 shutil.rmtree(tmpDir)
915 return self._bootclasspath
865 916
866 def check_get_env(key): 917 def check_get_env(key):
867 """ 918 """
868 Gets an environment variable, aborting with a useful message if it is not set. 919 Gets an environment variable, aborting with a useful message if it is not set.
869 """ 920 """
1037 parser = ArgumentParser(prog='mx build') 1088 parser = ArgumentParser(prog='mx build')
1038 1089
1039 javaCompliance = java().javaCompliance 1090 javaCompliance = java().javaCompliance
1040 1091
1041 defaultEcjPath = join(_mainSuite.dir, 'mx', 'ecj.jar') 1092 defaultEcjPath = join(_mainSuite.dir, 'mx', 'ecj.jar')
1042 1093
1043 parser = parser if parser is not None else ArgumentParser(prog='mx build') 1094 parser = parser if parser is not None else ArgumentParser(prog='mx build')
1044 parser.add_argument('-f', action='store_true', dest='force', help='force build (disables timestamp checking)') 1095 parser.add_argument('-f', action='store_true', dest='force', help='force build (disables timestamp checking)')
1045 parser.add_argument('-c', action='store_true', dest='clean', help='removes existing build output') 1096 parser.add_argument('-c', action='store_true', dest='clean', help='removes existing build output')
1046 parser.add_argument('--source', dest='compliance', help='Java compliance level', default=str(javaCompliance)) 1097 parser.add_argument('--source', dest='compliance', help='Java compliance level', default=str(javaCompliance))
1047 parser.add_argument('--Wapi', action='store_true', dest='warnAPI', help='show warnings about using internal APIs') 1098 parser.add_argument('--Wapi', action='store_true', dest='warnAPI', help='show warnings about using internal APIs')
1438 print 'node [shape=rect];' 1489 print 'node [shape=rect];'
1439 for p in projects(): 1490 for p in projects():
1440 for dep in p.canonical_deps(): 1491 for dep in p.canonical_deps():
1441 print '"' + p.name + '"->"' + dep + '"' 1492 print '"' + p.name + '"->"' + dep + '"'
1442 print '}' 1493 print '}'
1443 1494
1444 1495
1445 def _source_locator_memento(deps): 1496 def _source_locator_memento(deps):
1446 slm = XMLDoc() 1497 slm = XMLDoc()
1447 slm.open('sourceLookupDirector') 1498 slm.open('sourceLookupDirector')
1448 slm.open('sourceContainers', {'duplicates' : 'false'}) 1499 slm.open('sourceContainers', {'duplicates' : 'false'})
1449 1500
1450 # Every Java program depends on the JRE 1501 # Every Java program depends on the JRE
1451 memento = XMLDoc().element('classpathContainer', {'path' : 'org.eclipse.jdt.launching.JRE_CONTAINER'}).xml() 1502 memento = XMLDoc().element('classpathContainer', {'path' : 'org.eclipse.jdt.launching.JRE_CONTAINER'}).xml()
1452 slm.element('classpathContainer', {'memento' : memento, 'typeId':'org.eclipse.jdt.launching.sourceContainer.classpathContainer'}) 1503 slm.element('classpathContainer', {'memento' : memento, 'typeId':'org.eclipse.jdt.launching.sourceContainer.classpathContainer'})
1453 1504
1454 for dep in deps: 1505 for dep in deps:
1455 if dep.isLibrary(): 1506 if dep.isLibrary():
1456 if hasattr(dep, 'eclipse.container'): 1507 if hasattr(dep, 'eclipse.container'):
1457 memento = XMLDoc().element('classpathContainer', {'path' : getattr(dep, 'eclipse.container')}).xml() 1508 memento = XMLDoc().element('classpathContainer', {'path' : getattr(dep, 'eclipse.container')}).xml()
1458 slm.element('classpathContainer', {'memento' : memento, 'typeId':'org.eclipse.jdt.launching.sourceContainer.classpathContainer'}) 1509 slm.element('classpathContainer', {'memento' : memento, 'typeId':'org.eclipse.jdt.launching.sourceContainer.classpathContainer'})
1480 launch.close('mapAttribute') 1531 launch.close('mapAttribute')
1481 launch.element('stringAttribute', {'key' : 'org.eclipse.jdt.launching.PROJECT_ATTR', 'value' : ''}) 1532 launch.element('stringAttribute', {'key' : 'org.eclipse.jdt.launching.PROJECT_ATTR', 'value' : ''})
1482 launch.element('stringAttribute', {'key' : 'org.eclipse.jdt.launching.VM_CONNECTOR_ID', 'value' : 'org.eclipse.jdt.launching.socketAttachConnector'}) 1533 launch.element('stringAttribute', {'key' : 'org.eclipse.jdt.launching.VM_CONNECTOR_ID', 'value' : 'org.eclipse.jdt.launching.socketAttachConnector'})
1483 launch.close('launchConfiguration') 1534 launch.close('launchConfiguration')
1484 launch = launch.xml(newl='\n') % slm.xml(escape=True) 1535 launch = launch.xml(newl='\n') % slm.xml(escape=True)
1485 1536
1486 if name is None: 1537 if name is None:
1487 name = 'attach-' + hostname + '-' + port 1538 name = 'attach-' + hostname + '-' + port
1488 eclipseLaunches = join('mx', 'eclipse-launches') 1539 eclipseLaunches = join('mx', 'eclipse-launches')
1489 if not exists(eclipseLaunches): 1540 if not exists(eclipseLaunches):
1490 os.makedirs(eclipseLaunches) 1541 os.makedirs(eclipseLaunches)
1514 vmArgs.append(a) 1565 vmArgs.append(a)
1515 else: 1566 else:
1516 mainClass = a 1567 mainClass = a
1517 appArgs = list(reversed(argsCopy)) 1568 appArgs = list(reversed(argsCopy))
1518 break 1569 break
1519 1570
1520 if mainClass is None: 1571 if mainClass is None:
1521 log('Cannot create Eclipse launch configuration without main class or jar file: java ' + ' '.join(javaArgs)) 1572 log('Cannot create Eclipse launch configuration without main class or jar file: java ' + ' '.join(javaArgs))
1522 return False 1573 return False
1523 1574
1524 if name is None: 1575 if name is None:
1525 if mainClass == '-jar': 1576 if mainClass == '-jar':
1526 name = basename(appArgs[0]) 1577 name = basename(appArgs[0])
1527 if len(appArgs) > 1 and not appArgs[1].startswith('-'): 1578 if len(appArgs) > 1 and not appArgs[1].startswith('-'):
1528 name = name + '_' + appArgs[1] 1579 name = name + '_' + appArgs[1]
1533 if cp is not None: 1584 if cp is not None:
1534 for e in cp.split(os.pathsep): 1585 for e in cp.split(os.pathsep):
1535 for s in suites(): 1586 for s in suites():
1536 deps += [p for p in s.projects if e == p.output_dir()] 1587 deps += [p for p in s.projects if e == p.output_dir()]
1537 deps += [l for l in s.libs if e == l.get_path(False)] 1588 deps += [l for l in s.libs if e == l.get_path(False)]
1538 1589
1539 slm = _source_locator_memento(deps) 1590 slm = _source_locator_memento(deps)
1540 1591
1541 launch = XMLDoc() 1592 launch = XMLDoc()
1542 launch.open('launchConfiguration', {'type' : 'org.eclipse.jdt.launching.localJavaApplication'}) 1593 launch.open('launchConfiguration', {'type' : 'org.eclipse.jdt.launching.localJavaApplication'})
1543 launch.element('stringAttribute', {'key' : 'org.eclipse.debug.core.source_locator_id', 'value' : 'org.eclipse.jdt.launching.sourceLocator.JavaSourceLookupDirector'}) 1594 launch.element('stringAttribute', {'key' : 'org.eclipse.debug.core.source_locator_id', 'value' : 'org.eclipse.jdt.launching.sourceLocator.JavaSourceLookupDirector'})
1544 launch.element('stringAttribute', {'key' : 'org.eclipse.debug.core.source_locator_memento', 'value' : '%s'}) 1595 launch.element('stringAttribute', {'key' : 'org.eclipse.debug.core.source_locator_memento', 'value' : '%s'})
1545 launch.element('stringAttribute', {'key' : 'org.eclipse.jdt.launching.JRE_CONTAINER', 'value' : 'org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/' + jre}) 1596 launch.element('stringAttribute', {'key' : 'org.eclipse.jdt.launching.JRE_CONTAINER', 'value' : 'org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/' + jre})
1562 suite = _mainSuite 1613 suite = _mainSuite
1563 1614
1564 for p in projects(): 1615 for p in projects():
1565 if p.native: 1616 if p.native:
1566 continue 1617 continue
1567 1618
1568 if not exists(p.dir): 1619 if not exists(p.dir):
1569 os.makedirs(p.dir) 1620 os.makedirs(p.dir)
1570 1621
1571 out = XMLDoc() 1622 out = XMLDoc()
1572 out.open('classpath') 1623 out.open('classpath')
1573 1624
1574 for src in p.srcDirs: 1625 for src in p.srcDirs:
1575 srcDir = join(p.dir, src) 1626 srcDir = join(p.dir, src)
1576 if not exists(srcDir): 1627 if not exists(srcDir):
1577 os.mkdir(srcDir) 1628 os.mkdir(srcDir)
1578 out.element('classpathentry', {'kind' : 'src', 'path' : src}) 1629 out.element('classpathentry', {'kind' : 'src', 'path' : src})
1675 with open(join(eclipseSettingsDir, name)) as f: 1726 with open(join(eclipseSettingsDir, name)) as f:
1676 content = f.read() 1727 content = f.read()
1677 content = content.replace('${javaCompliance}', str(p.javaCompliance)) 1728 content = content.replace('${javaCompliance}', str(p.javaCompliance))
1678 update_file(join(settingsDir, name), content) 1729 update_file(join(settingsDir, name), content)
1679 1730
1680 make_eclipse_attach('localhost', '8000', deps=projects()) 1731 make_eclipse_attach('localhost', '8000', deps=projects())
1681 1732
1682 def netbeansinit(args, suite=None): 1733 def netbeansinit(args, suite=None):
1683 """(re)generate NetBeans project configurations""" 1734 """(re)generate NetBeans project configurations"""
1684 1735
1685 if suite is None: 1736 if suite is None:
1715 out.close('source-roots') 1766 out.close('source-roots')
1716 out.open('test-roots') 1767 out.open('test-roots')
1717 out.element('root', {'id' : 'test.src.dir'}) 1768 out.element('root', {'id' : 'test.src.dir'})
1718 out.close('test-roots') 1769 out.close('test-roots')
1719 out.close('data') 1770 out.close('data')
1720 1771
1721 firstDep = True 1772 firstDep = True
1722 for dep in p.all_deps([], True): 1773 for dep in p.all_deps([], True):
1723 if dep == p: 1774 if dep == p:
1724 continue; 1775 continue;
1725 1776
1892 eclipseinit(args, suite) 1943 eclipseinit(args, suite)
1893 netbeansinit(args, suite) 1944 netbeansinit(args, suite)
1894 1945
1895 def javadoc(args): 1946 def javadoc(args):
1896 """generate javadoc for some/all Java projects""" 1947 """generate javadoc for some/all Java projects"""
1897 1948
1898 parser = ArgumentParser(prog='mx javadoc') 1949 parser = ArgumentParser(prog='mx javadoc')
1899 parser.add_argument('--unified', action='store_true', help='put javadoc in a single directory instead of one per project') 1950 parser.add_argument('--unified', action='store_true', help='put javadoc in a single directory instead of one per project')
1900 parser.add_argument('--force', action='store_true', help='(re)generate javadoc even if package-list file exists') 1951 parser.add_argument('--force', action='store_true', help='(re)generate javadoc even if package-list file exists')
1901 parser.add_argument('--projects', action='store', help='comma separated projects to process (omit to process all projects)') 1952 parser.add_argument('--projects', action='store', help='comma separated projects to process (omit to process all projects)')
1902 parser.add_argument('--argfile', action='store', help='name of file containing extra javadoc options') 1953 parser.add_argument('--argfile', action='store', help='name of file containing extra javadoc options')
2004 sp = os.pathsep.join(sp) 2055 sp = os.pathsep.join(sp)
2005 log('Generating {2} for {0} in {1}'.format(', '.join(names), out, docDir)) 2056 log('Generating {2} for {0} in {1}'.format(', '.join(names), out, docDir))
2006 run([java().javadoc, memory, '-classpath', cp, '-quiet', '-d', out, '-sourcepath', sp] + docletArgs + links + extraArgs + list(pkgs)) 2057 run([java().javadoc, memory, '-classpath', cp, '-quiet', '-d', out, '-sourcepath', sp] + docletArgs + links + extraArgs + list(pkgs))
2007 log('Generated {2} for {0} in {1}'.format(', '.join(names), out, docDir)) 2058 log('Generated {2} for {0} in {1}'.format(', '.join(names), out, docDir))
2008 2059
2060 def findclass(args):
2061 """find all classes matching a given substring"""
2062
2063 for entry, filename in classpath_walk(includeBootClasspath=True):
2064 if filename.endswith('.class'):
2065 if isinstance(entry, zipfile.ZipFile):
2066 classname = filename.replace('/', '.')
2067 else:
2068 classname = filename.replace(os.sep, '.')
2069 classname = classname[:-len('.class')]
2070 for a in args:
2071 if a in classname:
2072 log(classname)
2073
2009 def javap(args): 2074 def javap(args):
2010 """launch javap with a -classpath option denoting all available classes 2075 """launch javap with a -classpath option denoting all available classes
2011 2076
2012 Run the JDK javap class file disassembler with the following prepended options: 2077 Run the JDK javap class file disassembler with the following prepended options:
2013 2078
2045 'build': [build, '[options]'], 2110 'build': [build, '[options]'],
2046 'checkstyle': [checkstyle, ''], 2111 'checkstyle': [checkstyle, ''],
2047 'canonicalizeprojects': [canonicalizeprojects, ''], 2112 'canonicalizeprojects': [canonicalizeprojects, ''],
2048 'clean': [clean, ''], 2113 'clean': [clean, ''],
2049 'eclipseinit': [eclipseinit, ''], 2114 'eclipseinit': [eclipseinit, ''],
2115 'findclass': [findclass, ''],
2050 'help': [help_, '[command]'], 2116 'help': [help_, '[command]'],
2051 'ideclean': [ideclean, ''], 2117 'ideclean': [ideclean, ''],
2052 'ideinit': [ideinit, ''], 2118 'ideinit': [ideinit, ''],
2053 'projectgraph': [projectgraph, ''], 2119 'projectgraph': [projectgraph, ''],
2054 'javap': [javap, ''], 2120 'javap': [javap, ''],