comparison mxtool/mx.py @ 8131:83ec1df0a30f

added support for distributions to mx added GRAAL distribution to create graal.jar in top level directory
author Doug Simon <doug.simon@oracle.com>
date Wed, 06 Mar 2013 16:59:10 +0100
parents c7d7d9936809
children 6e3ebc6fd5a4
comparison
equal deleted inserted replaced
8126:22bbd34705ed 8131:83ec1df0a30f
141 141
142 DEFAULT_JAVA_ARGS = '-ea -Xss2m -Xmx1g' 142 DEFAULT_JAVA_ARGS = '-ea -Xss2m -Xmx1g'
143 143
144 _projects = dict() 144 _projects = dict()
145 _libs = dict() 145 _libs = dict()
146 _dists = dict()
146 _suites = dict() 147 _suites = dict()
147 _mainSuite = None 148 _mainSuite = None
148 _opts = None 149 _opts = None
149 _java = None 150 _java = None
150 151
152 """
153 A distribution is a jar or zip file containing the output from one or more Java projects.
154 """
155 class Distribution:
156 def __init__(self, suite, name, path, deps):
157 self.suite = suite
158 self.name = name
159 self.path = path.replace('/', os.sep)
160 if not isabs(self.path):
161 self.path = join(suite.dir, self.path)
162 self.deps = deps
163
164 def __str__(self):
165 return self.name
166
151 """ 167 """
152 A dependency is a library or project specified in a suite. 168 A dependency is a library or project specified in a suite.
153 """ 169 """
154 class Dependency: 170 class Dependency:
155 def __init__(self, suite, name): 171 def __init__(self, suite, name):
414 class Suite: 430 class Suite:
415 def __init__(self, d, primary): 431 def __init__(self, d, primary):
416 self.dir = d 432 self.dir = d
417 self.projects = [] 433 self.projects = []
418 self.libs = [] 434 self.libs = []
435 self.dists = []
419 self.includes = [] 436 self.includes = []
420 self.commands = None 437 self.commands = None
421 self.primary = primary 438 self.primary = primary
422 mxDir = join(d, 'mx') 439 mxDir = join(d, 'mx')
423 self._load_env(mxDir) 440 self._load_env(mxDir)
425 self._load_includes(mxDir) 442 self._load_includes(mxDir)
426 443
427 def _load_projects(self, mxDir): 444 def _load_projects(self, mxDir):
428 libsMap = dict() 445 libsMap = dict()
429 projsMap = dict() 446 projsMap = dict()
447 distsMap = dict()
430 projectsFile = join(mxDir, 'projects') 448 projectsFile = join(mxDir, 'projects')
431 if not exists(projectsFile): 449 if not exists(projectsFile):
432 return 450 return
433 with open(projectsFile) as f: 451 with open(projectsFile) as f:
434 for line in f: 452 for line in f:
445 kind, name, attr = parts 463 kind, name, attr = parts
446 if kind == 'project': 464 if kind == 'project':
447 m = projsMap 465 m = projsMap
448 elif kind == 'library': 466 elif kind == 'library':
449 m = libsMap 467 m = libsMap
468 elif kind == 'distribution':
469 m = distsMap
450 else: 470 else:
451 abort('Property name does not start with "project@" or "library@": ' + key) 471 abort('Property name does not start with "project@", "library@" or "distribution@": ' + key)
452 472
453 attrs = m.get(name) 473 attrs = m.get(name)
454 if attrs is None: 474 if attrs is None:
455 attrs = dict() 475 attrs = dict()
456 m[name] = attrs 476 m[name] = attrs
492 sourceUrls = pop_list(attrs, 'sourceUrls') 512 sourceUrls = pop_list(attrs, 'sourceUrls')
493 l = Library(self, name, path, mustExist, urls, sourcePath, sourceUrls) 513 l = Library(self, name, path, mustExist, urls, sourcePath, sourceUrls)
494 l.__dict__.update(attrs) 514 l.__dict__.update(attrs)
495 self.libs.append(l) 515 self.libs.append(l)
496 516
517 for name, attrs in distsMap.iteritems():
518 path = attrs.pop('path')
519 deps = pop_list(attrs, 'dependencies')
520 d = Distribution(self, name, path, deps)
521 d.__dict__.update(attrs)
522 self.dists.append(d)
523
497 def _load_commands(self, mxDir): 524 def _load_commands(self, mxDir):
498 commands = join(mxDir, 'commands.py') 525 commands = join(mxDir, 'commands.py')
499 if exists(commands): 526 if exists(commands):
500 # temporarily extend the Python path 527 # temporarily extend the Python path
501 sys.path.insert(0, mxDir) 528 sys.path.insert(0, mxDir)
547 for l in self.libs: 574 for l in self.libs:
548 existing = _libs.get(l.name) 575 existing = _libs.get(l.name)
549 if existing is not None: 576 if existing is not None:
550 abort('cannot redefine library ' + l.name) 577 abort('cannot redefine library ' + l.name)
551 _libs[l.name] = l 578 _libs[l.name] = l
579 for d in self.dists:
580 existing = _dists.get(l.name)
581 if existing is not None:
582 abort('cannot redefine distribution ' + d.name)
583 _dists[d.name] = d
552 584
553 class XMLElement(xml.dom.minidom.Element): 585 class XMLElement(xml.dom.minidom.Element):
554 def writexml(self, writer, indent="", addindent="", newl=""): 586 def writexml(self, writer, indent="", addindent="", newl=""):
555 writer.write(indent+"<" + self.tagName) 587 writer.write(indent+"<" + self.tagName)
556 588
650 def projects(): 682 def projects():
651 """ 683 """
652 Get the list of all loaded projects. 684 Get the list of all loaded projects.
653 """ 685 """
654 return _projects.values() 686 return _projects.values()
687
688 def distribution(name, fatalIfMissing=True):
689 """
690 Get the distribution for a given name. This will abort if the named distribution does
691 not exist and 'fatalIfMissing' is true.
692 """
693 d = _dists.get(name)
694 if d is None and fatalIfMissing:
695 abort('distribution named ' + name + ' not found')
696 return d
655 697
656 def project(name, fatalIfMissing=True): 698 def project(name, fatalIfMissing=True):
657 """ 699 """
658 Get the project for a given name. This will abort if the named project does 700 Get the project for a given name. This will abort if the named project does
659 not exist and 'fatalIfMissing' is true. 701 not exist and 'fatalIfMissing' is true.
1475 jdtArgs.append('@' + argfile.name) 1517 jdtArgs.append('@' + argfile.name)
1476 run(jdtArgs) 1518 run(jdtArgs)
1477 finally: 1519 finally:
1478 for n in toBeDeleted: 1520 for n in toBeDeleted:
1479 os.remove(n) 1521 os.remove(n)
1522
1523 for dist in _dists.values():
1524 archive(['@' + dist.name])
1480 1525
1481 if suppliedParser: 1526 if suppliedParser:
1482 return args 1527 return args
1483 return None 1528 return None
1484 1529
1576 1621
1577 def processorjars(): 1622 def processorjars():
1578 projects = set() 1623 projects = set()
1579 1624
1580 for p in sorted_deps(): 1625 for p in sorted_deps():
1581 if _needsEclipseJarBuild(p): 1626 if _isAnnotationProcessorDependency(p):
1582 projects.add(p) 1627 projects.add(p)
1583 1628
1584 if len(projects) <= 0: 1629 if len(projects) <= 0:
1585 return 1630 return
1586 1631
1587 pnames = [p.name for p in projects] 1632 pnames = [p.name for p in projects]
1588 build(['--projects', ",".join(pnames)]) 1633 build(['--projects', ",".join(pnames)])
1589 jarprojects(pnames) 1634 archive(pnames)
1590 1635
1591 def jarprojects(args): 1636 def archive(args):
1592 """create jar files for the output of one or more projects""" 1637 """create jar files for projects and distributions"""
1593 parser = ArgumentParser(prog='mx jar'); 1638 parser = ArgumentParser(prog='mx archive');
1594 parser.add_argument('-d', '--dest', help='single jar file to create') 1639 parser.add_argument('names', nargs=REMAINDER, metavar='[<project>|@<distribution>]...')
1595 parser.add_argument('projects', nargs=REMAINDER, metavar='projects...')
1596 args = parser.parse_args(args) 1640 args = parser.parse_args(args)
1597 1641
1598 if not args.projects: 1642 for name in args.names:
1599 args.projects = [p.name for p in projects()] 1643 if name.startswith('@'):
1600 1644 dname = name[1:]
1601 if args.dest is not None: 1645 d = distribution(dname)
1602 zf = zipfile.ZipFile(args.dest, 'w') 1646 zf = zipfile.ZipFile(d.path, 'w')
1603 1647 for p in sorted_deps(d.deps):
1604 for pname in args.projects: 1648 outputDir = p.output_dir()
1605 p = project(pname, fatalIfMissing=True) 1649 for root, _, files in os.walk(outputDir):
1606 if args.dest is None: 1650 for f in files:
1651 relpath = root[len(outputDir) + 1:]
1652 arcname = join(relpath, f).replace(os.sep, '/')
1653 zf.write(join(root, f), arcname)
1654 zf.close()
1655 else:
1656 p = project(name)
1657 outputDir = p.output_dir()
1607 jar = join(p.dir, p.name + '.jar') 1658 jar = join(p.dir, p.name + '.jar')
1608 zf = zipfile.ZipFile(jar, 'w') 1659 zf = zipfile.ZipFile(jar, 'w')
1609 outputDir = p.output_dir() 1660 for root, _, files in os.walk(outputDir):
1610 for root, _, files in os.walk(outputDir): 1661 for f in files:
1611 for f in files: 1662 relpath = root[len(outputDir) + 1:]
1612 relpath = root[len(outputDir) + 1:] 1663 arcname = join(relpath, f).replace(os.sep, '/')
1613 arcname = join(relpath, f).replace(os.sep, '/') 1664 zf.write(join(root, f), arcname)
1614 zf.write(join(root, f), arcname)
1615 if args.dest is None:
1616 zf.close() 1665 zf.close()
1617
1618 if args.dest is not None:
1619 zf.close()
1620 1666
1621 def canonicalizeprojects(args): 1667 def canonicalizeprojects(args):
1622 """process all project files to canonicalize the dependencies 1668 """process all project files to canonicalize the dependencies
1623 1669
1624 The exit code of this command reflects how many files were updated.""" 1670 The exit code of this command reflects how many files were updated."""
1994 suite = _mainSuite 2040 suite = _mainSuite
1995 2041
1996 if buildProcessorJars: 2042 if buildProcessorJars:
1997 processorjars() 2043 processorjars()
1998 2044
2045 projToDist = dict()
2046 for dist in _dists.values():
2047 distDeps = sorted_deps(dist.deps)
2048 for p in distDeps:
2049 projToDist[p.name] = (dist, [dep.name for dep in distDeps])
2050
1999 for p in projects(): 2051 for p in projects():
2000 if p.native: 2052 if p.native:
2001 continue 2053 continue
2002 2054
2003 if not exists(p.dir): 2055 if not exists(p.dir):
2108 out.open('buildCommand') 2160 out.open('buildCommand')
2109 out.element('name', data=buildCommand) 2161 out.element('name', data=buildCommand)
2110 out.element('arguments', data='') 2162 out.element('arguments', data='')
2111 out.close('buildCommand') 2163 out.close('buildCommand')
2112 2164
2113 if (_needsEclipseJarBuild(p)): 2165 if _isAnnotationProcessorDependency(p):
2114 targetValues = _genEclipseJarBuild(p); 2166 _genEclipseBuilder(out, p, 'Jar.launch', 'archive ' + p.name, refresh = False, async = False)
2115 for value in targetValues: 2167 _genEclipseBuilder(out, p, 'Refresh.launch', '', refresh = True, async = True)
2116 out.open('buildCommand') 2168
2117 out.element('name', data='org.eclipse.ui.externaltools.ExternalToolBuilder') 2169 if projToDist.has_key(p.name):
2118 out.element('triggers', data='auto,full,incremental,') 2170 dist, distDeps = projToDist[p.name]
2119 out.open('arguments') 2171 _genEclipseBuilder(out, p, 'Create' + dist.name + 'Dist.launch', 'archive @' + dist.name, refresh=False, async=True)
2120 out.open('dictionary') 2172
2121 out.element('key', data = 'LaunchConfigHandle')
2122 out.element('value', data = value)
2123 out.close('dictionary')
2124 out.open('dictionary')
2125 out.element('key', data = 'incclean')
2126 out.element('value', data = 'true')
2127 out.close('dictionary')
2128 out.close('arguments')
2129 out.close('buildCommand')
2130
2131 out.close('buildSpec') 2173 out.close('buildSpec')
2132 out.open('natures') 2174 out.open('natures')
2133 out.element('nature', data='org.eclipse.jdt.core.javanature') 2175 out.element('nature', data='org.eclipse.jdt.core.javanature')
2134 if exists(csConfig): 2176 if exists(csConfig):
2135 out.element('nature', data='net.sf.eclipsecs.core.CheckstyleNature') 2177 out.element('nature', data='net.sf.eclipsecs.core.CheckstyleNature')
2180 update_file(join(p.dir, '.factorypath'), out.xml(indent='\t', newl='\n')) 2222 update_file(join(p.dir, '.factorypath'), out.xml(indent='\t', newl='\n'))
2181 2223
2182 make_eclipse_attach('localhost', '8000', deps=projects()) 2224 make_eclipse_attach('localhost', '8000', deps=projects())
2183 2225
2184 2226
2185 def _needsEclipseJarBuild(p): 2227 def _isAnnotationProcessorDependency(p):
2186 processors = set([]) 2228 """
2229 Determines if a given project is part of an annotation processor.
2230 """
2231 processors = set()
2187 2232
2188 for otherProject in projects(): 2233 for otherProject in projects():
2189 if hasattr(otherProject, 'annotationProcessors') and len(otherProject.annotationProcessors) > 0: 2234 if hasattr(otherProject, 'annotationProcessors') and len(otherProject.annotationProcessors) > 0:
2190 for processorName in otherProject.annotationProcessors: 2235 for processorName in otherProject.annotationProcessors:
2191 processors.add(project(processorName, fatalIfMissing=True)) 2236 processors.add(project(processorName, fatalIfMissing=True))
2198 if p in deps: 2243 if p in deps:
2199 return True 2244 return True
2200 2245
2201 return False 2246 return False
2202 2247
2203 def _genEclipseJarBuild(p): 2248 def _genEclipseBuilder(dotProjectDoc, p, name, mxCommand, refresh=True, async=False):
2204 builders = []
2205 builders.append(_genEclipseLaunch(p, 'Jar.launch', ''.join(['jarprojects ', p.name]), refresh = False, async = False))
2206 builders.append(_genEclipseLaunch(p, 'Refresh.launch', '', refresh = True, async = True))
2207 return builders
2208
2209 def _genEclipseLaunch(p, name, mxCommand, refresh=True, async=False):
2210 launchOut = XMLDoc(); 2249 launchOut = XMLDoc();
2211 launchOut.open('launchConfiguration', {'type' : 'org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType'}) 2250 launchOut.open('launchConfiguration', {'type' : 'org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType'})
2212 if refresh: 2251 if refresh:
2213 launchOut.element('stringAttribute', {'key' : 'org.eclipse.debug.core.ATTR_REFRESH_SCOPE', 'value': '${project}'}) 2252 launchOut.element('stringAttribute', {'key' : 'org.eclipse.debug.core.ATTR_REFRESH_SCOPE', 'value': '${project}'})
2214 launchOut.element('booleanAttribute', {'key' : 'org.eclipse.debug.core.capture_output', 'value': 'false'}) 2253 launchOut.element('booleanAttribute', {'key' : 'org.eclipse.debug.core.capture_output', 'value': 'false'})
2234 2273
2235 if not exists(externalToolDir): 2274 if not exists(externalToolDir):
2236 os.makedirs(externalToolDir) 2275 os.makedirs(externalToolDir)
2237 update_file(join(externalToolDir, name), launchOut.xml(indent='\t', newl='\n')) 2276 update_file(join(externalToolDir, name), launchOut.xml(indent='\t', newl='\n'))
2238 2277
2239 return ''.join(["<project>/.externalToolBuilders/", name]) 2278 dotProjectDoc.open('buildCommand')
2240 2279 dotProjectDoc.element('name', data='org.eclipse.ui.externaltools.ExternalToolBuilder')
2241 2280 dotProjectDoc.element('triggers', data='auto,full,incremental,')
2281 dotProjectDoc.open('arguments')
2282 dotProjectDoc.open('dictionary')
2283 dotProjectDoc.element('key', data = 'LaunchConfigHandle')
2284 dotProjectDoc.element('value', data = '<project>/.externalToolBuilders/' + name)
2285 dotProjectDoc.close('dictionary')
2286 dotProjectDoc.open('dictionary')
2287 dotProjectDoc.element('key', data = 'incclean')
2288 dotProjectDoc.element('value', data = 'true')
2289 dotProjectDoc.close('dictionary')
2290 dotProjectDoc.close('arguments')
2291 dotProjectDoc.close('buildCommand')
2292
2242 def netbeansinit(args, suite=None): 2293 def netbeansinit(args, suite=None):
2243 """(re)generate NetBeans project configurations""" 2294 """(re)generate NetBeans project configurations"""
2244 2295
2245 if suite is None: 2296 if suite is None:
2246 suite = _mainSuite 2297 suite = _mainSuite
2954 'findclass': [findclass, ''], 3005 'findclass': [findclass, ''],
2955 'fsckprojects': [fsckprojects, ''], 3006 'fsckprojects': [fsckprojects, ''],
2956 'help': [help_, '[command]'], 3007 'help': [help_, '[command]'],
2957 'ideclean': [ideclean, ''], 3008 'ideclean': [ideclean, ''],
2958 'ideinit': [ideinit, ''], 3009 'ideinit': [ideinit, ''],
2959 'jarprojects': [jarprojects, '[options]'], 3010 'archive': [archive, '[options]'],
2960 'projectgraph': [projectgraph, ''], 3011 'projectgraph': [projectgraph, ''],
2961 'javap': [javap, ''], 3012 'javap': [javap, ''],
2962 'javadoc': [javadoc, '[options]'], 3013 'javadoc': [javadoc, '[options]'],
2963 'site': [site, '[options]'], 3014 'site': [site, '[options]'],
2964 'netbeansinit': [netbeansinit, ''], 3015 'netbeansinit': [netbeansinit, ''],