# HG changeset patch # User Doug Simon # Date 1333725887 -7200 # Node ID 887b45f6aa029411acc3e4e7a13c78a734688364 # Parent e91f0761c56d53d9cd041bba75879c7bc17abce7 improved name of Eclipse launch file created for jar applications converted IDE configuration generation to use XML class diff -r e91f0761c56d -r 887b45f6aa02 mxtool/mx.py --- a/mxtool/mx.py Fri Apr 06 14:26:33 2012 +0200 +++ b/mxtool/mx.py Fri Apr 06 17:24:47 2012 +0200 @@ -401,27 +401,32 @@ abort('cannot redefine library ' + l.name) _libs[l.name] = l + class XML(xml.dom.minidom.Document): def __init__(self): xml.dom.minidom.Document.__init__(self) self.current = self - - def open(self, tag, attributes={}): + self.padTextNodeWithoutSiblings = False + + def open(self, tag, attributes={}, data=None): element = self.createElement(tag) for key, value in attributes.items(): element.setAttribute(key, value) self.current.appendChild(element) self.current = element + if data is not None: + element.appendChild(self.createTextNode(data)) return self - def close(self): + def close(self, tag): assert self.current != self + assert tag == self.current.tagName, str(tag) + ' != ' + self.current.tagName self.current = self.current.parentNode return self - def element(self, tag, attributes={}): - return self.open(tag, attributes).close() + def element(self, tag, attributes={}, data=None): + return self.open(tag, attributes, data).close(tag) def xml(self, indent='', newl='', escape=False): assert self.current == self @@ -431,6 +436,35 @@ result = xml.sax.saxutils.escape(result, entities) return result + @staticmethod + def _Element_writexml(self, writer, indent="", addindent="", newl=""): + # Monkey patch: if the only child of an Element node is a Text node, then the + # text is printed without any indentation or new line padding + writer.write(indent+"<" + self.tagName) + + attrs = self._get_attributes() + a_names = attrs.keys() + a_names.sort() + + for a_name in a_names: + writer.write(" %s=\"" % a_name) + xml.dom.minidom._write_data(writer, attrs[a_name].value) + writer.write("\"") + if self.childNodes: + if not self.ownerDocument.padTextNodeWithoutSiblings and len(self.childNodes) == 1 and isinstance(self.childNodes[0], xml.dom.minidom.Text): + writer.write(">") + self.childNodes[0].writexml(writer) + writer.write("%s" % (self.tagName,newl)) + else: + writer.write(">%s"%(newl)) + for node in self.childNodes: + node.writexml(writer,indent+addindent,addindent,newl) + writer.write("%s%s" % (indent,self.tagName,newl)) + else: + writer.write("/>%s"%(newl)) + +xml.dom.minidom.Element.writexml = XML._Element_writexml + def get_os(): """ Get a canonical form of sys.platform. @@ -1404,15 +1438,60 @@ print '"' + p.name + '"->"' + dep + '"' print '}' -def make_eclipse_launch(args, jre, name=None, deps=[]): + +def _source_locator_memento(deps): + slm = XML() + slm.open('sourceLookupDirector') + slm.open('sourceContainers', {'duplicates' : 'false'}) + + for dep in deps: + if dep.isLibrary(): + if hasattr(dep, 'eclipse.container'): + memento = XML().element('classpathContainer', {'path' : getattr(dep, 'eclipse.container')}).xml() + slm.element('classpathContainer', {'memento' : memento, 'typeId':'org.eclipse.jdt.launching.sourceContainer.classpathContainer'}) + else: + memento = XML().element('javaProject', {'name' : dep.name}).xml() + slm.element('container', {'memento' : memento, 'typeId':'org.eclipse.jdt.launching.sourceContainer.javaProject'}) + + slm.close('sourceContainers') + slm.close('sourceLookupDirector') + return slm + +def make_eclipse_attach(hostname, port, name=None, deps=[]): + """ + Creates an Eclipse launch configuration file for attaching to a Java process. """ - Creates an Eclipse launch configuration file. + slm = _source_locator_memento(deps) + launch = XML() + launch.open('launchConfiguration', {'type' : 'org.eclipse.jdt.launching.remoteJavaApplication'}) + launch.element('stringAttribute', {'key' : 'org.eclipse.debug.core.source_locator_id', 'value' : 'org.eclipse.jdt.launching.sourceLocator.JavaSourceLookupDirector'}) + launch.element('stringAttribute', {'key' : 'org.eclipse.debug.core.source_locator_memento', 'value' : '%s'}) + launch.element('booleanAttribute', {'key' : 'org.eclipse.jdt.launching.ALLOW_TERMINATE', 'value' : 'true'}) + launch.open('mapAttribute', {'key' : 'org.eclipse.jdt.launching.CONNECT_MAP'}) + launch.element('mapEntry', {'key' : 'hostname', 'value' : hostname}) + launch.element('mapEntry', {'key' : 'port', 'value' : port}) + launch.close('mapAttribute') + launch.element('stringAttribute', {'key' : 'org.eclipse.jdt.launching.PROJECT_ATTR', 'value' : ''}) + launch.element('stringAttribute', {'key' : 'org.eclipse.jdt.launching.VM_CONNECTOR_ID', 'value' : 'org.eclipse.jdt.launching.socketAttachConnector'}) + launch.close('launchConfiguration') + launch = launch.xml(newl='\n') % slm.xml(escape=True) + + if name is None: + name = 'attach-' + hostname + '-' + port + eclipseLaunches = join('mx', 'eclipse-launches') + if not exists(eclipseLaunches): + os.makedirs(eclipseLaunches) + return update_file(join(eclipseLaunches, name + '.launch'), launch) + +def make_eclipse_launch(javaArgs, jre, name=None, deps=[]): + """ + Creates an Eclipse launch configuration file for running/debugging a Java command. """ mainClass = None vmArgs = [] appArgs = [] cp = None - argsCopy = list(reversed(args)) + argsCopy = list(reversed(javaArgs)) while len(argsCopy) != 0: a = argsCopy.pop() if a == '-jar': @@ -1432,37 +1511,26 @@ break if mainClass is None: - log('Cannot create Eclipse launch configuration without main class') + log('Cannot create Eclipse launch configuration without main class or jar file: java ' + ' '.join(javaArgs)) return False if name is None: if mainClass == '-jar': name = basename(appArgs[0]) + if len(appArgs) > 1 and not appArgs[1].startswith('-'): + name = name + '_' + appArgs[1] else: name = mainClass name = time.strftime('%Y-%m-%d-%H%M%S_' + name) - slm = XML() - slm.open('sourceLookupDirector') - slm.open('sourceContainers', {'duplicates' : 'false'}) - if cp is not None: for e in cp.split(os.pathsep): for s in suites(): deps += [p for p in s.projects if e == p.output_dir()] deps += [l for l in s.libs if e == l.get_path(False)] - for dep in deps: - if dep.isLibrary(): - if hasattr(dep, 'eclipse.container'): - memento = XML().element('classpathContainer', {'path' : getattr(dep, 'eclipse.container')}).xml() - slm.element('classpathContainer', {'memento' : memento, 'typeId':'org.eclipse.jdt.launching.sourceContainer.classpathContainer'}) - else: - memento = XML().element('javaProject', {'name' : dep.name}).xml() - slm.element('container', {'memento' : memento, 'typeId':'org.eclipse.jdt.launching.sourceContainer.javaProject'}) - - slm.close() - slm.close() + slm = _source_locator_memento(deps) + launch = XML() launch.open('launchConfiguration', {'type' : 'org.eclipse.jdt.launching.localJavaApplication'}) launch.element('stringAttribute', {'key' : 'org.eclipse.debug.core.source_locator_id', 'value' : 'org.eclipse.jdt.launching.sourceLocator.JavaSourceLookupDirector'}) @@ -1472,7 +1540,7 @@ launch.element('stringAttribute', {'key' : 'org.eclipse.jdt.launching.PROGRAM_ARGUMENTS', 'value' : ' '.join(appArgs)}) launch.element('stringAttribute', {'key' : 'org.eclipse.jdt.launching.PROJECT_ATTR', 'value' : ''}) launch.element('stringAttribute', {'key' : 'org.eclipse.jdt.launching.VM_ARGUMENTS', 'value' : ' '.join(vmArgs)}) - launch.close() + launch.close('launchConfiguration') launch = launch.xml(newl='\n') % slm.xml(escape=True) eclipseLaunches = join('mx', 'eclipse-launches') @@ -1486,14 +1554,6 @@ if suite is None: suite = _mainSuite - def println(out, obj): - out.write(str(obj) + '\n') - - source_locator_memento = '\n' - entities = { '"': """, "'": "'", '\n': ' ' } - - sml = XML() - for p in projects(): if p.native: continue @@ -1501,18 +1561,17 @@ if not exists(p.dir): os.makedirs(p.dir) - out = StringIO.StringIO() - - println(out, '') - println(out, '') + out = XML() + out.open('classpath') + for src in p.srcDirs: srcDir = join(p.dir, src) if not exists(srcDir): os.mkdir(srcDir) - println(out, '\t') + out.element('classpathentry', {'kind' : 'src', 'path' : src}) # Every Java program depends on the JRE - println(out, '\t') + out.element('classpathentry', {'kind' : 'con', 'path' : 'org.eclipse.jdt.launching.JRE_CONTAINER'}) for dep in p.all_deps([], True): if dep == p: @@ -1520,92 +1579,82 @@ if dep.isLibrary(): if hasattr(dep, 'eclipse.container'): - println(out, '\t') + out.element('classpathentry', {'exported' : 'true', 'kind' : 'con', 'path' : getattr(dep, 'eclipse.container')}) elif hasattr(dep, 'eclipse.project'): - println(out, '\t') + out.element('classpathentry', {'combineaccessrules' : 'false', 'exported' : 'true', 'kind' : 'src', 'path' : '/' + getattr(dep, 'eclipse.project')}) else: path = dep.path if dep.mustExist: dep.get_path(resolve=True) if isabs(path): - println(out, '\t') + out.element('classpathentry', {'exported' : 'true', 'kind' : 'lib', 'path' : path}) else: # Relative paths for "lib" class path entries have various semantics depending on the Eclipse # version being used (e.g. see https://bugs.eclipse.org/bugs/show_bug.cgi?id=274737) so it's # safest to simply use absolute paths. - println(out, '\t') + out.element('classpathentry', {'exported' : 'true', 'kind' : 'lib', 'path' : join(suite.dir, path)}) else: - println(out, '\t') + out.element('classpathentry', {'combineaccessrules' : 'false', 'exported' : 'true', 'kind' : 'src', 'path' : '/' + dep.name}) - println(out, '\t') - println(out, '') - update_file(join(p.dir, '.classpath'), out.getvalue()) - out.close() + out.element('classpathentry', {'kind' : 'output', 'path' : getattr(p, 'eclipse.output', 'bin')}) + out.close('classpath') + update_file(join(p.dir, '.classpath'), out.xml(indent='\t', newl='\n')) csConfig = join(project(p.checkstyleProj).dir, '.checkstyle_checks.xml') if exists(csConfig): - out = StringIO.StringIO() + out = XML() dotCheckstyle = join(p.dir, ".checkstyle") checkstyleConfigPath = '/' + p.checkstyleProj + '/.checkstyle_checks.xml' - println(out, '') - println(out, '') - println(out, '\t') - println(out, '\t\t') - println(out, '\t') - println(out, '\t') - println(out, '\t\t') - println(out, '\t') - println(out, '\t') - println(out, '\t\t') - println(out, '\t') + out.open('fileset-config', {'file-format-version' : '1.2.0', 'simple-config' : 'true'}) + out.open('local-check-config', {'name' : 'Checks', 'location' : checkstyleConfigPath, 'type' : 'project', 'description' : ''}) + out.element('additional-data', {'name' : 'protect-config-file', 'value' : 'false'}) + out.close('local-check-config') + out.open('fileset', {'name' : 'all', 'enabled' : 'true', 'check-config-name' : 'Checks', 'local' : 'true'}) + out.element('file-match-pattern', {'match-pattern' : '.', 'include-pattern' : 'true'}) + out.close('fileset') + out.open('filter', {'name' : 'all', 'enabled' : 'true', 'check-config-name' : 'Checks', 'local' : 'true'}) + out.element('filter-data', {'value' : 'java'}) + out.close('filter') exclude = join(p.dir, '.checkstyle.exclude') if exists(exclude): - println(out, '\t') + out.open('filter', {'name' : 'FilesFromPackage', 'enabled' : 'true'}) with open(exclude) as f: for line in f: if not line.startswith('#'): line = line.strip() exclDir = join(p.dir, line) assert isdir(exclDir), 'excluded source directory listed in ' + exclude + ' does not exist or is not a directory: ' + exclDir - println(out, '\t\t') - println(out, '\t') + out.element('filter-data', {'value' : line}) + out.close('filter') - println(out, '') - update_file(dotCheckstyle, out.getvalue()) - out.close() - - - out = StringIO.StringIO() + out.close('fileset-config') + update_file(dotCheckstyle, out.xml(indent='\t', newl='\n')) - println(out, '') - println(out, '') - println(out, '\t' + p.name + '') - println(out, '\t') - println(out, '\t') - println(out, '\t') - println(out, '\t') - println(out, '\t\t') - println(out, '\t\t\torg.eclipse.jdt.core.javabuilder') - println(out, '\t\t\t') - println(out, '\t\t\t') - println(out, '\t\t') + out = XML() + out.open('projectDescription') + out.element('name', data=p.name) + out.element('comment', data='') + out.element('projects', data='') + out.open('buildSpec') + out.open('buildCommand') + out.element('name', data='org.eclipse.jdt.core.javabuilder') + out.element('arguments', data='') + out.close('buildCommand') if exists(csConfig): - println(out, '\t\t') - println(out, '\t\t\tnet.sf.eclipsecs.core.CheckstyleBuilder') - println(out, '\t\t\t') - println(out, '\t\t\t') - println(out, '\t\t') - println(out, '\t') - println(out, '\t') - println(out, '\t\torg.eclipse.jdt.core.javanature') + out.open('buildCommand') + out.element('name', data='net.sf.eclipsecs.core.CheckstyleBuilder') + out.element('arguments', data='') + out.close('buildCommand') + out.close('buildSpec') + out.open('natures') + out.element('nature', data='org.eclipse.jdt.core.javanature') if exists(csConfig): - println(out, '\t\tnet.sf.eclipsecs.core.CheckstyleNature') - println(out, '\t') - println(out, '') - update_file(join(p.dir, '.project'), out.getvalue()) - out.close() + out.element('nature', data='net.sf.eclipsecs.core.CheckstyleNature') + out.close('natures') + out.close('projectDescription') + update_file(join(p.dir, '.project'), out.xml(indent='\t', newl='\n')) settingsDir = join(p.dir, ".settings") if not exists(settingsDir): @@ -1620,28 +1669,8 @@ content = f.read() content = content.replace('${javaCompliance}', str(p.javaCompliance)) update_file(join(settingsDir, name), content) - - memento = '\n\n' - source_locator_memento += '\n' - - source_locator_memento += '\n' - launch = r""" - - - - - - - - - - -""".format(xml.sax.saxutils.escape(source_locator_memento, entities)) - eclipseLaunches = join(suite.dir, 'mx', 'eclipse-launches') - if not exists(eclipseLaunches): - os.makedirs(eclipseLaunches) - update_file(join(eclipseLaunches, 'attach-8000.launch'), launch) + make_eclipse_attach('localhost', '8000', deps=projects()) def netbeansinit(args, suite=None): """(re)generate NetBeans project configurations""" @@ -1649,9 +1678,6 @@ if suite is None: suite = _mainSuite - def println(out, obj): - out.write(str(obj) + '\n') - updated = False for p in projects(): if p.native: @@ -1660,32 +1686,28 @@ if not exists(join(p.dir, 'nbproject')): os.makedirs(join(p.dir, 'nbproject')) - out = StringIO.StringIO() - - println(out, '') - println(out, '') - println(out, '\tBuilds, tests, and runs the project ' + p.name + '.') - println(out, '\t') - println(out, '') - updated = update_file(join(p.dir, 'build.xml'), out.getvalue()) or updated - out.close() + out = XML() + out.open('project', {'name' : p.name, 'default' : 'default', 'basedir' : '.'}) + out.element('description', data='Builds, tests, and runs the project ' + p.name + '.') + out.element('import', {'file' : 'nbproject/build-impl.xml'}) + out.close('project') + updated = update_file(join(p.dir, 'build.xml'), out.xml(indent='\t', newl='\n')) or updated - out = StringIO.StringIO() - println(out, '') - println(out, '') - println(out, ' org.netbeans.modules.java.j2seproject') - println(out, ' ') - println(out, ' ') - println(out, ' ' + p.name+ '') - println(out, ' ') - println(out, ' ') - println(out, ' ') - println(out, ' ') - println(out, ' ') - println(out, ' ') - println(out, ' ') - println(out, ' ') - + out = XML() + out.open('project', {'xmlns' : 'http://www.netbeans.org/ns/project/1'}) + out.element('type', data='org.netbeans.modules.java.j2seproject') + out.open('configuration') + out.open('data', {'xmlns' : 'http://www.netbeans.org/ns/j2se-project/3'}) + out.element('name', data=p.name) + out.element('explicit-platform', {'explicit-source-supported' : 'true'}) + out.open('source-roots') + out.element('root', {'id' : 'src.dir'}) + out.close('source-roots') + out.open('test-roots') + out.element('root', {'id' : 'test.src.dir'}) + out.close('test-roots') + out.close('data') + firstDep = True for dep in p.all_deps([], True): if dep == p: @@ -1694,28 +1716,26 @@ if not dep.isLibrary(): n = dep.name.replace('.', '_') if firstDep: - println(out, ' ') + out.open('references', {'xmlns' : 'http://www.netbeans.org/ns/ant-project-references/1'}) firstDep = False - println(out, ' ') - println(out, ' ' + n + '') - println(out, ' jar') - println(out, ' ') - println(out, ' jar') - println(out, ' clean') - println(out, ' jar') - println(out, ' ') + out.open('reference') + out.element('foreign-project', data=n) + out.element('artifact-type', data='jar') + out.element('script', data='build.xml') + out.element('target', data='jar') + out.element('clean-target', data='clean') + out.element('id', data='jar') + out.close('reference') if not firstDep: - println(out, ' ') + out.close('references') - println(out, ' ') - println(out, '') - updated = update_file(join(p.dir, 'nbproject', 'project.xml'), out.getvalue()) or updated - out.close() + out.close('configuration') + out.close('project') + updated = update_file(join(p.dir, 'nbproject', 'project.xml'), out.xml(indent=' ', newl='\n')) or updated out = StringIO.StringIO() - jdkPlatform = 'JDK_' + java().version content = """ @@ -1791,7 +1811,7 @@ ${build.test.classes.dir} test.src.dir= source.encoding=UTF-8""".replace(':', os.pathsep).replace('/', os.sep) - println(out, content) + print >> out, content mainSrc = True for src in p.srcDirs: @@ -1799,12 +1819,12 @@ if not exists(srcDir): os.mkdir(srcDir) ref = 'file.reference.' + p.name + '-' + src - println(out, ref + '=' + src) + print >> out, ref + '=' + src if mainSrc: - println(out, 'src.dir=${' + ref + '}') + print >> out, 'src.dir=${' + ref + '}' mainSrc = False else: - println(out, 'src.' + src + '.dir=${' + ref + '}') + print >> out, 'src.' + src + '.dir=${' + ref + '}' javacClasspath = [] for dep in p.all_deps([], True): @@ -1818,18 +1838,18 @@ if os.sep == '\\': path = path.replace('\\', '\\\\') ref = 'file.reference.' + dep.name + '-bin' - println(out, ref + '=' + path) + print >> out, ref + '=' + path else: n = dep.name.replace('.', '_') relDepPath = os.path.relpath(dep.dir, p.dir).replace(os.sep, '/') ref = 'reference.' + n + '.jar' - println(out, 'project.' + n + '=' + relDepPath) - println(out, ref + '=${project.' + n + '}/dist/' + dep.name + '.jar') + print >> out, 'project.' + n + '=' + relDepPath + print >> out, ref + '=${project.' + n + '}/dist/' + dep.name + '.jar' javacClasspath.append('${' + ref + '}') - println(out, 'javac.classpath=\\\n ' + (os.pathsep + '\\\n ').join(javacClasspath)) + print >> out, 'javac.classpath=\\\n ' + (os.pathsep + '\\\n ').join(javacClasspath) updated = update_file(join(p.dir, 'nbproject', 'project.properties'), out.getvalue()) or updated