/******************************************************************************* * Copyright (c) 2006-2016 * Software Technology Group, Dresden University of Technology * DevBoost GmbH, Dresden, Amtsgericht Dresden, HRB 34001 * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Software Technology Group - TU Dresden, Germany; * DevBoost GmbH - Dresden, Germany * - initial API and implementation ******************************************************************************/ package de.devboost.buildboost.genext.cmdlineapp.steps; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.net.URISyntaxException; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import de.devboost.buildboost.BuildException; import de.devboost.buildboost.ant.AbstractAntTargetGenerator; import de.devboost.buildboost.ant.AntTarget; import de.devboost.buildboost.artifacts.Plugin; import de.devboost.buildboost.model.BuildEventType; import de.devboost.buildboost.model.IBuildListener; import de.devboost.buildboost.util.PluginPackagingHelper; import de.devboost.buildboost.util.StreamUtil; import de.devboost.buildboost.util.XMLContent; public class CommandlineAppPackagingStep extends AbstractAntTargetGenerator { private final Plugin plugin; private final IBuildListener buildListener; public CommandlineAppPackagingStep(Plugin plugin, IBuildListener buildListener) { this.plugin = plugin; this.buildListener = buildListener; } @Override public Collection<AntTarget> generateAntTargets() throws BuildException { XMLContent content = new XMLContent(); String temporaryDir = "temp/cmdlineapps/" + plugin.getIdentifier(); content.append("<mkdir dir=\"" + temporaryDir + "\" />"); Set<Plugin> dependencies = plugin.getAllDependencies(); PluginPackagingHelper packagingHelper = new PluginPackagingHelper(); packagingHelper.addPackageAsJarFileScript(content, temporaryDir, plugin); packagingHelper.addPackageAsJarFileScripts(content, temporaryDir, dependencies); // add script content content.append("<jar destfile=\"dist/commandlineapps/" + plugin.getIdentifier() + ".jar\">"); // TODO this is a dirty hack and will not work when BuildBoost is used in its packaged form URL classLocation = getClass().getProtectionDomain().getCodeSource().getLocation(); String pathTail = getClass().getPackage().getName().replace(".", File.separator) + File.separator + "jar-in-jar-loader.zip"; try { content.append("<zipfileset src=\"" + new File(classLocation.toURI().getPath(), pathTail).getAbsolutePath() + "\"/>"); } catch (URISyntaxException e) { throw new BuildException(e.getMessage()); } List<String> allLibraries = new ArrayList<String>(); // add the project itself addProject(content, temporaryDir, plugin, allLibraries); // add the dependencies for (Plugin dependency : dependencies) { if (dependency.isProject()) { addProject(content, temporaryDir, dependency, allLibraries); } else { addTargetPlatformPlugin(content, dependency, allLibraries); } } Set<String> additionalFiles = getLines("additional_zip_contents.conf"); if (additionalFiles != null) { for (String additionalFile : additionalFiles) { content.append("<fileset file=\"" + plugin.getLocation().getAbsolutePath() + File.separator + additionalFile + "\" />"); } } allLibraries = removeExcludedLibraries(allLibraries); StringBuilder spaceSeparatedLibs = new StringBuilder(); for (String lib : allLibraries) { spaceSeparatedLibs.append(" "); spaceSeparatedLibs.append(lib); } content.append("<manifest>"); content.append( "<attribute name=\"Main-Class\" value=\"org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader\"/>"); content.append("<attribute name=\"Rsrc-Main-Class\" value=\"" + plugin.getIdentifier() + ".Main\"/>"); content.append("<attribute name=\"Class-Path\" value=\".\"/>"); content.append("<attribute name=\"Rsrc-Class-Path\" value=\"./" + spaceSeparatedLibs.toString() + "\"/>"); content.append("</manifest>"); content.append("</jar>"); AntTarget target = new AntTarget("package-cmdlineapp-" + plugin.getIdentifier(), content); return Collections.singleton(target); } private List<String> removeExcludedLibraries(List<String> allLibraries) { String filename = "excluded_libraries.conf"; Set<String> librariesToRemoveFromClasspath = getLines(filename); if (librariesToRemoveFromClasspath == null) { return allLibraries; } Set<String> remainingLibraries = new LinkedHashSet<String>(allLibraries); for (String libraryToRemoveFromClasspath : librariesToRemoveFromClasspath) { boolean removed = remainingLibraries.remove(libraryToRemoveFromClasspath); if (removed) { buildListener.handleBuildEvent(BuildEventType.INFO, "Removed excluded library '" + libraryToRemoveFromClasspath + "' from JAR classpath"); } else { buildListener.handleBuildEvent(BuildEventType.INFO, "Can't find excluded library '" + libraryToRemoveFromClasspath + "'"); } } return new ArrayList<String>(remainingLibraries); } private Set<String> getLines(String filename) { String path = plugin.getAbsolutePath() + File.separator + filename; File excludeFile = new File(path); if (!excludeFile.exists()) { return null; } Set<String> librariesToRemoveFromClasspath = new LinkedHashSet<String>(); try { String contentAsString = new StreamUtil().getContentAsString(new FileInputStream(excludeFile)); contentAsString = contentAsString.replace("\r", ""); String[] lines = contentAsString.split("\n"); for (int i = 0; i < lines.length; i++) { String line = lines[i].trim(); if (line.isEmpty()) { continue; } librariesToRemoveFromClasspath.add(line); } } catch (FileNotFoundException e) { buildListener.handleBuildEvent(BuildEventType.ERROR, e.getMessage()); } catch (IOException e) { buildListener.handleBuildEvent(BuildEventType.ERROR, e.getMessage()); } return librariesToRemoveFromClasspath; } private void addTargetPlatformPlugin(XMLContent content, Plugin plugin, List<String> allLibraries) { File file = plugin.getFile(); if (file.isFile()) { content.append("<fileset file=\"" + file.getAbsolutePath() + "\" />"); allLibraries.add(file.getName()); } else { // TODO extracted plug-ins must be packaged } } private void addProject(XMLContent content, String tempDir, Plugin project, List<String> allLibraries) { String jarName = project.getIdentifier() + ".jar"; content.append("<fileset dir=\"" + tempDir + "\" includes=\"" + jarName + "\" />"); allLibraries.add(jarName); for (String lib : project.getLibs()) { String absoluteLibPath = project.getAbsoluteLibPath(lib); File libFile = new File(absoluteLibPath); content.append("<zipfileset dir=\"" + libFile.getParentFile().getAbsolutePath() + "\" includes=\"" + libFile.getName() + "\"/>"); allLibraries.add(libFile.getName()); } } }