вторник, 12 марта 2013 г.

IDEA Ant script updater for Scala (Updated for 2.10) (Scons builder)


The way build yours IDEA project with Scala sources with command line tools:

- Generate <project-name>.xml Ant build script from IDE (Build -&gt; Generate Ant Build ...)
- Update this xml with given (under cut) scons builder
- Run Ant

Example:
 dataprocessor_ant_xml = env.IdeaAntUpdater(  
   target = 'DataProcessor/dataprocessor_with_main.xml',  
   source = 'DataProcessor/dataprocessor.xml',  
   jar2MainClass = {   
     'DataProcessor.jar' : 'com.kavanga.StreamProcessor',   
   },  
   scala = True,  
 )  
 dataprocessor_jar = env.SimpleAnt(  
   target = [   
     'DataProcessor/out/artifacts/DataProcessor_jar/DataProcessor.jar',  
   ],  
   source = [ dataprocessor_ant_xml, 'DataProcessor/dataprocessor.properties' ] + protobuf_nodes,  
   source_dirs = [ 'DataProcessor/src' ],  
 )  

import os
import re
import xml.etree.ElementTree as ET

def error(message):
    print message
    assert(False)

def simpleAntRunner(target, source, env):
    return os.system('ant -f %s'%(str(source[0])))

def javaSources(target, source, env):
    source_dirs = env.get('source_dirs', [])
    source_exts = env.get('source_exts', [ '.java', '.xml', '.scala' ])

    for src in source_dirs:
        for dirpath, dirnames, filenames in os.walk(src):
            source.extend([os.path.join(dirpath, jname) for jname in filenames if os.path.splitext(jname)[1].lower() in source_exts])

    return (target, source)

def setMainClass(jar, className):
    # find manifest
    manifest = jar.find('manifest')
    if manifest is None :
        # create if no
        manifest = ET.SubElement(jar, 'manifest')   
    # find main class attribute
    for attribute in manifest.findall('attribute'):
        if attribute.attrib.get('name', '') == Main-Class:
            return
    # set, if no
    ET.SubElement(manifest, 'attribute').attrib.update({
        'name'  : 'Main-Class',
        'value' : className
    })    

def setMainClasses(root, jar2MainClass):
    for jar in root.findall('.//jar'):
        for jarName,className in jar2MainClass.items():
            if jar.attrib.get('destfile', '').find(jarName) != -1:
                setMainClass(jar, className)
                break

def addScalac(root):
    #
    # find scala libs
    #
    scala_stuff_descr = {
        'scala-library'  : True,
        'scala-compiler' : True,
        'scala-reflect'  : False,
    }
    scala_stuff = {
    }

    
    for pathelem in root.findall('.//pathelement'):
        location = pathelem.attrib.get('location', '')
        for stuff in scala_stuff_descr.keys():
            if location.endswith(stuff + 'jar') or location.find(stuff) >= 0:
                scala_stuff[stuff] = location
            scala_library = location
    for stuff, required in scala_stuff_descr.items():
        if required and not scala_stuff.has_key(stuff):
            error('No scala required item founded %s' % stuff)

    #
    # insert scala init target
    #
    scala_init = ET.SubElement(root, 'target')
    scala_init.attrib['name'] = 'init_scalac'
    
    scala_task = ET.SubElement(scala_init, 'taskdef')
    scala_task.attrib['resource']='scala/tools/ant/antlib.xml'
    scapa_cp = ET.SubElement(scala_task, 'classpath')
    for stuff, location in scala_stuff.items():
        ET.SubElement(scapa_cp, 'pathelement').attrib['location'] = location

    #
    # insert scala bild targets
    #
    # Nodes with name='Singapore' that have a 'javac' child
    for target in root.findall('.//target'):
        javac = target.find('javac')
        if javac is None:
            continue
        target.attrib['depends'] =  'init_scalac' if not target.attrib.has_key('depends') else target.attrib['depends'] + ',init_scalac'
        scalac = ET.Element('scalac')
        target.insert(list(target).index(javac), scalac)
        scalac.insert(0, javac.find('classpath'))
        ET.SubElement(scalac, 'include').attrib['name'] = '**/*.scala'
        ET.SubElement(scalac, 'include').attrib['name'] = '**/*.java'
        scalac.attrib.update({
            'force'  : 'changed',
            'srcref' : javac.find('src').attrib['refid'],
            'destdir': javac.attrib['destdir']
        })


def ideaAntUpdater(target, source, env):
    tree = ET.parse(str(source[0]))
    root = tree.getroot()

    if env.get('jar2MainClass', None):
        setMainClasses(root, env['jar2MainClass'])
    if env.get('scala', False):
        addScalac(root)

    tree.write(str(target[0]))

    return 0

def ideaAntEmitter(target, source, env):
    env.Depends(target, env.Value(env.get('jar2MainClass', None)))
    env.Depends(target, env.Value(env.get('scala', False)))
    env.Depends(target, env.Value('Version: 1.0.2'))
    return (target, source)

class Builder(object):
    def __init__(self):
        pass

    def configure(self, env):
        env['BUILDERS']['SimpleAnt'] = env.Builder(
            action = simpleAntRunner,
            emitter = javaSources,
        )

        env['BUILDERS']['IdeaAntUpdater'] = env.Builder(
            action = ideaAntUpdater,
            emitter = ideaAntEmitter
        )

Комментариев нет:

Отправить комментарий