/* * Copyright 2012 James Moger * * 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.moxie; import static java.text.MessageFormat.format; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.text.MessageFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.LinkedHashSet; import java.util.List; import java.util.Properties; import java.util.Scanner; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.moxie.Toolkit.Key; import org.moxie.console.Console; import org.moxie.maxml.MaxmlException; import org.moxie.utils.DeepCopier; import org.moxie.utils.FileUtils; import org.moxie.utils.StringUtils; /** * Build is a container class for the effective build configuration, the console, * and the solver. */ public class Build { private final BuildConfig config; private final Console console; private final Solver solver; private final Date buildDate; public Build(File configFile, File basedir) throws MaxmlException, IOException { this.config = new BuildConfig(configFile, basedir); this.console = new Console(config.isColor()); this.console.setDebug(config.isDebug()); this.solver = new Solver(console, config); this.buildDate = new Date(); } @Override public int hashCode() { return config.hashCode(); } @Override public boolean equals(Object o) { if (o instanceof Build) { return config.getProjectConfig().file.equals(((Build) o).getConfig().getProjectConfig().file); } return false; } public Date getBuildDate() { return buildDate; } public String getBuildDateString() { return new SimpleDateFormat("yyyy-MM-dd").format(buildDate); } public String getBuildTimestamp() { return new SimpleDateFormat("yyyy-MM-dd HH:mm").format(buildDate); } public Date getReleaseDate() { return config.getPom().releaseDate; } public String getReleaseDateString() { if (config.getPom().releaseDate != null) { return new SimpleDateFormat("yyyy-MM-dd").format(config.getPom().releaseDate); } return null; } public Solver getSolver() { return solver; } public BuildConfig getConfig() { return config; } public Console getConsole() { return console; } public Pom getPom() { return config.getPom(); } public Pom getPom(List<String> tags) { if (tags == null || tags.isEmpty()) { return getPom(); } Pom pom = DeepCopier.copy(config.getPom()); pom.clearDependencies(); for (Dependency dep : config.getPom().getDependencies(false)) { for (String tag : tags) { if (dep.tags.contains(tag.toLowerCase())) { if (dep.ring == Constants.RING1) { pom.addDependency(dep, dep.definedScope); } } } } return pom; } public File getBuildArtifact(String classifier) { String name = config.getPom().artifactId; if (!StringUtils.isEmpty(config.getPom().version)) { name += "-" + config.getPom().version; } if (StringUtils.isEmpty(classifier)) { classifier = config.getPom().classifier; } if (!StringUtils.isEmpty(classifier)) { name += "-" + classifier; } return new File(getConfig().getTargetDirectory(), name + ".jar"); } public void setup() { if (config.getRepositories().isEmpty()) { console.warn("No dependency repositories have been defined!"); } solver.updateRepositoryMetadata(); boolean solutionBuilt = solver.solve(); ToolkitConfig project = config.getProjectConfig(); // create apt source directories for (SourceDirectory sd : config.getSourceDirectories()) { if (sd.apt) { sd.getSources().mkdirs(); } } if (project.apply.size() > 0) { console.separator(); console.log("apply"); boolean applied = false; // create/update Eclipse configuration files if (solutionBuilt && (project.getEclipseSettings() != null)) { EclipseSettings settings = project.getEclipseSettings(); writeEclipseFactorypath(settings); writeEclipseClasspath(settings); writeEclipseProject(settings); console.notice(1, "rebuilt Eclipse configuration"); applied = true; } // create/update IntelliJ IDEA configuration files if (solutionBuilt && (project.getIntelliJSettings() != null)) { IntelliJSettings settings = project.getIntelliJSettings(); writeIntelliJProject(settings); writeIntelliJAnt(); writeIntelliJClasspath(settings); console.notice(1, "rebuilt IntelliJ IDEA configuration"); applied = true; } // create/update Maven POM if (solutionBuilt && project.apply(Toolkit.APPLY_POM)) { writePOM(); console.notice(1, "rebuilt pom.xml"); applied = true; } if (!applied) { console.log(1, "nothing applied"); } } } private File getIDEOutputFolder(Scope scope) { File baseFolder = new File(config.getProjectDirectory(), "bin"); if (scope == null) { return baseFolder; } switch (scope) { case test: return new File(baseFolder, "test-classes"); default: return new File(baseFolder, "classes"); } } private void writeEclipseClasspath(EclipseSettings settings) { if (config.getSourceDirectories().isEmpty() || config.getPom().isPOM() || !config.getModules().isEmpty()) { // no classpath to write return; } File projectFolder = config.getProjectDirectory(); String genSrcDir = null; List<SourceDirectory> sourceDirs = new ArrayList<SourceDirectory>(); sourceDirs.addAll(config.getProjectConfig().getSourceDirectories()); sourceDirs.addAll(config.getProjectConfig().getResourceDirectories()); StringBuilder sb = new StringBuilder(); for (SourceDirectory sourceFolder : sourceDirs) { if (Scope.site.equals(sourceFolder.scope)) { continue; } String srcPath = FileUtils.getRelativePath(projectFolder, sourceFolder.getSources()); if (sourceFolder.scope.isDefault()) { if (sourceFolder.apt) { // defined apt generated source folder genSrcDir = srcPath; } else { // defined standard source folder sb.append(format("<classpathentry kind=\"src\" path=\"{0}\" />\n", srcPath)); } } else { // defined source folder, not compile-scoped (i.e. test) sb.append(format("<classpathentry kind=\"src\" path=\"{0}\" output=\"{1}\" />\n", srcPath, FileUtils.getRelativePath(projectFolder, getIDEOutputFolder(sourceFolder.scope)))); } } // determine how to output dependencies (fixed-path or variable-relative) String kind = settings.var ? "var" : "lib"; boolean extRelative = getConfig().getProjectConfig().dependencyDirectory != null && getConfig().getProjectConfig().dependencyDirectory.exists(); // always link classpath against Moxie artifact cache Set<Dependency> dependencies = solver.solve(Scope.test); for (Dependency dependency : dependencies) { if (dependency instanceof SystemDependency) { SystemDependency sys = (SystemDependency) dependency; sb.append(format("<classpathentry kind=\"lib\" path=\"{0}\" />\n", FileUtils.getRelativePath(projectFolder, new File(sys.path)))); } else { File jar = solver.getMoxieCache().getArtifact(dependency, dependency.extension); Dependency sources = dependency.getSourcesArtifact(); File srcJar = solver.getMoxieCache().getArtifact(sources, sources.extension); String jarPath; String srcPath; if ("var".equals(kind)) { // relative to MOXIE_HOME jarPath = Toolkit.MOXIE_ROOT + "/" + FileUtils.getRelativePath(config.getMoxieRoot(), jar); srcPath = Toolkit.MOXIE_ROOT + "/" + FileUtils.getRelativePath(config.getMoxieRoot(), srcJar); } else { // filesystem path if (extRelative) { // relative to project dependency folder jar = config.getProjectConfig().getProjectDependencyArtifact(dependency); // relative to project dependency source folder srcJar = config.getProjectConfig().getProjectDependencySourceArtifact(dependency); jarPath = FileUtils.getRelativePath(projectFolder, jar); srcPath = FileUtils.getRelativePath(projectFolder, srcJar); } else { // absolute, hard-coded path to Moxie root jarPath = jar.getAbsolutePath(); srcPath = srcJar.getAbsolutePath(); } } if (!jar.exists()) { console.error("Excluding {0} from Eclipse classpath because artifact does not exist!", dependency.getCoordinates()); continue; } if (srcJar.exists() && srcJar.length() > 1024) { // has non-placeholder sources jar sb.append(format("<classpathentry kind=\"{0}\" path=\"{1}\" sourcepath=\"{2}\" />\n", kind, jarPath, srcPath)); } else { // no sources sb.append(format("<classpathentry kind=\"{0}\" path=\"{1}\" />\n", kind, jarPath)); } } } for (Build linkedProject : solver.getLinkedModules()) { String projectName = null; File dotProject = new File(linkedProject.config.getProjectDirectory(), ".project"); if (dotProject.exists()) { // extract Eclipse project name console.debug("extracting project name from {0}", dotProject.getAbsolutePath()); Pattern p = Pattern.compile("(<name>)(.+)(</name>)"); try { Scanner scanner = new Scanner(dotProject); while (scanner.hasNextLine()) { scanner.nextLine(); projectName = scanner.findInLine(p); if (!StringUtils.isEmpty(projectName)) { Matcher m = p.matcher(projectName); m.find(); projectName = m.group(2).trim(); console.debug(1, projectName); break; } } scanner.close(); } catch (FileNotFoundException e) { } } else { // use folder name projectName = linkedProject.config.getProjectDirectory().getName(); } sb.append(format("<classpathentry kind=\"src\" path=\"/{0}\" />\n", projectName)); } sb.append("<classpathentry kind=\"con\" path=\"org.eclipse.jdt.launching.JRE_CONTAINER\" />\n"); if (settings.groovy) { sb.append("<classpathentry exported=\"true\" kind=\"con\" path=\"GROOVY_SUPPORT\" />\n"); sb.append("<classpathentry exported=\"true\" kind=\"con\" path=\"GROOVY_DSL_SUPPORT\" />\n"); } if (settings.wst){ sb.append("<classpathentry kind=\"con\" path=\"org.eclipse.jst.j2ee.internal.web.container\" />\n"); sb.append("<classpathentry kind=\"con\" path=\"org.eclipse.jst.j2ee.internal.module.container\" />\n"); } // determine if we should append an default apt source folder to the classpath File aptPrefs = new File(projectFolder, ".settings/org.eclipse.jdt.apt.core.prefs"); Properties aptProps = readEclipsePrefs(aptPrefs); if (Boolean.valueOf(aptProps.getProperty("org.eclipse.jdt.apt.aptEnabled"))) { genSrcDir = aptProps.getProperty("org.eclipse.jdt.apt.genSrcDir"); if (genSrcDir == null) { genSrcDir = ".apt_generated"; } sb.append(format("<classpathentry kind=\"src\" path=\"{0}\">\n", genSrcDir)); sb.append("\t<attributes>\n"); sb.append("\t\t<attribute name=\"optional\" value=\"true\"/>\n"); sb.append("\t</attributes>\n"); sb.append("</classpathentry>\n"); } sb.append(format("<classpathentry kind=\"output\" path=\"{0}\" />\n", FileUtils.getRelativePath(projectFolder, getIDEOutputFolder(Scope.compile)))); StringBuilder file = new StringBuilder(); file.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); file.append("<classpath>\n"); file.append(StringUtils.insertHardTab(sb.toString())); file.append("</classpath>\n"); FileUtils.writeContent(new File(projectFolder, ".classpath"), file.toString()); } private void writeEclipseFactorypath(EclipseSettings settings) { File projectFolder = config.getProjectDirectory(); StringBuilder sb = new StringBuilder(); // identify apt-processing dependencies on compile classpath Set<Dependency> aptDeps = new LinkedHashSet<Dependency>(); List<Dependency> dependencies = config.getPom().getDependencies(Scope.compile); for (Dependency dep : dependencies) { if (dep.ring == Constants.RING1 && dep.apt) { aptDeps.addAll(solver.getRuntimeDependencies(dep)); } } if (aptDeps.size() > 0) { // resolve apt artifacts Set<File> aptFiles = new LinkedHashSet<File>(); for (Dependency dep : aptDeps) { File file = solver.getArtifact(dep); aptFiles.add(file); } // create the factorypath file boolean runInBatchMode = false; String pattern = "<factorypathentry kind=\"{0}\" id=\"{1}\" enabled=\"true\" runInBatchMode=\"{2}\" />\n"; sb.append(MessageFormat.format(pattern, "PLUGIN", "org.eclipse.jst.ws.annotations.core", runInBatchMode)); // kind choices are EXTJAR, VARJAR, or WKSPJAR String kind = settings.var ? "VARJAR" : "EXTJAR"; for (File file : aptFiles) { // default to EXTJAR String jarPath = file.getAbsolutePath(); if ("VARJAR".equals(kind)) { // relative to MOXIE_HOME jarPath = Toolkit.MOXIE_ROOT + "/" + FileUtils.getRelativePath(config.getMoxieRoot(), file); } else if ("WKSPJAR".equals(kind)) { // relative to workspace // TODO } sb.append(MessageFormat.format(pattern, kind, jarPath, runInBatchMode)); } // write the factorypath file StringBuilder file = new StringBuilder(); file.append("<factorypath>\n"); file.append(StringUtils.insertHardTab(sb.toString())); file.append("</factorypath>\n"); FileUtils.writeContent(new File(projectFolder, ".factorypath"), file.toString()); String genSrcDir = ".apt_generated"; for (SourceDirectory dir : config.getSourceDirectories()) { if (dir.apt && Scope.compile.equals(dir.scope)) { genSrcDir = dir.name; break; } } // create/update Eclipse apt preferences File aptPrefs = new File(projectFolder, ".settings/org.eclipse.jdt.apt.core.prefs"); Properties aptDefaults = new Properties(); aptDefaults.put("org.eclipse.jdt.apt.reconcileEnabled", "true"); Properties aptOverrides = new Properties(); aptOverrides.put("org.eclipse.jdt.apt.genSrcDir", genSrcDir); aptOverrides.put("org.eclipse.jdt.apt.aptEnabled", "true"); writeEclipsePrefs(aptPrefs, aptDefaults, aptOverrides); // create/update Eclipse jdt preferences File jdtPrefs = new File(projectFolder, ".settings/org.eclipse.jdt.core.prefs"); Properties jdtOverrides = new Properties(); jdtOverrides.put("org.eclipse.jdt.core.compiler.processAnnotations", "enabled"); writeEclipsePrefs(jdtPrefs, new Properties(), jdtOverrides); } } private Properties readEclipsePrefs(File prefsFile) { Properties props = new Properties(); if (prefsFile.exists()) { // load existing prefs file FileInputStream is = null; try { is = new FileInputStream(prefsFile); props.load(is); } catch (Exception e) { getConsole().error(e); } finally { try { is.close(); } catch (Exception e) { } } } return props; } private void writeEclipsePrefs(File prefsFile, Properties defaults, Properties overrides) { // create/update Eclipse preferences if (prefsFile.exists()) { // load existing prefs file Properties props = readEclipsePrefs(prefsFile); defaults.putAll(props); } else { // create .settings folder prefsFile.getParentFile().mkdirs(); // insert prefs version defaults.put("eclipse.preferences.version", "1"); } // ensure the overrides are set defaults.putAll(overrides); FileOutputStream os = null; try { os = new FileOutputStream(prefsFile); defaults.store(os, null); } catch (Exception e) { getConsole().error(e); } finally { try { os.close(); } catch (Exception e) { } } } private void writeEclipseProject(EclipseSettings settings) { if (!config.getModules().isEmpty()) { // do not write project file for a parent descriptor return; } File dotProject = new File(config.getProjectDirectory(), ".project"); if (dotProject.exists()) { // update name and description try { StringBuilder sb = new StringBuilder(); Pattern namePattern = Pattern.compile("\\s*?<name>(.+)</name>"); Pattern descriptionPattern = Pattern.compile("\\s*?<comment>(.+)</comment>"); boolean replacedName = false; boolean replacedDescription = false; Scanner scanner = new Scanner(dotProject); while (scanner.hasNextLine()) { String line = scanner.nextLine(); // replace name if (!replacedName) { Matcher m = namePattern.matcher(line); if (m.matches()) { int start = m.start(1); int end = m.end(1); //console.error("s=" + start + " e=" + end + " l=" + line); line = line.substring(0, start) + config.getPom().getName() + line.substring(end); replacedName = true; } } // replace description if (!replacedDescription) { Matcher m = descriptionPattern.matcher(line); if (m.matches()) { int start = m.start(1); int end = m.end(1); //console.error("s=" + start + " e=" + end + " l=" + line); line = line.substring(0, start) + (config.getPom().getDescription() == null ? "" : config.getPom().getDescription()) + line.substring(end); replacedDescription = true; } } sb.append(line).append('\n'); } scanner.close(); FileUtils.writeContent(dotProject, sb.toString()); } catch (FileNotFoundException e) { } return; } // create file StringBuilder sb = new StringBuilder(); sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); sb.append("<projectDescription>\n"); sb.append(MessageFormat.format("\t<name>{0}</name>\n", getPom().name)); sb.append(MessageFormat.format("\t<comment>{0}</comment>\n", getPom().description == null ? "" : getPom().description)); sb.append("\t<projects>\n"); sb.append("\t</projects>\n"); sb.append("\t<buildSpec>\n"); List<String> buildCommands = new ArrayList<String>(); if (config.getSourceDirectories().size() > 0) { buildCommands.add("org.eclipse.jdt.core.javabuilder"); } if (settings.wst) { buildCommands.add("org.eclipse.wst.common.project.facet.core.builder"); buildCommands.add("org.eclipse.wst.validation.validationbuilder"); buildCommands.add("org.eclipse.wst.jsdt.core.javascriptValidator"); } for (String cmd : buildCommands) { sb.append("\t\t<buildCommand>\n"); sb.append(MessageFormat.format("\t\t\t<name>{0}</name>\n", cmd)); sb.append("\t\t\t<arguments>\n"); sb.append("\t\t\t</arguments>\n"); sb.append("\t\t</buildCommand>\n"); } sb.append("\t</buildSpec>\n"); sb.append("\t<natures>\n"); if (config.getSourceDirectories().size() > 0) { List<String> natures = new ArrayList<String>(); natures.add("org.eclipse.jdt.core.javanature"); if (settings.groovy) { natures.add("org.eclipse.jdt.groovy.core.groovyNature"); } if (settings.wst){ natures.add("org.eclipse.wst.common.modulecore.ModuleCoreNature"); natures.add("org.eclipse.wst.common.project.facet.core.nature"); natures.add("org.eclipse.wst.jsdt.core.jsNature"); } for (String nature : natures) { sb.append(MessageFormat.format("\t\t<nature>{0}</nature>\n", nature)); } } sb.append("\t</natures>\n"); sb.append("</projectDescription>\n\n"); FileUtils.writeContent(dotProject, sb.toString()); } private void writeIntelliJProject(IntelliJSettings settings) { if (config.getModules().isEmpty()) { // no modules to write project files return; } ToolkitConfig project = config.getProjectConfig(); File dotIdea = new File(project.baseDirectory, ".idea"); dotIdea.mkdirs(); // Group name prefers name attribute, but will use groupId if required String groupName = project.pom.getGroupId(); if (!project.pom.getArtifactId().equals(project.pom.getName())) { groupName = project.pom.getName(); } List<Module> modules = new ArrayList<Module>(config.getModules()); Collections.sort(modules); StringBuilder sb = new StringBuilder(); for (Module module : modules) { File moduleFolder = new File(project.baseDirectory, module.folder); File configFile = new File(moduleFolder, module.descriptor); if (!configFile.exists()) { continue; } ToolkitConfig moduleConfig; try { moduleConfig = new ToolkitConfig(configFile, moduleFolder, Toolkit.MOXIE_DEFAULTS); if (StringUtils.isEmpty(moduleConfig.getPom().artifactId)) { console.warn(2, "excluding module ''{0}'' from IntelliJ IDEA project because it has no artifactId!", module.folder); continue; } if (moduleConfig.getPom().isPOM()) { // skip pom modules console.warn(2, "excluding module ''{0}'' from IntelliJ IDEA project because it is a POM module!", module.folder); continue; } if (moduleConfig.getSourceDirectories().isEmpty()) { // skip modules without source folders console.warn(2, "excluding module ''{0}'' from IntelliJ IDEA project because it has no source directories!", module.folder); continue; } sb.append(format("<module fileurl=\"file://$PROJECT_DIR$/{0}/{1}.iml\" filepath=\"$PROJECT_DIR$/{0}/{1}.iml\" group=\"{2}\" />\n", module.folder, moduleConfig.getPom().artifactId, groupName)); } catch (Exception e) { console.error(e, "Failed to parse {0} for module {1}!", module.descriptor, module.folder); } } StringBuilder modulesStr = new StringBuilder(); modulesStr.append("<modules>\n"); modulesStr.append(StringUtils.insertHalfTab(sb.toString())); modulesStr.append("</modules>"); StringBuilder component = new StringBuilder(); component.append("<component name=\"ProjectModuleManager\">\n"); component.append(StringUtils.insertHalfTab(modulesStr.toString())); component.append("</component>"); StringBuilder file = new StringBuilder(); file.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); file.append("<project version=\"4\">\n"); file.append(StringUtils.insertHalfTab(component.toString())); file.append("</project>\n\n"); FileUtils.writeContent(new File(dotIdea, "modules.xml"), file.toString()); } private void writeIntelliJAnt() { if (config.getModules().isEmpty()) { // no modules to write project files return; } ToolkitConfig project = config.getProjectConfig(); File dotIdea = new File(project.baseDirectory, ".idea"); dotIdea.mkdirs(); File antFile = new File(dotIdea, "ant.xml"); if (antFile.exists()) { // do not attempt to update this file return; } StringBuilder sb = new StringBuilder(); File rootAnt = new File(project.baseDirectory, "build.xml"); if (rootAnt.exists()) { sb.append(format("<buildFile url=\"file://$PROJECT_DIR$/{0}\" />\n", rootAnt.getName())); } for (Module module : project.modules) { File moduleFolder = new File(project.baseDirectory, module.folder); File scriptFile = new File(moduleFolder, module.script); if (!scriptFile.exists()) { continue; } sb.append(format("<buildFile url=\"file://$PROJECT_DIR$/{0}/{1}\" />\n", module.folder, module.script)); } StringBuilder component = new StringBuilder(); component.append("<component name=\"AntConfiguration\">\n"); component.append(StringUtils.insertHalfTab(sb.toString())); component.append("</component>"); StringBuilder file = new StringBuilder(); file.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); file.append("<project version=\"4\">\n"); file.append(StringUtils.insertHalfTab(component.toString())); file.append("</project>\n\n"); FileUtils.writeContent(antFile, file.toString()); } private void writeIntelliJClasspath(IntelliJSettings settings) { if (config.getSourceDirectories().isEmpty() || config.getPom().isPOM() || !config.getModules().isEmpty()) { // no classpath to write return; } File projectFolder = config.getProjectDirectory(); StringBuilder sb = new StringBuilder(); sb.append(format("<output url=\"file://$MODULE_DIR$/{0}\" />\n", FileUtils.getRelativePath(projectFolder, getIDEOutputFolder(Scope.compile)))); sb.append(format("<output-test url=\"file://$MODULE_DIR$/{0}\" />\n", FileUtils.getRelativePath(projectFolder, getIDEOutputFolder(Scope.test)))); sb.append("<exclude-output />\n"); sb.append("<content url=\"file://$MODULE_DIR$\">\n"); List<SourceDirectory> sourceDirs = new ArrayList<SourceDirectory>(); sourceDirs.addAll(config.getProjectConfig().getSourceDirectories()); sourceDirs.addAll(config.getProjectConfig().getResourceDirectories()); StringBuilder sf = new StringBuilder(); for (SourceDirectory sourceFolder : sourceDirs) { if (Scope.site.equals(sourceFolder.scope)) { continue; } sf.append(format("<sourceFolder url=\"file://$MODULE_DIR$/{0}\" isTestSource=\"{1}\" />\n", FileUtils.getRelativePath(projectFolder, sourceFolder.getSources()), Scope.test.equals(sourceFolder.scope))); } sb.append(StringUtils.insertHalfTab(sf.toString())); sb.append("</content>\n"); sb.append("<orderEntry type=\"sourceFolder\" forTests=\"false\" />\n"); // determine how to output dependencies (fixed-path or variable-relative) boolean variableRelative = false; boolean extRelative = getConfig().getProjectConfig().dependencyDirectory != null && getConfig().getProjectConfig().dependencyDirectory.exists(); // always link classpath against Moxie artifact cache Set<Dependency> dependencies = new LinkedHashSet<Dependency>(); dependencies.addAll(solver.solve(Scope.compile)); // add unique test classpath items dependencies.addAll(solver.solve(Scope.test)); for (Dependency dependency : dependencies) { Scope scope = null; File jar = null; File srcJar = null; String jarPath = null; String srcPath = null; if (dependency instanceof SystemDependency) { SystemDependency sys = (SystemDependency) dependency; jar = new File(sys.path); jarPath = format("jar://{0}!/", jar.getAbsolutePath()); } else { if (dependency.definedScope == null) { getConsole().error("{0} is missing a definedScope!", dependency.getCoordinates()); } // COMPILE scope is always implied and unnecessary in iml file if (!dependency.definedScope.isDefault()) { scope = dependency.definedScope; } jar = solver.getMoxieCache().getArtifact(dependency, dependency.extension); Dependency sources = dependency.getSourcesArtifact(); srcJar = solver.getMoxieCache().getArtifact(sources, sources.extension); if (variableRelative) { // relative to MOXIE_HOME jarPath = format("jar://$" + Toolkit.MOXIE_ROOT + "$/{0}!/", FileUtils.getRelativePath(config.getMoxieRoot(), jar)); srcPath = format("jar://$" + Toolkit.MOXIE_ROOT + "$/{0}!/", FileUtils.getRelativePath(config.getMoxieRoot(), srcJar)); } else { // filesystem path if (extRelative) { // relative to project dependency folder jar = config.getProjectConfig().getProjectDependencyArtifact(dependency); // relative to project dependency source folder srcJar = config.getProjectConfig().getProjectDependencySourceArtifact(dependency); jarPath = format("jar://$MODULE_DIR$/{0}!/", FileUtils.getRelativePath(projectFolder, jar)); srcPath = format("jar://$MODULE_DIR$/{0}!/", FileUtils.getRelativePath(projectFolder, srcJar)); } else { // relative to USER_HOME jarPath = format("jar://$USER_HOME$/.moxie/{0}!/", FileUtils.getRelativePath(config.getMoxieRoot(), jar)); srcPath = format("jar://$USER_HOME$/.moxie/{0}!/", FileUtils.getRelativePath(config.getMoxieRoot(), srcJar)); } } } if (!jar.exists()) { console.error("Excluding {0} from IntelliJ IDEA classpath because artifact does not exist!", dependency.getCoordinates()); continue; } if (scope == null) { sb.append("<orderEntry type=\"module-library\">\n"); } else { sb.append(format("<orderEntry type=\"module-library\" scope=\"{0}\">\n", scope.name().toUpperCase())); } StringBuilder lib = new StringBuilder(); lib.append(format("<library name=\"{0}\">\n", jar.getName())); StringBuilder CLASSES = new StringBuilder(); CLASSES.append("<CLASSES>\n"); CLASSES.append(StringUtils.insertHalfTab(format("<root url=\"{0}\" />\n", jarPath))); CLASSES.append("</CLASSES>\n"); lib.append(StringUtils.insertHalfTab(CLASSES.toString())); lib.append(StringUtils.insertHalfTab("<JAVADOC />\n")); if (srcJar != null && srcJar.exists() && srcJar.length() > 1024) { StringBuilder SOURCES = new StringBuilder(); SOURCES.append("<SOURCES>\n"); SOURCES.append(StringUtils.insertHalfTab(format("<root url=\"{0}\" />\n", srcPath))); SOURCES.append("</SOURCES>\n"); lib.append(StringUtils.insertHalfTab(SOURCES.toString())); } else { lib.append(StringUtils.insertHalfTab("<SOURCES />\n")); } lib.append("</library>\n"); sb.append(StringUtils.insertHalfTab(lib.toString())); sb.append("</orderEntry>\n"); } for (Build linkedProject : solver.getLinkedModules()) { String artifactId = linkedProject.getPom().getArtifactId(); sb.append(format("<orderEntry type=\"module\" module-name=\"{0}\" />\n", artifactId)); } sb.append("<orderEntry type=\"inheritedJdk\" />\n"); StringBuilder component = new StringBuilder(); component.append("<component name=\"NewModuleRootManager\" inherit-compiler-output=\"false\">\n"); component.append(StringUtils.insertHalfTab(sb.toString())); component.append("</component>"); StringBuilder file = new StringBuilder(); file.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); file.append("<module type=\"JAVA_MODULE\" version=\"4\">\n"); file.append(StringUtils.insertHalfTab(component.toString())); file.append("</module>\n\n"); String name = config.getPom().getArtifactId(); FileUtils.writeContent(new File(projectFolder, name + ".iml"), file.toString()); } private void writePOM() { if (config.getSourceDirectories().isEmpty() || config.getPom().isPOM() || !config.getModules().isEmpty()) { // no POM to write return; } StringBuilder sb = new StringBuilder(); sb.append("<!-- This file is automatically generated by Moxie. DO NOT HAND EDIT! -->\n"); sb.append(getPom().toXML(false, config.getRepositoryDefinitions())); FileUtils.writeContent(new File(config.getProjectDirectory(), "pom.xml"), sb.toString()); } public void describe() { console.title(getPom().name, getPom().version); describeConfig(); describeSettings(); } void describeConfig() { Pom pom = getPom(); console.log("project metadata"); describe(Key.name, pom.name); describe(Key.description, pom.description); describe(Key.groupId, pom.groupId); describe(Key.artifactId, pom.artifactId); describe(Key.version, pom.version); describe(Key.organization, pom.organization); describe(Key.url, pom.url); if (!solver.isOnline()) { console.separator(); console.warn("Moxie is running offline. Network functions disabled."); } if (config.isVerbose()) { console.separator(); console.log("source directories"); for (SourceDirectory directory : config.getSourceDirectories()) { console.sourceDirectory(directory); } console.separator(); console.log("resource directories"); for (SourceDirectory directory : config.getResourceDirectories()) { console.sourceDirectory(directory); } console.separator(); console.log("output directory"); console.log(1, config.getOutputDirectory(null).toString()); console.separator(); } } void describeSettings() { if (config.isVerbose()) { console.log("Moxie parameters"); describe(Toolkit.MX_ROOT, solver.getMoxieCache().getRootFolder().getAbsolutePath()); describe(Toolkit.MX_ONLINE, "" + solver.isOnline()); describe(Toolkit.MX_UPDATEMETADATA, "" + solver.isUpdateMetadata()); describe(Toolkit.MX_DEBUG, "" + config.isDebug()); describe(Toolkit.MX_VERBOSE, "" + config.isVerbose()); describe(Toolkit.Key.mavenCacheStrategy, config.getMavenCacheStrategy().name()); console.log("dependency sources"); if (config.getRepositories().size() == 0) { console.error("no dependency sources defined!"); } for (Repository repository : config.getRepositories()) { console.log(1, repository.toString()); console.download(repository.getRepositoryUrl()); console.log(); } List<Proxy> actives = config.getMoxieConfig().getActiveProxies(); if (actives.size() > 0) { console.log("proxy settings"); for (Proxy proxy : actives) { if (proxy.active) { describe("proxy", proxy.host + ":" + proxy.port); } } console.separator(); } } } void describe(Enum<?> key, String value) { describe(key.name(), value); } void describe(String key, String value) { if (StringUtils.isEmpty(value)) { return; } console.key(StringUtils.leftPad(key, 12, ' '), value); } @Override public String toString() { return "Build (" + getPom().toString() + ")"; } }