assorted changes

This commit is contained in:
Maxim Shafirov
2009-09-01 21:20:53 +04:00
parent 83aa20d5e0
commit bd319c6eb3
17 changed files with 775 additions and 53 deletions
+1
View File
@@ -6,6 +6,7 @@
<w>Groovyc</w>
<w>Instrumentations</w>
<w>Javac</w>
<w>Runtime</w>
<w>args</w>
<w>chunkey</w>
<w>depdends</w>
-1
View File
@@ -52,7 +52,6 @@
<component name="ProjectDetails">
<option name="projectName" value="jps" />
</component>
<component name="ProjectFileVersion" converted="true" />
<component name="ProjectKey">
<option name="state" value="project://default" />
</component>
+1
View File
@@ -5,6 +5,7 @@
<module fileurl="file://$PROJECT_DIR$/samples/A/A.iml" filepath="$PROJECT_DIR$/samples/A/A.iml" />
<module fileurl="file://$PROJECT_DIR$/samples/B/B.iml" filepath="$PROJECT_DIR$/samples/B/B.iml" />
<module fileurl="file://$PROJECT_DIR$/antlayout/antlayout.iml" filepath="$PROJECT_DIR$/antlayout/antlayout.iml" />
<module fileurl="file://$PROJECT_DIR$/gantLauncher/gantLauncher.iml" filepath="$PROJECT_DIR$/gantLauncher/gantLauncher.iml" />
<module fileurl="file://$PROJECT_DIR$/jps.iml" filepath="$PROJECT_DIR$/jps.iml" />
</modules>
</component>
+1
View File
@@ -16,6 +16,7 @@ public class JarContainer extends ZipContainer {
protected Zip createTask() {
Jar task = new Jar();
task.setTaskName("jar");
task.setWhenmanifestonly((Zip.WhenEmpty) Zip.WhenEmpty.getInstance(Zip.WhenEmpty.class, "skip"));
return task;
}
+1 -1
View File
@@ -18,7 +18,7 @@ public class ZipContainer extends Container {
public ZipContainer() {
task = createTask();
task.setCompress(true); // Default compress is false
task.setCompress(false); // Default compress is false
}
public String getName() {
+22 -1
View File
@@ -5,22 +5,39 @@ includeTool << Jps
def projectHome = "$basedir"
def libs = "$projectHome/lib/"
project.targetFolder = "${projectHome}/build"
def gantHome = "/Users/max/libs/gant-1.7.0"
project.targetFolder = "${projectHome}/build"
library("ANT") {
classpath "$libs/ant-1.7.1.jar"
}
library("gant") {
new File("$gantHome/lib").eachFile {
classpath it
}
}
module("JPS") {
targetLevel ="1.5"
classpath antLayout
src "${projectHome}/src"
}
module("antLayout") {
targetLevel = "1.5"
classpath ANT
src "${projectHome}/antLayout/src"
}
module("gantLauncher") {
targetLevel = "1.5"
classpath ANT
classpath gant
src "${projectHome}/gantLauncher/src"
}
target('default' : 'Default target') {
project.clean()
project.makeAll()
@@ -33,5 +50,9 @@ target('default' : 'Default target') {
exclude (name: "JDOM*.class")
}
}
jar("gant_patches.jar") {
module("gantLauncher")
}
}
}
+19
View File
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<module relativePaths="true" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="Groovy" name="Groovy">
<configuration />
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Ant" level="project" />
<orderEntry type="library" name="gant-1.7.0" level="application" />
</component>
</module>
@@ -0,0 +1,351 @@
/*
* Copyright 2003-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package groovy.util;
import groovy.xml.QName;
import org.apache.tools.ant.*;
import org.apache.tools.ant.helper.AntXMLContext;
import org.apache.tools.ant.helper.ProjectHelper2;
import org.apache.tools.ant.input.DefaultInputHandler;
import org.codehaus.groovy.ant.FileScanner;
import org.xml.sax.Attributes;
import org.xml.sax.Locator;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.AttributesImpl;
import java.io.InputStream;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Allows <a href="http://ant.apache.org/manual/coretasklist.html">Ant tasks</a> to
* be used with GroovyMarkup. Requires the ant.jar in your classpath which will
* happen automatically if you are using the Groovy distribution but will be up
* to you to organize if you are embedding Groovy. If you wish to use the
* <a href="http://ant.apache.org/manual/optionaltasklist.html">optional tasks</a>
* you will need to add one or more additional jars from the ant distribution to
* your classpath.
*
* @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
* @author Dierk Koenig (dk)
* @author Marc Guillemot
* @version $Revision: 12900 $
*/
public class AntBuilder extends BuilderSupport {
private static final Class[] ADD_TASK_PARAM_TYPES = { String.class };
private final Logger log = Logger.getLogger(getClass().getName());
private Project project;
private final AntXMLContext antXmlContext;
private final ProjectHelper2.ElementHandler antElementHandler = new ProjectHelper2.ElementHandler();
private final ProjectHelper2.TargetHandler antTargetHandler = new ProjectHelper2.TargetHandler();
private final Target collectorTarget;
private final Target implicitTarget;
private Object lastCompletedNode;
public AntBuilder() {
this(createProject());
}
public AntBuilder(final Project project) {
this(project, new Target());
}
public AntBuilder(final Project project, final Target owningTarget) {
this.project = project;
this.project.setInputHandler(new DefaultInputHandler());
collectorTarget = owningTarget;
antXmlContext = new AntXMLContext(project);
collectorTarget.setProject(project);
antXmlContext.setCurrentTarget(collectorTarget);
antXmlContext.setLocator(new AntBuilderLocator());
antXmlContext.setCurrentTargets(new HashMap());
implicitTarget = new Target();
implicitTarget.setProject(project);
implicitTarget.setName("");
antXmlContext.setImplicitTarget(implicitTarget);
// FileScanner is a Groovy hack (utility?)
project.addDataTypeDefinition("fileScanner", FileScanner.class);
}
public AntBuilder(final Task parentTask) {
this(parentTask.getProject(), parentTask.getOwningTarget());
// define "owning" task as wrapper to avoid having tasks added to the target
// but it needs to be an UnknownElement and no access is available from
// task to its original UnknownElement
final UnknownElement ue = new UnknownElement(parentTask.getTaskName());
ue.setProject(parentTask.getProject());
ue.setTaskType(parentTask.getTaskType());
ue.setTaskName(parentTask.getTaskName());
ue.setLocation(parentTask.getLocation());
ue.setOwningTarget(parentTask.getOwningTarget());
ue.setRuntimeConfigurableWrapper(parentTask.getRuntimeConfigurableWrapper());
parentTask.getRuntimeConfigurableWrapper().setProxy(ue);
antXmlContext.pushWrapper(parentTask.getRuntimeConfigurableWrapper());
}
/**#
* Gets the Ant project in which the tasks are executed
* @return the project
*/
public Project getProject() {
return project;
}
/**
* @return Factory method to create new Project instances
*/
protected static Project createProject() {
final Project project = new Project();
final ProjectHelper helper = ProjectHelper.getProjectHelper();
project.addReference(ProjectHelper.PROJECTHELPER_REFERENCE, helper);
helper.getImportStack().addElement("AntBuilder"); // import checks that stack is not empty
final BuildLogger logger = new NoBannerLogger();
logger.setMessageOutputLevel(org.apache.tools.ant.Project.MSG_INFO);
logger.setOutputPrintStream(System.out);
logger.setErrorPrintStream(System.err);
project.addBuildListener(logger);
project.init();
project.getBaseDir();
return project;
}
protected void setParent(Object parent, Object child) {
}
/**
* We don't want to return the node as created in {@link #createNode(Object, Map, Object)}
* but the one made ready by {@link #nodeCompleted(Object, Object)}
* @see groovy.util.BuilderSupport#doInvokeMethod(java.lang.String, java.lang.Object, java.lang.Object)
*/
protected Object doInvokeMethod(String methodName, Object name, Object args) {
super.doInvokeMethod(methodName, name, args);
// return the completed node
return lastCompletedNode;
}
/**
* Determines, when the ANT Task that is represented by the "node" should perform.
* Node must be an ANT Task or no "perform" is called.
* If node is an ANT Task, it performs right after complete contstruction.
* If node is nested in a TaskContainer, calling "perform" is delegated to that
* TaskContainer.
* @param parent note: null when node is root
* @param node the node that now has all its children applied
*/
protected void nodeCompleted(final Object parent, final Object node) {
antElementHandler.onEndElement(null, null, antXmlContext);
lastCompletedNode = node;
if (parent != null && !(parent instanceof Target)) {
log.finest("parent is not null: no perform on nodeCompleted");
return; // parent will care about when children perform
}
// as in Target.execute()
if (node instanceof Task) {
Task task = (Task) node;
final String taskName = task.getTaskName();
// save original streams
InputStream savedIn = System.in;
InputStream savedProjectInputStream = project.getDefaultInputStream();
if (!(savedIn instanceof DemuxInputStream)) {
project.setDefaultInputStream(savedIn);
System.setIn(new DemuxInputStream(project));
}
try {
task.perform();
} finally {
// restore original streams
project.setDefaultInputStream(savedProjectInputStream);
System.setIn(savedIn);
}
// "Unwrap" the UnknownElement to return the real task to the calling code
if (node instanceof UnknownElement) {
final UnknownElement unknownElement = (UnknownElement) node;
unknownElement.maybeConfigure();
lastCompletedNode = unknownElement.getRealThing();
}
// restore dummy collector target
if ("import".equals(taskName)) {
antXmlContext.setCurrentTarget(collectorTarget);
}
}
else if (node instanceof Target) {
// restore dummy collector target
antXmlContext.setCurrentTarget(collectorTarget);
}
else {
final RuntimeConfigurable r = (RuntimeConfigurable) node;
r.maybeConfigure(project);
}
}
protected Object createNode(Object tagName) {
return createNode(tagName, Collections.EMPTY_MAP);
}
protected Object createNode(Object name, Object value) {
Object task = createNode(name);
setText(task, value.toString());
return task;
}
protected Object createNode(Object name, Map attributes, Object value) {
Object task = createNode(name, attributes);
setText(task, value.toString());
return task;
}
/**
* Builds an {@link Attributes} from a {@link Map}
*
* @param attributes the attributes to wrap
* @return the wrapped attributes
*/
protected static Attributes buildAttributes(final Map attributes) {
final AttributesImpl attr = new AttributesImpl();
for (final Iterator iter=attributes.entrySet().iterator(); iter.hasNext(); ) {
final Map.Entry entry = (Map.Entry) iter.next();
final String attributeName = (String) entry.getKey();
final String attributeValue = String.valueOf(entry.getValue());
attr.addAttribute(null, attributeName, attributeName, "CDATA", attributeValue);
}
return attr;
}
protected Object createNode(final Object name, final Map attributes) {
final Attributes attrs = buildAttributes(attributes);
String tagName = name.toString();
String ns = "";
if (name instanceof QName) {
QName q = (QName)name;
tagName = q.getLocalPart();
ns = q.getNamespaceURI();
}
// import can be used only as top level element
if ("import".equals(name)) {
antXmlContext.setCurrentTarget(implicitTarget);
}
else if ("target".equals(name)) {
return onStartTarget(attrs, tagName, ns);
}
try
{
antElementHandler.onStartElement(ns, tagName, tagName, attrs, antXmlContext);
}
catch (final SAXParseException e)
{
log.log(Level.SEVERE, "Caught: " + e, e);
}
final RuntimeConfigurable wrapper = (RuntimeConfigurable) antXmlContext.getWrapperStack().lastElement();
return wrapper.getProxy();
}
private Target onStartTarget(final Attributes attrs, String tagName, String ns) {
final Target target = new Target();
target.setProject(project);
target.setLocation(new Location(antXmlContext.getLocator()));
try {
antTargetHandler.onStartElement(ns, tagName, tagName, attrs, antXmlContext);
final Target newTarget = (Target) getProject().getTargets().get(attrs.getValue("name"));
// execute dependencies (if any)
final Vector targets = new Vector();
for (final Enumeration deps=newTarget.getDependencies(); deps.hasMoreElements();)
{
final String targetName = (String) deps.nextElement();
targets.add(project.getTargets().get(targetName));
}
getProject().executeSortedTargets(targets);
antXmlContext.setCurrentTarget(newTarget);
return newTarget;
}
catch (final SAXParseException e) {
log.log(Level.SEVERE, "Caught: " + e, e);
}
return null;
}
protected void setText(Object task, String text) {
final char[] characters = text.toCharArray();
try {
antElementHandler.characters(characters, 0, characters.length, antXmlContext);
}
catch (final SAXParseException e) {
log.log(Level.WARNING, "SetText failed: " + task + ". Reason: " + e, e);
}
}
public Project getAntProject() {
return project;
}
}
/**
* Would be nice to retrieve location information (from AST?).
* In a first time, without info
*/
class AntBuilderLocator implements Locator {
public int getColumnNumber()
{
return 0;
}
public int getLineNumber()
{
return 0;
}
public String getPublicId()
{
return "";
}
public String getSystemId()
{
return "";
}
}
@@ -0,0 +1,180 @@
// Gant -- A Groovy way of scripting Ant tasks.
//
// Copyright © 2008-9 Russel Winder
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the License is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing permissions and limitations under the
// License.
package org.codehaus.gant.ant ;
import java.io.File ;
import java.util.ArrayList ;
import java.util.HashMap ;
import java.util.List ;
import java.util.Map ;
import org.apache.tools.ant.AntClassLoader ;
import org.apache.tools.ant.BuildException ;
import org.apache.tools.ant.BuildListener ;
import org.apache.tools.ant.Project ;
import org.apache.tools.ant.Task ;
import org.codehaus.gant.GantBinding ;
import org.codehaus.gant.GantBuilder ;
/**
* Execute a Gant script.
*
* <p>This Ant task provides a Gant calling capability. The original intention behind this was to support
* continuous integration systems that do not directly support Gant but only Ant. However it also allows
* for gradual evolution of an Ant build into a Gant build.</p>
*
* <p>Possible attributes are:</p>
*
* <ul>
* <li>file &ndash; the path of the Gant script to execute.</li>
* <li>target &ndash; the target to execute; must be a single target name. For specifying than a
* single target, use nested gantTarget tags.</li>
* </ul>
*
* <p>Both of these are optional. The file 'build.gant' and the default target are used by default. An
* error results if there is no default target and no target is specified.</p>
*
* <p>Definitions, if needed, are specified using nested <code>definition</code> tags, one for each symbol
* to be defined. Each <code>definition</code> tag takes a compulsory <code>name</code> attribute and an
* optional <code>value</code> attribute.</p>
*
* @author Russel Winder
*/
public class Gant extends Task {
/**
* The path to the file to use to drive the Gant build. The default is build.gant. This path is
* relative to the basedir of the Ant project if it is set, or the directory in which the job was started
* if the basedir is not set.
*/
private String file = "build.gant" ;
/**
* A class representing a nested definition tag.
*/
public static final class Definition {
private String name ;
private String value ;
public void setName ( final String s ) { name = s ; }
public String getName ( ) { return name ; }
public void setValue ( final String s ) { value = s ; }
public String getValue ( ) { return value ; }
}
/**
* A list of definitions to be set in the Gant instance.
*/
private final List<Definition> definitions = new ArrayList<Definition> ( ) ;
/**
* A class representing a nested target tag.
*/
public static final class GantTarget {
private String value ;
public void setValue ( final String s ) { value = s ; }
public String getValue ( ) { return value ; }
}
/**
* A list of targets to be achieved by the Gant instance.
*/
private final List<GantTarget> targets = new ArrayList<GantTarget> ( ) ;
/**
* Set the name of the build file to use. This path is relative to the basedir of the Ant project if it
* is set, or the directory in which the job was started if the basedir is not set.
*
* @param f The name of the file to be used to drive the build.
*/
public void setFile ( final String f ) { file = f ; }
/**
* Set the target to be achieved.
*
* @param t The target to achieve.
*/
public void setTarget ( final String t ) {
final GantTarget gt = new GantTarget ( ) ;
gt.setValue ( t ) ;
targets.add ( gt ) ;
}
/**
* Create a node to represent a nested <code>gantTarget</code> tag.
*
* @return a new <code>GantTarget</code> instance ready for values to be added.
*/
public GantTarget createGantTarget ( ) {
final GantTarget gt = new GantTarget ( ) ;
targets.add ( gt ) ;
return gt ;
}
/**
* Create a node to represent a nested <code>definition</code> tag.
*
* @return a new <code>Definition</code> instance ready for values to be added.
*/
public Definition createDefinition ( ) {
final Definition definition = new Definition ( ) ;
definitions.add ( definition ) ;
return definition ;
}
/**
* Load the file and then execute it.
*/
@Override public void execute ( ) throws BuildException {
//
// At first it might seem appropriate to use the Project object from the calling Ant instance as the
// Project object used by the AntBuilder object and hence GantBuilder object associated with the Gant
// instance we are going to create here. However, if we just use that Project object directly then
// there are problems with proper annotation of the lines of output, so it isn't really an option.
// Therefore create a new Project instance and set the things appropriately from the original Project
// object.
//
// Issues driving things here are GANT-50 and GANT-80. GANT-50 is about having the correct base
// directory for operations, GANT-80 is about ensuring that all output generation actually generated
// observable output.
//
// NB As this class is called Gant, we have to use fully qualified name to get to the Gant main class.
//
final Project antProject = getOwningTarget ( ).getProject ( ) ;
final Project newProject = new Project ( ) ;
newProject.init ( ) ;
// Deal with GANT-80 by getting all the the loggers from the Ant instance Project object and adding
// them to the new Project Object. This was followed up by GANT-91 so the code was amended to copying
// over all listeners except the class loader if present.
for ( final Object o : antProject.getBuildListeners ( ) ) {
final BuildListener listener = (BuildListener) o ;
if ( ! ( listener instanceof AntClassLoader ) ) { newProject.addBuildListener ( listener ) ; }
}
// Deal with GANT-50 by getting the base directory from the Ant instance Project object and use it for
// the new Project object.
newProject.setBaseDir ( antProject.getBaseDir ( ) ) ;
final File gantFile = newProject.resolveFile( file ) ;
if ( ! gantFile.exists ( ) ) { throw new BuildException ( "Gantfile does not exist." , getLocation ( ) ) ; }
final GantBuilder ant = new GantBuilder ( newProject ) ;
final Map<String,String> environmentParameter = new HashMap<String,String> ( ) ;
environmentParameter.put ( "environment" , "environment" ) ;
ant.invokeMethod ( "property" , new Object[] { environmentParameter } ) ;
final GantBinding binding = new GantBinding ( ) ;
binding.forcedSettingOfVariable ( "ant" , ant ) ;
for ( final Definition definition : definitions ) {
final Map<String,String> definitionParameter = new HashMap<String,String> ( ) ;
definitionParameter.put ( "name" , definition.getName ( ) ) ;
definitionParameter.put ( "value" , definition.getValue ( ) ) ;
ant.invokeMethod ( "property" , new Object[] { definitionParameter } ) ;
}
final gant.Gant gant = new gant.Gant ( binding ) ;
gant.loadScript ( gantFile ) ;
final List<String> targetsAsStrings = new ArrayList<String> ( ) ;
for ( final GantTarget g : targets ) { targetsAsStrings.add ( g.getValue ( ) ) ; }
final int returnCode = gant.processTargets ( targetsAsStrings ) ;
if ( returnCode != 0 ) { throw new BuildException ( "Gant execution failed with return code " + returnCode + '.' , getLocation ( ) ) ; }
}
}
+2 -2
View File
@@ -2,7 +2,7 @@
<module relativePaths="true" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="Groovy" name="Groovy/Grails">
<configuration compile="true" />
<configuration />
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
@@ -13,8 +13,8 @@
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="groovy-1.6.3" level="application" />
<orderEntry type="library" name="gant-1.7.0" level="application" />
<orderEntry type="library" name="groovy-1.6.3" level="application" />
<orderEntry type="library" name="Ant" level="project" />
<orderEntry type="library" name="Javac2" level="project" />
<orderEntry type="module" module-name="antlayout" />
Binary file not shown.
+1 -1
View File
@@ -51,7 +51,7 @@ final class Jps {
})
binding.ant.taskdef(name: "layout", classname: "jetbrains.antlayout.tasks.LayoutTask")
project.taskdef(name: "layout", classname: "jetbrains.antlayout.tasks.LayoutTask")
}
def Jps(GantBinding binding, Map map) {
+13
View File
@@ -13,6 +13,7 @@ class Module extends LazyInitializeableObject implements ClasspathItem {
List excludes = []
Map<String, Object> props = [:]
Map<String, String> sourceRootPrefixes = [:]
def Module(project, name, initializer) {
this.project = project;
@@ -66,6 +67,18 @@ class Module extends LazyInitializeableObject implements ClasspathItem {
project.builder.makeModule(this)
}
def getOutput() {
make()
}
List<String> runtimeClasspath() {
project.builder.moduleRuntimeClasspath(this, false)
}
List<String> testRuntimeClasspath() {
project.builder.moduleRuntimeClasspath(this, true)
}
def makeTests() {
project.builder.makeModuleTests(this)
}
+71 -20
View File
@@ -28,8 +28,12 @@ class Project {
final Map<String, Module> modules = [:]
final Map<String, Library> libraries = [:]
Closure stagePrinter;
String targetFolder = "."
boolean dryRun = false
def Project(GantBinding binding) {
builder = new ProjectBuilder(binding, this)
this.binding = binding;
@@ -105,6 +109,14 @@ class Project {
binding.ant.project.log(message, org.apache.tools.ant.Project.MSG_WARN)
}
def stage(String message) {
if (stagePrinter != null) {
stagePrinter(message)
}
info(message)
}
def info(String message) {
binding.ant.project.log(message, org.apache.tools.ant.Project.MSG_INFO)
}
@@ -113,8 +125,19 @@ class Project {
builder.buildAll()
}
def makeProduction() {
builder.buildProduction()
}
def clean() {
binding.ant.delete(dir: targetFolder)
if (!dryRun) {
stage("Cleaning $targetFolder")
binding.ant.delete(dir: targetFolder)
}
else {
stage("Cleaning $targetFolder skipped as we're running dry")
}
builder.clean()
}
def ClasspathItem resolve(Object dep) {
@@ -122,28 +145,24 @@ class Project {
return dep
}
if (dep instanceof String) {
String path = dep
List<ClasspathItem> results = []
resolvers.each {
def resolved = it.resolve(path)
if (resolved != null) results.add(resolved)
}
String path = dep.toString()
if (results.isEmpty()) {
if (new File(path).exists()) return new PathEntry(path: path)
error("Cannot resolve $path")
}
else if (results.size() > 1) {
error("Ambigous resolve for $path. All of $results match")
}
return results[0]
List<ClasspathItem> results = []
resolvers.each {
def resolved = it.resolve(path)
if (resolved != null) results.add(resolved)
}
error("cannot resolve $dep")
return null
if (results.isEmpty()) {
if (new File(path).exists()) return new PathEntry(path: path)
error("Cannot resolve $path")
}
else if (results.size() > 1) {
error("Ambigous resolve for $path. All of $results match")
}
return results[0]
}
def getAt(String key) {
@@ -159,4 +178,36 @@ class Project {
def putAt(String key, Object value) {
props[key] = value
}
String getPropertyIfDefined(String name) {
try {
binding[name]
}
catch (MissingPropertyException mpe) {
return null
}
}
boolean isDefined(String prop) {
try {
binding[prop]
return true
}
catch (MissingPropertyException mpe) {
return false
}
}
def exportProperty(String name, String value) {
binding.ant.project.setProperty(name, value)
}
def taskdef(Map args) {
binding.ant.taskdef(name: args.name, classname: args.classname) {
String additionalClasspathId = getPropertyIfDefined("additional.classpath.id")
if (additionalClasspathId != null) {
classpath (refid: additionalClasspathId)
}
}
}
}
+45 -14
View File
@@ -34,6 +34,13 @@ class ProjectBuilder {
}
}
public def clean() {
outputs.clear()
testOutputs.clear()
cp.clear()
testCp.clear()
}
public def buildAll() {
buildChunks()
chunks.each {
@@ -42,6 +49,13 @@ class ProjectBuilder {
}
}
public def buildProduction() {
buildChunks()
chunks.each {
makeChunk(it)
}
}
private ModuleChunk chunkForModule(Module m) {
buildChunks();
mapping[m]
@@ -55,7 +69,7 @@ class ProjectBuilder {
String currentOutput = outputs[chunk]
if (currentOutput != null) return currentOutput
project.info("Making module ${chunk.name}")
project.stage("Making module ${chunk.name}")
def dst = folderForChunkOutput(chunk, classesDir(binding.project), false)
outputs[chunk] = dst
compile(chunk, dst, false)
@@ -71,7 +85,7 @@ class ProjectBuilder {
String currentOutput = testOutputs[chunk]
if (currentOutput != null) return currentOutput
project.info("Making tests for ${chunk.name}")
project.stage("Making tests for ${chunk.name}")
def dst = folderForChunkOutput(chunk, testClassesDir(binding.project), true)
testOutputs[chunk] = dst
compile(chunk, dst, true)
@@ -80,11 +94,11 @@ class ProjectBuilder {
}
private String classesDir(Project project) {
return new File(project.targetFolder, "classes").absolutePath
return new File(project.targetFolder, "production").absolutePath
}
private String testClassesDir(Project project) {
return new File(project.targetFolder, "testClasses").absolutePath
return new File(project.targetFolder, "test").absolutePath
}
private String folderForChunkOutput(ModuleChunk chunk, String basePath, boolean tests) {
@@ -108,25 +122,26 @@ class ProjectBuilder {
(
sourceRoots: sources,
excludes: chunk.excludes,
classpath: moduleClasspath(chunk, tests),
classpath: moduleCompileClasspath(chunk, tests),
targetFolder: dst,
tempRootsToDelete: []
)
state.print()
project.builders().each {
it.processModule(chunk, state)
if (!project.dryRun) {
project.builders().each {
it.processModule(chunk, state)
}
state.tempRootsToDelete.each {
binding.ant.delete(dir: it)
}
}
state.tempRootsToDelete.each {
binding.ant.delete(dir: it)
chunk.modules.each {
project.exportProperty("module.${it.name}.output.${tests ? "test" : "main"}", dst)
}
binding.ant.project.setProperty("module.${chunk.name}.output.${tests ? "test" : "main"}", dst)
}
List<String> moduleClasspath(ModuleChunk chunk, boolean test) {
List<String> moduleCompileClasspath(ModuleChunk chunk, boolean test) {
Map<ModuleChunk, List<String>> map = test ? testCp : cp
if (map[chunk] != null) return map[chunk]
@@ -143,6 +158,18 @@ class ProjectBuilder {
map[chunk] = set.asList()
}
List<String> moduleRuntimeClasspath(Module module, boolean test) {
return chunkRuntimeClasspath(chunkForModule(module), test)
}
List<String> chunkRuntimeClasspath(ModuleChunk chunk, boolean test) {
Set<String> set = new LinkedHashSet()
set.addAll(moduleCompileClasspath(chunk, test))
set.add(chunkOutput(chunk))
return set.asList()
}
private def transitiveClasspath(Object chunkOrModule, boolean test, Set<String> set, Set<Object> processed) {
if (processed.contains(chunkOrModule)) return
processed << chunkOrModule
@@ -173,6 +200,9 @@ class ProjectBuilder {
}
private String zipIfNecessary(String currentOut, ModuleChunk chunk) {
return currentOut
/*
def currentOutAsFile = new File(currentOut)
if (currentOutAsFile.isDirectory() && currentOutAsFile.list().length > 0) {
@@ -186,6 +216,7 @@ class ProjectBuilder {
else {
currentOut
}
*/
}
private String chunkTestOutput(ModuleChunk chunk) {
@@ -23,10 +23,22 @@ class JavacBuilder implements ModuleBuilder {
params.destdir = state.targetFolder
if (sourceLevel != null) params.source = sourceLevel
if (targetLevel != null) params.target = targetLevel
params.memoryMaximumSize = "512m"
params.fork = "true"
params.debug = "on"
def customJavac = module["javac"]
if (customJavac != null) {
params.executable = customJavac
}
def customArgs = module["javac_args"]
ant.javac (params) {
if (customArgs) {
compilerarg(line: customArgs)
}
state.sourceRoots.each {
src(path: it)
}
@@ -50,26 +62,45 @@ class JavacBuilder implements ModuleBuilder {
class ResourceCopier implements ModuleBuilder {
def processModule(ModuleChunk module, ModuleBuildState state) {
def processModule(ModuleChunk chunk, ModuleBuildState state) {
if (state.sourceRoots.isEmpty()) return;
def project = module.project
def project = chunk.project
def ant = project.binding.ant
ant.copy(todir: state.targetFolder) {
state.sourceRoots.each { root ->
fileset (dir : root) {
patternset (refid: module["compiler.resources.id"])
type (type: "file")
chunk.modules.each { module ->
def rootProcessor = {String root ->
if (new File(root).exists()) {
def target = state.targetFolder
def prefix = module.sourceRootPrefixes[root]
if (prefix != null) {
if (!(target.endsWith("/") || target.endsWith("\\"))) {
target += "/"
}
target += prefix
}
ant.copy(todir: target) {
fileset(dir: root) {
patternset(refid: chunk["compiler.resources.id"])
type(type: "file")
}
}
}
else {
project.warning("$root doesn't exist")
}
}
module.sourceRoots.each (rootProcessor)
module.testRoots.each (rootProcessor)
}
}
}
class GroovycBuilder implements ModuleBuilder {
def GroovycBuilder(Project project) {
project.binding.ant.taskdef (name: "groovyc", classname: "org.codehaus.groovy.ant.Groovyc")
project.taskdef (name: "groovyc", classname: "org.codehaus.groovy.ant.Groovyc")
}
def processModule(ModuleChunk module, ModuleBuildState state) {
@@ -78,15 +109,33 @@ class GroovycBuilder implements ModuleBuilder {
def project = module.project
def ant = project.binding.ant
ant.groovyc (destdir: state.targetFolder) {
final String destDir = state.targetFolder
ant.touch(millis: 239) {
fileset(dir: destDir) {
include(name: "**/*.class")
}
}
ant.groovyc(destdir: destDir) {
state.sourceRoots.each {
src(path: it)
}
include(name: "**/*.groovy")
classpath {
state.classpath.each {
pathelement(location: it)
}
pathelement(location: destDir) // Includes classes generated there by javac compiler
}
}
ant.touch() {
fileset(dir: destDir) {
include(name: "**/*.class")
}
}
}
@@ -95,7 +144,7 @@ class GroovycBuilder implements ModuleBuilder {
class GroovyStubGenerator implements ModuleBuilder {
def GroovyStubGenerator(Project project) {
project.binding.ant.taskdef (name: "generatestubs", classname: "org.codehaus.groovy.ant.GenerateStubsTask")
project.taskdef (name: "generatestubs", classname: "org.codehaus.groovy.ant.GenerateStubsTask")
}
def processModule(ModuleChunk module, ModuleBuildState state) {
@@ -133,14 +182,14 @@ class GroovyStubGenerator implements ModuleBuilder {
class JetBrainsInstrumentations implements ModuleBuilder {
def JetBrainsInstrumentations(Project project) {
project.binding.ant.taskdef(name: "jb_instrumentations", classname: "com.intellij.ant.InstrumentIdeaExtensions")
project.taskdef(name: "jb_instrumentations", classname: "com.intellij.ant.InstrumentIdeaExtensions")
}
def processModule(ModuleChunk module, ModuleBuildState state) {
def project = module.project
def ant = project.binding.ant
ant.jb_instrumentations(destdir: state.targetFolder) {
ant.jb_instrumentations(destdir: state.targetFolder, failonerror: "false") {
state.sourceRoots.each {
src(path: it)
}
@@ -147,6 +147,7 @@ public class IdeaProjectLoader {
componentTag.content.sourceFolder.each {Node folderTag ->
String path = expandMacro(pathFromUrl(attr(folderTag, "url")), projectBasePath, moduleBasePath)
String prefix = attr(folderTag, "packagePrefix")
if (folderTag.attribute("isTestSource") == "true") {
testSrc path
@@ -154,6 +155,10 @@ public class IdeaProjectLoader {
else {
src path
}
if (prefix != null && prefix != "") {
project.modules[currentModuleName].sourceRootPrefixes[path] = (prefix.replace('.', '/'))
}
}
componentTag.content.excludeFolder.each {Node exTag ->