Java tutorial
package org.codehaus.tycho.eclipsepackaging; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Properties; import java.util.Set; import java.util.StringTokenizer; import java.util.Map.Entry; import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.filefilter.FileFilterUtils; import org.apache.commons.io.filefilter.IOFileFilter; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.project.MavenProject; import org.codehaus.plexus.archiver.ArchiverException; import org.codehaus.plexus.archiver.util.ArchiveEntryUtils; import org.codehaus.plexus.archiver.zip.ZipArchiver; import org.codehaus.plexus.component.repository.exception.ComponentLookupException; import org.codehaus.plexus.util.xml.pull.XmlPullParserException; import org.codehaus.tycho.MavenSessionUtils; import org.codehaus.tycho.PlatformPropertiesUtils; import org.codehaus.tycho.TargetEnvironment; import org.codehaus.tycho.TargetPlatformConfiguration; import org.codehaus.tycho.TychoConstants; import org.codehaus.tycho.buildversion.VersioningHelper; import org.codehaus.tycho.maven.DependenciesReader; import org.codehaus.tycho.model.Feature; import org.codehaus.tycho.model.PluginRef; import org.codehaus.tycho.model.ProductConfiguration; import org.codehaus.tycho.model.Feature.FeatureRef; import org.codehaus.tycho.osgitools.features.FeatureDescription; import org.eclipse.osgi.service.resolver.BundleDescription; import org.eclipse.pde.internal.swt.tools.IconExe; import org.osgi.framework.Version; /** * @goal product-export */ public class ProductExportMojo extends AbstractTychoPackagingMojo { /** * The product configuration, a .product file. This file manages all aspects of a product definition from its * constituent plug-ins to configuration files to branding. * * @parameter expression="${productConfiguration}" */ private File productConfigurationFile; /** * @parameter expression="${productConfiguration}/../p2.inf" */ private File p2inf; /** * Location of generated .product file with all versions replaced with their expanded values. * * @parameter expression="${project.build.directory}/${project.artifactId}.product" */ private File expandedProductFile; /** * Parsed product configuration file */ private ProductConfiguration productConfiguration; /** * Build qualifier. Recommended way to set this parameter is using * build-qualifier goal. * * @parameter expression="${buildQualifier}" */ protected String qualifier; /** * @parameter */ private TargetEnvironment[] environments; /** * @component roleHint="eclipse-application" */ private DependenciesReader rcpDependencyReader; /** * @parameter expression="${tycho.product.createArchive}" default-value="true" */ private boolean createProductArchive; /** * @parameter default-value="false" */ private boolean includeSources; public void execute() throws MojoExecutionException, MojoFailureException { initializeProjectContext(); if (productConfigurationFile == null) { File basedir = project.getBasedir(); File productCfg = new File(basedir, project.getArtifactId() + ".product"); if (productCfg.exists()) { productConfigurationFile = productCfg; } } if (productConfigurationFile == null) { throw new MojoExecutionException("Product configuration file not expecified"); } if (!productConfigurationFile.exists()) { throw new MojoExecutionException( "Product configuration file not found " + productConfigurationFile.getAbsolutePath()); } try { getLog().debug("Parsing productConfiguration"); productConfiguration = ProductConfiguration.read(productConfigurationFile); } catch (IOException e) { throw new MojoExecutionException("Error reading product configuration file", e); } catch (XmlPullParserException e) { throw new MojoExecutionException("Error parsing product configuration file", e); } // build results will vary from system to system without explicit target environment configuration if (productConfiguration.includeLaunchers() && environments == null) { throw new MojoFailureException( "Product includes native launcher but no target environment was specified"); } for (TargetEnvironment environment : getEnvironments()) { File target = getTarget(environment); File targetEclipse = new File(target, "eclipse"); targetEclipse.mkdirs(); generateDotEclipseProduct(targetEclipse); generateConfigIni(environment, targetEclipse); includeRootFiles(environment, targetEclipse); if (productConfiguration.useFeatures()) { copyFeatures(environment, targetEclipse, productConfiguration.getFeatures()); } else { copyPlugins(environment, targetEclipse, productConfiguration.getPlugins()); } if (productConfiguration.includeLaunchers()) { copyExecutable(environment, targetEclipse); } if (createProductArchive) { createProductArchive(environment, target); } } Version productVersion = Version.parseVersion(productConfiguration.getVersion()); productVersion = VersioningHelper.expandVersion(productVersion, qualifier); productConfiguration.setVersion(productVersion.toString()); try { ProductConfiguration.write(productConfiguration, expandedProductFile); if (p2inf.canRead()) { FileUtils.copyFile(p2inf, new File(expandedProductFile.getParentFile(), p2inf.getName())); } } catch (IOException e) { throw new MojoExecutionException("Error writing expanded product configuration file", e); } if (!createProductArchive || environments != null) { project.getArtifact().setFile(expandedProductFile); } } private TargetEnvironment[] getEnvironments() { if (environments != null) { return environments; } TargetPlatformConfiguration configuration = (TargetPlatformConfiguration) project .getContextValue(TychoConstants.CTX_TARGET_PLATFORM_CONFIGURATION); return new TargetEnvironment[] { configuration.getEnvironment() }; } private File getTarget(TargetEnvironment environment) { File target; if (environments == null) { target = new File(project.getBuild().getDirectory(), "product"); } else { target = new File(project.getBuild().getDirectory(), toString(environment)); } target.mkdirs(); return target; } private String toString(TargetEnvironment environment) { StringBuilder sb = new StringBuilder(); sb.append(environment.getOs()).append('.').append(environment.getWs()).append('.') .append(environment.getArch()); if (environment.getNl() != null) { sb.append('.').append(environment.getNl()); } return sb.toString(); } @Override protected void initializeProjectContext() { bundleResolutionState = rcpDependencyReader.getBundleResolutionState(session, project); featureResolutionState = rcpDependencyReader.getFeatureResolutionState(session, project); } /** * Root files are files that must be packaged with an Eclipse install but are not features or plug-ins. These files * are added to the root or to a specified sub folder of the build. * * <pre> * root= * root.<confi>= * root.folder.<subfolder>= * root.<config>.folder.<subfolder>= * </pre> * * Not supported are the properties root.permissions and root.link. * * @see http://help.eclipse.org/ganymede/index.jsp?topic=/org.eclipse.pde.doc.user/tasks/pde_rootfiles.htm * * @throws MojoExecutionException */ private void includeRootFiles(TargetEnvironment environment, File target) throws MojoExecutionException { Properties properties = project.getProperties(); String generatedBuildProperties = properties.getProperty("generatedBuildProperties"); getLog().debug("includeRootFiles from " + generatedBuildProperties); if (generatedBuildProperties != null) { Properties rootProperties = new Properties(); try { rootProperties.load(new FileInputStream(new File(project.getBasedir(), generatedBuildProperties))); if (!rootProperties.isEmpty()) { String config = getConfig(environment); String root = "root"; String rootConfig = "root." + config; String rootFolder = "root.folder."; String rootConfigFolder = "root." + config + ".folder."; Set<Entry<Object, Object>> entrySet = rootProperties.entrySet(); for (Iterator iterator = entrySet.iterator(); iterator.hasNext();) { Entry<String, String> entry = (Entry<String, String>) iterator.next(); String key = entry.getKey().trim(); // root= if (root.equals(key)) { handleRootEntry(target, entry.getValue(), null); } // root.xxx= else if (rootConfig.equals(key)) { handleRootEntry(target, entry.getValue(), null); } // root.folder.yyy= else if (key.startsWith(rootFolder)) { String subFolder = entry.getKey().substring((rootFolder.length())); handleRootEntry(target, entry.getValue(), subFolder); } // root.xxx.folder.yyy= else if (key.startsWith(rootConfigFolder)) { String subFolder = entry.getKey().substring((rootConfigFolder.length())); handleRootEntry(target, entry.getValue(), subFolder); } else { getLog().debug("ignoring property " + entry.getKey() + "=" + entry.getValue()); } } } } catch (FileNotFoundException e) { throw new MojoExecutionException("Error including root files for product", e); } catch (IOException e) { throw new MojoExecutionException("Error including root files for product", e); } } } /** * @param rootFileEntry files and directories seperated by semicolons, the syntax is: * <ul> * <li>for a relative file: file:license.html,...</li> * <li>for a absolute file: absolute:file:/eclipse/about.html,...</li> * <li>for a relative folder: rootfiles,...</li> * <li>for a absolute folder: absolute:/eclipse/rootfiles,...</li> * </ul> * @param subFolder the sub folder to which the root file entries are copied to */ private void handleRootEntry(File target, String rootFileEntries, String subFolder) { StringTokenizer t = new StringTokenizer(rootFileEntries, ","); File destination = target; if (subFolder != null) { destination = new File(target, subFolder); } while (t.hasMoreTokens()) { String rootFileEntry = t.nextToken(); String fileName = rootFileEntry.trim(); boolean isAbsolute = false; if (fileName.startsWith("absolute:")) { isAbsolute = true; fileName = fileName.substring("absolute:".length()); } if (fileName.startsWith("file")) { fileName = fileName.substring("file:".length()); } File source = null; if (!isAbsolute) { source = new File(project.getBasedir(), fileName); } else { source = new File(fileName); } if (source.isFile()) { try { FileUtils.copyFileToDirectory(source, destination); } catch (IOException e) { e.printStackTrace(); } } else if (source.isDirectory()) { try { FileUtils.copyDirectoryToDirectory(source, destination); } catch (IOException e) { e.printStackTrace(); } } else { getLog().warn("Skipping root entry " + rootFileEntry); } } } private String getConfig(TargetEnvironment environment) { String os = environment.getOs(); String ws = environment.getWs(); String arch = environment.getArch(); StringBuffer config = new StringBuffer(ws).append(".").append(os).append(".").append(arch); return config.toString(); } private void createProductArchive(TargetEnvironment environment, File target) throws MojoExecutionException { ZipArchiver zipper; try { zipper = (ZipArchiver) plexus.lookup(ZipArchiver.ROLE, "zip"); } catch (ComponentLookupException e) { throw new MojoExecutionException("Unable to resolve ZipArchiver", e); } String classifier = toString(environment); StringBuilder filename = new StringBuilder(project.getBuild().getFinalName()); if (environments != null) { filename.append('-').append(classifier); } filename.append(".zip"); File destFile = new File(project.getBuild().getDirectory(), filename.toString()); try { zipper.addDirectory(target); zipper.setDestFile(destFile); zipper.createArchive(); } catch (Exception e) { throw new MojoExecutionException("Error packing product", e); } if (environments == null) { // main artifact project.getArtifact().setFile(destFile); } else { projectHelper.attachArtifact(project, destFile, classifier); } } private boolean isEclipse32Platform() throws MojoFailureException { BundleDescription runtime = bundleResolutionState.getSystemBundle(); if (runtime == null) { throw new MojoFailureException("Could not obtain system bundle"); } if (!"org.eclipse.osgi".equals(runtime.getSymbolicName())) { throw new MojoFailureException("Unsupported OSGi platform " + runtime.getSymbolicName()); } Version osgiVersion = runtime.getVersion(); return osgiVersion.getMajor() == 3 && osgiVersion.getMinor() == 2; } private void generateDotEclipseProduct(File target) throws MojoExecutionException { getLog().debug("Generating .eclipseproduct"); Properties props = new Properties(); setPropertyIfNotNull(props, "version", productConfiguration.getVersion()); setPropertyIfNotNull(props, "name", productConfiguration.getName()); setPropertyIfNotNull(props, "id", productConfiguration.getId()); File eclipseproduct = new File(target, ".eclipseproduct"); try { FileOutputStream fos = new FileOutputStream(eclipseproduct); props.store(fos, "Eclipse Product File"); fos.close(); } catch (IOException e) { throw new MojoExecutionException("Error creating .eclipseproduct file.", e); } } private void generateConfigIni(TargetEnvironment environment, File target) throws MojoExecutionException, MojoFailureException { getLog().debug("Generating config.ini"); Properties props = new Properties(); String id = productConfiguration.getId(); if (id != null) { String splash = id.split("\\.")[0]; setPropertyIfNotNull(props, "osgi.splashPath", "platform:/base/plugins/" + splash); } setPropertyIfNotNull(props, "eclipse.product", id); // TODO check if there are any other levels setPropertyIfNotNull(props, "osgi.bundles.defaultStartLevel", "4"); if (productConfiguration.useFeatures()) { setPropertyIfNotNull(props, "osgi.bundles", getFeaturesOsgiBundles()); } else { setPropertyIfNotNull(props, "osgi.bundles", getPluginsOsgiBundles(environment)); } File configsFolder = new File(target, "configuration"); configsFolder.mkdirs(); File configIni = new File(configsFolder, "config.ini"); try { FileOutputStream fos = new FileOutputStream(configIni); props.store(fos, "Product Runtime Configuration File"); fos.close(); } catch (IOException e) { throw new MojoExecutionException("Error creating .eclipseproduct file.", e); } } private String getFeaturesOsgiBundles() { // TODO how does eclipse know this? return "org.eclipse.equinox.common@2:start,org.eclipse.update.configurator@3:start,org.eclipse.core.runtime@start"; } private String getPluginsOsgiBundles(TargetEnvironment environment) throws MojoFailureException { List<PluginRef> plugins = productConfiguration.getPlugins(); StringBuilder buf = new StringBuilder(plugins.size() * 10); for (PluginRef plugin : plugins) { // reverse engineering discovered // this plugin is not present on config.ini, and if so nothing // starts if ("org.eclipse.osgi".equals(plugin.getId())) { continue; } if (buf.length() != 0) { buf.append(','); } buf.append(plugin.getId()); // reverse engineering discovered // the final bundle has @start after runtime if ("org.eclipse.core.runtime".equals(plugin.getId())) { buf.append("@start"); } if (isEclipse32Platform() && "org.eclipse.equinox.common".equals(plugin.getId())) { buf.append("@2:start"); } } // required plugins, RCP didn't start without both if (!isEclipse32Platform()) { if (buf.length() != 0) { buf.append(','); } String os = environment.getOs(); String ws = environment.getWs(); String arch = environment.getArch(); buf.append("org.eclipse.equinox.launcher,"); buf.append("org.eclipse.equinox.launcher." + ws + "." + os + "." + arch); } return buf.toString(); } private void copyFeatures(TargetEnvironment environment, File target, List<FeatureRef> features) throws MojoExecutionException { getLog().debug("copying " + features.size() + " features "); for (FeatureRef feature : features) { copyFeature(environment, target, feature); } } private void copyFeature(TargetEnvironment environment, File target, FeatureRef feature) throws MojoExecutionException { String featureId = feature.getId(); String featureVersion = feature.getVersion(); FeatureDescription featureDescription = featureResolutionState.getFeature(featureId, featureVersion); if (featureDescription == null) { throw new MojoExecutionException("Unable to resolve feature " + featureId + "_" + featureVersion); } featureVersion = VersioningHelper.getExpandedVersion(session, featureDescription); Feature featureRef = featureDescription.getFeature(); MavenProject project = MavenSessionUtils.getMavenProject(session, featureDescription.getLocation()); de.schlichtherle.io.File source; if (project == null) { getLog().debug("feature = bundle: " + featureDescription.getLocation()); source = new de.schlichtherle.io.File(featureDescription.getLocation()); } else { getLog().debug("feature = project: " + project.getArtifact()); source = new de.schlichtherle.io.File(project.getArtifact().getFile()); } File targetFolder = new File(target, "features/" + featureRef.getId() + "_" + featureVersion); targetFolder.mkdirs(); source.copyAllTo(targetFolder); List<FeatureRef> featureRefs = featureRef.getIncludedFeatures(); for (FeatureRef fRef : featureRefs) { copyFeature(environment, target, fRef); } // copy all plugins from all features List<PluginRef> pluginRefs = featureRef.getPlugins(); for (PluginRef pluginRef : pluginRefs) { if (matchTargetEnvironment(environment, pluginRef)) { copyPlugin(target, pluginRef); } } } private boolean matchTargetEnvironment(TargetEnvironment environment, PluginRef pluginRef) { String pluginOs = pluginRef.getOs(); String pluginWs = pluginRef.getWs(); String pluginArch = pluginRef.getArch(); if (environments == null) { // no target environment, only include environment independent plugins return pluginOs == null && pluginWs == null && pluginArch == null; } String os = environment.getOs(); String ws = environment.getWs(); String arch = environment.getArch(); return (pluginOs == null || os.equals(pluginOs)) && // (pluginWs == null || ws.equals(pluginWs)) && // (pluginArch == null || arch.equals(pluginArch)); } private void copyPlugins(TargetEnvironment environment, File pluginsFolder, Collection<PluginRef> plugins) throws MojoExecutionException, MojoFailureException { getLog().debug("copying " + plugins.size() + " plugins "); for (PluginRef plugin : plugins) { copyPlugin(pluginsFolder, plugin); } // required plugins, RCP didn't start without both if (!isEclipse32Platform()) { copyPlugin(pluginsFolder, newPluginRef("org.eclipse.equinox.launcher", null, false)); String os = environment.getOs(); String ws = environment.getWs(); String arch = environment.getArch(); // for Mac OS X there is no org.eclipse.equinox.launcher.carbon.macosx.x86 folder, // only a org.eclipse.equinox.launcher.carbon.macosx folder. // see http://jira.codehaus.org/browse/MNGECLIPSE-1075 if (PlatformPropertiesUtils.OS_MACOSX.equals(os)) { copyPlugin(pluginsFolder, newPluginRef("org.eclipse.equinox.launcher." + ws + "." + os, null, false)); } else { copyPlugin(pluginsFolder, newPluginRef("org.eclipse.equinox.launcher." + ws + "." + os + "." + arch, null, false)); } } } private PluginRef newPluginRef(String id, String version, boolean unpack) { PluginRef plugin = new PluginRef("plugin"); plugin.setId(id); if (version != null) { plugin.setVersion(version); } plugin.setUnpack(unpack); return plugin; } private String copyPlugin(File target, PluginRef plugin) throws MojoExecutionException { String bundleId = plugin.getId(); String bundleVersion = plugin.getVersion(); getLog().debug("Copying plugin " + bundleId + "_" + bundleVersion); if (bundleVersion == null || "0.0.0".equals(bundleVersion)) { bundleVersion = TychoConstants.HIGHEST_VERSION; } BundleDescription bundle = bundleResolutionState.getBundle(bundleId, bundleVersion); if (bundle == null) { throw new MojoExecutionException("Plugin '" + bundleId + "_" + bundleVersion + "' not found!"); } String sourceBundle = bundleResolutionState.getManifestAttribute(bundle, "Eclipse-SourceBundle"); if (!includeSources && sourceBundle != null && sourceBundle.trim().length() > 0) { getLog().debug("Ignoring source bundle " + bundleId + "_" + bundleVersion); return null; } MavenProject bundleProject = MavenSessionUtils.getMavenProject(session, bundle.getLocation()); File source; if (bundleProject != null) { source = bundleProject.getArtifact().getFile(); } else { source = new File(bundle.getLocation()); } bundleVersion = VersioningHelper.getExpandedVersion(session, bundle); File pluginsFolder = new File(target, "plugins"); File targetFolder = new File(pluginsFolder, bundleId + "_" + bundleVersion + ".jar"); if (source.isDirectory()) { copyToDirectory(source, pluginsFolder); } else if (plugin.isUnpack()) { // when unpacked doesn't have .jar extension String path = targetFolder.getAbsolutePath(); path = path.substring(0, path.length() - 4); targetFolder = new File(path); targetFolder.mkdirs(); new de.schlichtherle.io.File(source).copyAllTo(targetFolder); // unpackToDirectory(source, target); } else { copyToFile(source, targetFolder); } return bundleVersion; } private void copyToFile(File source, File target) throws MojoExecutionException { try { target.getParentFile().mkdirs(); if (source.isFile()) { FileUtils.copyFile(source, target); } else if (source.isDirectory()) { FileUtils.copyDirectory(source, target); } else { getLog().warn("Skipping bundle " + source.getAbsolutePath()); } } catch (IOException e) { throw new MojoExecutionException("Unable to copy " + source.getName(), e); } } private void copyToDirectory(File source, File targetFolder) throws MojoExecutionException { try { if (source.isFile()) { FileUtils.copyFileToDirectory(source, targetFolder); } else if (source.isDirectory()) { FileUtils.copyDirectoryToDirectory(source, targetFolder); } else { getLog().warn("Skipping bundle " + source.getAbsolutePath()); } } catch (IOException e) { throw new MojoExecutionException("Unable to copy " + source.getName(), e); } } private void copyExecutable(TargetEnvironment environment, File target) throws MojoExecutionException, MojoFailureException { getLog().debug("Creating launcher"); FeatureDescription feature; // eclipse 3.2 if (isEclipse32Platform()) { feature = featureResolutionState.getFeature("org.eclipse.platform.launchers", null); } else { feature = featureResolutionState.getFeature("org.eclipse.equinox.executable", null); } if (feature == null) { throw new MojoExecutionException("RPC delta feature not found!"); } File location = feature.getLocation(); String os = environment.getOs(); String ws = environment.getWs(); String arch = environment.getArch(); File osLauncher = new File(location, "bin/" + ws + "/" + os + "/" + arch); try { // Don't copy eclipsec file IOFileFilter eclipsecFilter = FileFilterUtils .notFileFilter(FileFilterUtils.prefixFileFilter("eclipsec")); FileUtils.copyDirectory(osLauncher, target, eclipsecFilter); } catch (IOException e) { throw new MojoExecutionException("Unable to copy launcher executable", e); } File launcher = getLauncher(environment, target); // make launcher executable try { getLog().debug("running chmod"); ArchiveEntryUtils.chmod(launcher, 0755, null); } catch (ArchiverException e) { throw new MojoExecutionException("Unable to make launcher being executable", e); } File osxEclipseApp = null; // Rename launcher if (productConfiguration.getLauncher() != null && productConfiguration.getLauncher().getName() != null) { String launcherName = productConfiguration.getLauncher().getName(); String newName = launcherName; // win32 has extensions if (PlatformPropertiesUtils.OS_WIN32.equals(os)) { String extension = FilenameUtils.getExtension(launcher.getAbsolutePath()); newName = launcherName + "." + extension; } else if (PlatformPropertiesUtils.OS_MACOSX.equals(os)) { // the launcher is renamed to "eclipse", because // this is the value of the CFBundleExecutable // property within the Info.plist file. // see http://jira.codehaus.org/browse/MNGECLIPSE-1087 newName = "eclipse"; } getLog().debug("Renaming launcher to " + newName); File newLauncher = new File(launcher.getParentFile(), newName); if (!launcher.renameTo(newLauncher)) { throw new MojoExecutionException("Could not rename native launcher to " + newName); } launcher = newLauncher; // macosx: the *.app directory is renamed to the // product configuration launcher name // see http://jira.codehaus.org/browse/MNGECLIPSE-1087 if (PlatformPropertiesUtils.OS_MACOSX.equals(os)) { newName = launcherName + ".app"; getLog().debug("Renaming Eclipse.app to " + newName); File eclipseApp = new File(target, "Eclipse.app"); osxEclipseApp = new File(eclipseApp.getParentFile(), newName); eclipseApp.renameTo(osxEclipseApp); // ToDo: the "Info.plist" file must be patched, so that the // property "CFBundleName" has the value of the // launcherName variable } } // icons if (productConfiguration.getLauncher() != null) { if (PlatformPropertiesUtils.OS_WIN32.equals(os)) { getLog().debug("win32 icons"); List<String> icons = productConfiguration.getW32Icons(); if (icons != null) { getLog().debug(icons.toString()); try { String[] args = new String[icons.size() + 1]; args[0] = launcher.getAbsolutePath(); int pos = 1; for (String string : icons) { args[pos] = string; pos++; } IconExe.main(args); } catch (Exception e) { throw new MojoExecutionException("Unable to replace icons", e); } } else { getLog().debug("icons is null"); } } else if (PlatformPropertiesUtils.OS_LINUX.equals(os)) { String icon = productConfiguration.getLinuxIcon(); if (icon != null) { try { File sourceXPM = new File(project.getBasedir(), removeFirstSegment(icon)); File targetXPM = new File(launcher.getParentFile(), "icon.xpm"); FileUtils.copyFile(sourceXPM, targetXPM); } catch (IOException e) { throw new MojoExecutionException("Unable to create ico.xpm", e); } } } else if (PlatformPropertiesUtils.OS_MACOSX.equals(os)) { String icon = productConfiguration.getMacIcon(); if (icon != null) { try { if (osxEclipseApp == null) { osxEclipseApp = new File(target, "Eclipse.app"); } File source = new File(project.getBasedir(), removeFirstSegment(icon)); File targetFolder = new File(osxEclipseApp, "/Resources/" + source.getName()); FileUtils.copyFile(source, targetFolder); // Modify eclipse.ini File iniFile = new File(osxEclipseApp + "/Contents/MacOS/eclipse.ini"); if (iniFile.exists() && iniFile.canWrite()) { StringBuffer buf = new StringBuffer(FileUtils.readFileToString(iniFile)); int pos = buf.indexOf("Eclipse.icns"); buf.replace(pos, pos + 12, source.getName()); FileUtils.writeStringToFile(iniFile, buf.toString()); } } catch (Exception e) { throw new MojoExecutionException("Unable to create macosx icon", e); } } } } // eclipse 3.2 if (isEclipse32Platform()) { File startUpJar = new File(location, "bin/startup.jar"); try { FileUtils.copyFileToDirectory(startUpJar, target); } catch (IOException e) { throw new MojoExecutionException("Unable to copy startup.jar executable", e); } } } private String removeFirstSegment(String path) { int idx = path.indexOf('/'); if (idx < 0) { return null; } if (idx == 0) { idx = path.indexOf('/', 1); } if (idx < 0) { return null; } return path.substring(idx); } private File getLauncher(TargetEnvironment environment, File target) throws MojoExecutionException { String os = environment.getOs(); if (PlatformPropertiesUtils.OS_WIN32.equals(os)) { return new File(target, "launcher.exe"); } if (PlatformPropertiesUtils.OS_LINUX.equals(os) || PlatformPropertiesUtils.OS_SOLARIS.equals(os) || PlatformPropertiesUtils.OS_HPUX.equals(os) || PlatformPropertiesUtils.OS_AIX.equals(os)) { return new File(target, "launcher"); } if (PlatformPropertiesUtils.OS_MACOSX.equals(os)) { // TODO need to check this at macos return new File(target, "Eclipse.app/Contents/MacOS/launcher"); } throw new MojoExecutionException("Unexpected OS: " + os); } private void setPropertyIfNotNull(Properties properties, String key, String value) { if (value != null) { properties.setProperty(key, value); } } }