diff --git a/tycho-bundles/org.eclipse.tycho.core.shared/src/main/java/org/eclipse/tycho/core/resolver/shared/PlatformPropertiesUtils.java b/tycho-bundles/org.eclipse.tycho.core.shared/src/main/java/org/eclipse/tycho/core/resolver/shared/PlatformPropertiesUtils.java index dc32401c..62ebe2ed 100644 --- a/tycho-bundles/org.eclipse.tycho.core.shared/src/main/java/org/eclipse/tycho/core/resolver/shared/PlatformPropertiesUtils.java +++ b/tycho-bundles/org.eclipse.tycho.core.shared/src/main/java/org/eclipse/tycho/core/resolver/shared/PlatformPropertiesUtils.java @@ -1,208 +1,219 @@ /******************************************************************************* * Copyright (c) 2006 IBM Corporation and others. * 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: * Andrew Niefer - IBM Corporation - initial API and implementation * Sonatype Inc. - ongoing development *******************************************************************************/ package org.eclipse.tycho.core.resolver.shared; import java.util.Properties; /** * Creative copy&paste from org.eclipse.equinox.internal.launcher.Constants and * org.eclipse.equinox.launcher.Main. * * @author aniefer * @author igor * */ public class PlatformPropertiesUtils { public static final String INTERNAL_ARCH_I386 = "i386"; //$NON-NLS-1$ public static final String INTERNAL_AMD64 = "amd64"; //$NON-NLS-1$ public static final String INTERNAL_OS_SUNOS = "SunOS"; //$NON-NLS-1$ public static final String INTERNAL_OS_LINUX = "Linux"; //$NON-NLS-1$ public static final String INTERNAL_OS_MACOSX = "Mac OS"; //$NON-NLS-1$ public static final String INTERNAL_OS_AIX = "AIX"; //$NON-NLS-1$ public static final String INTERNAL_OS_HPUX = "HP-UX"; //$NON-NLS-1$ public static final String INTERNAL_OS_QNX = "QNX"; //$NON-NLS-1$ + public static final String INTERNAL_OS_FREEBSD = "FreeBSD"; //$NON-NLS-1$ public static final String ARCH_X86 = "x86";//$NON-NLS-1$ public static final String ARCH_X86_64 = "x86_64";//$NON-NLS-1$ public static final String ARCH_PPC = "ppc";//$NON-NLS-1$ public final static String OSGI_WS = "osgi.ws"; //$NON-NLS-1$ public final static String OSGI_OS = "osgi.os"; //$NON-NLS-1$ public final static String OSGI_ARCH = "osgi.arch"; //$NON-NLS-1$ public final static String OSGI_NL = "osgi.nl"; //$NON-NLS-1$ private static final class Constants extends PlatformPropertiesUtils { } /** * Constant string (value "win32") indicating the platform is running on a Window 32-bit * operating system (e.g., Windows 98, NT, 2000). */ public static final String OS_WIN32 = "win32";//$NON-NLS-1$ /** * Constant string (value "linux") indicating the platform is running on a Linux-based operating * system. */ public static final String OS_LINUX = "linux";//$NON-NLS-1$ /** * Constant string (value "aix") indicating the platform is running on an AIX-based operating * system. */ public static final String OS_AIX = "aix";//$NON-NLS-1$ /** * Constant string (value "solaris") indicating the platform is running on a Solaris-based * operating system. */ public static final String OS_SOLARIS = "solaris";//$NON-NLS-1$ /** * Constant string (value "hpux") indicating the platform is running on an HP/UX-based operating * system. */ public static final String OS_HPUX = "hpux";//$NON-NLS-1$ /** * Constant string (value "qnx") indicating the platform is running on a QNX-based operating * system. */ public static final String OS_QNX = "qnx";//$NON-NLS-1$ /** * Constant string (value "macosx") indicating the platform is running on a Mac OS X operating * system. */ public static final String OS_MACOSX = "macosx";//$NON-NLS-1$ + /** + * Constant string (value "freebsd") indicating the platform is running on a FreeBSD operating + * system. + */ + public static final String OS_FREEBSD = "freebsd";//$NON-NLS-1$ + /** * Constant string (value "unknown") indicating the platform is running on a machine running an * unknown operating system. */ public static final String OS_UNKNOWN = "unknown";//$NON-NLS-1$ /** * Constant string (value "win32") indicating the platform is running on a machine using the * Windows windowing system. */ public static final String WS_WIN32 = "win32";//$NON-NLS-1$ /** * Constant string (value "wpf") indicating the platform is running on a machine using the * Windows Presendation Foundation system. */ public static final String WS_WPF = "wpf";//$NON-NLS-1$ /** * Constant string (value "motif") indicating the platform is running on a machine using the * Motif windowing system. */ public static final String WS_MOTIF = "motif";//$NON-NLS-1$ /** * Constant string (value "gtk") indicating the platform is running on a machine using the GTK * windowing system. */ public static final String WS_GTK = "gtk";//$NON-NLS-1$ /** * Constant string (value "photon") indicating the platform is running on a machine using the * Photon windowing system. */ public static final String WS_PHOTON = "photon";//$NON-NLS-1$ /** * Constant string (value "carbon") indicating the platform is running on a machine using the * Carbon windowing system (Mac OS X). */ public static final String WS_CARBON = "carbon";//$NON-NLS-1$ /** * Constant string (value "cocoa") indicating the platform is running on a machine using the * Carbon windowing system (Mac OS X). */ public static final String WS_COCOA = "cocoa";//$NON-NLS-1$ /** * Constant string (value "unknown") indicating the platform is running on a machine running an * unknown windowing system. */ public static final String WS_UNKNOWN = "unknown";//$NON-NLS-1$ public static String getWS(Properties properties) { String ws = properties.getProperty(OSGI_WS); if (ws != null) return ws; String osName = getOS(properties); if (osName.equals(Constants.OS_WIN32)) return Constants.WS_WIN32; if (osName.equals(Constants.OS_LINUX)) return Constants.WS_GTK; + if (osName.equals(Constants.OS_FREEBSD)) + return Constants.WS_GTK; if (osName.equals(Constants.OS_MACOSX)) { String arch = getArch(properties); if (ARCH_X86_64.equals(arch)) return Constants.WS_COCOA; return Constants.WS_CARBON; } if (osName.equals(Constants.OS_HPUX)) return Constants.WS_MOTIF; if (osName.equals(Constants.OS_AIX)) return Constants.WS_MOTIF; if (osName.equals(Constants.OS_SOLARIS)) return Constants.WS_GTK; if (osName.equals(Constants.OS_QNX)) return Constants.WS_PHOTON; return Constants.WS_UNKNOWN; } public static String getOS(Properties properties) { String os = properties.getProperty(OSGI_OS); if (os != null) return os; String osName = System.getProperties().getProperty("os.name"); //$NON-NLS-1$ if (osName.regionMatches(true, 0, Constants.OS_WIN32, 0, 3)) return Constants.OS_WIN32; // EXCEPTION: All mappings of SunOS convert to Solaris if (osName.equalsIgnoreCase(Constants.INTERNAL_OS_SUNOS)) return Constants.OS_SOLARIS; if (osName.equalsIgnoreCase(Constants.INTERNAL_OS_LINUX)) return Constants.OS_LINUX; if (osName.equalsIgnoreCase(Constants.INTERNAL_OS_QNX)) return Constants.OS_QNX; if (osName.equalsIgnoreCase(Constants.INTERNAL_OS_AIX)) return Constants.OS_AIX; if (osName.equalsIgnoreCase(Constants.INTERNAL_OS_HPUX)) return Constants.OS_HPUX; + if (osName.equalsIgnoreCase(Constants.INTERNAL_OS_FREEBSD)) + return Constants.OS_FREEBSD; // os.name on Mac OS can be either Mac OS or Mac OS X if (osName.regionMatches(true, 0, Constants.INTERNAL_OS_MACOSX, 0, Constants.INTERNAL_OS_MACOSX.length())) return Constants.OS_MACOSX; return Constants.OS_UNKNOWN; } public static String getArch(Properties properties) { String arch = properties.getProperty(OSGI_ARCH); if (arch != null) return arch; String name = System.getProperties().getProperty("os.arch");//$NON-NLS-1$ // Map i386 architecture to x86 if (name.equalsIgnoreCase(Constants.INTERNAL_ARCH_I386)) return Constants.ARCH_X86; // Map amd64 architecture to x86_64 else if (name.equalsIgnoreCase(Constants.INTERNAL_AMD64)) return Constants.ARCH_X86_64; return name; } } diff --git a/tycho-metadata-model/src/main/java/org/eclipse/tycho/model/Launcher.java b/tycho-metadata-model/src/main/java/org/eclipse/tycho/model/Launcher.java index 5b525410..7f4f9259 100644 --- a/tycho-metadata-model/src/main/java/org/eclipse/tycho/model/Launcher.java +++ b/tycho-metadata-model/src/main/java/org/eclipse/tycho/model/Launcher.java @@ -1,134 +1,146 @@ /******************************************************************************* * Copyright (c) 2008, 2011 Sonatype Inc. and others. * 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: * Sonatype Inc. - initial API and implementation *******************************************************************************/ package org.eclipse.tycho.model; import java.util.Collections; import java.util.HashMap; import java.util.Map; import de.pdark.decentxml.Element; public class Launcher { public static final String ICON_LINUX = "icon"; public static final String ICON_MAC = ICON_LINUX; + public static final String ICON_FREEBSD = ICON_LINUX; + public static final String ICON_WINDOWS_ICO_PATH = "path"; public static final String ICON_WINDOWS_EXTRA_LARGE_HIGH = "winExtraLargeHigh"; public static final String ICON_WINDOWS_LARGE_LOW = "winLargeLow"; public static final String ICON_WINDOWS_LARGE_HIGH = "winLargeHigh"; public static final String ICON_WINDOWS_MEDIUM_LOW = "winMediumLow"; public static final String ICON_WINDOWS_MEDIUM_HIGH = "winMediumHigh"; public static final String ICON_WINDOWS_SMALL_LOW = "winSmallLow"; public static final String ICON_WINDOWS_SMALL_HIGH = "winSmallHigh"; public static final String ICON_SOLARIS_TINY = "solarisTiny"; public static final String ICON_SOLARIS_SMALL = "solarisSmall"; public static final String ICON_SOLARIS_MEDIUM = "solarisMedium"; public static final String ICON_SOLARIS_LARGE = "solarisLarge"; private Element dom; public Launcher(Element domLauncher) { this.dom = domLauncher; } public String getName() { return dom.getAttributeValue("name"); } public Map getLinuxIcon() { Element linuxDom = dom.getChild("linux"); if (linuxDom == null) { return Collections.emptyMap(); } Map linux = new HashMap<>(); putIfNotNull(linux, ICON_LINUX, linuxDom.getAttributeValue(ICON_LINUX)); return Collections.unmodifiableMap(linux); } + public Map getFreeBSDIcon() { + Element freebsdDom = dom.getChild("freebsd"); + if (freebsdDom == null) { + return Collections.emptyMap(); + } + Map freebsd = new HashMap<>(1); + putIfNotNull(freebsd, ICON_FREEBSD, freebsdDom.getAttributeValue(ICON_FREEBSD)); + return Collections.unmodifiableMap(freebsd); + } + public Map getMacosxIcon() { Element macosxDom = dom.getChild("macosx"); if (macosxDom == null) { return Collections.emptyMap(); } Map mac = new HashMap<>(); putIfNotNull(mac, ICON_LINUX, macosxDom.getAttributeValue(ICON_LINUX)); return Collections.unmodifiableMap(mac); } public Map getSolarisIcon() { Element solarisDom = dom.getChild("solaris"); if (solarisDom == null) { return Collections.emptyMap(); } Map solaris = new HashMap<>(); putIfNotNull(solaris, ICON_SOLARIS_LARGE, solarisDom.getAttributeValue(ICON_SOLARIS_LARGE)); putIfNotNull(solaris, ICON_SOLARIS_MEDIUM, solarisDom.getAttributeValue(ICON_SOLARIS_MEDIUM)); putIfNotNull(solaris, ICON_SOLARIS_SMALL, solarisDom.getAttributeValue(ICON_SOLARIS_SMALL)); putIfNotNull(solaris, ICON_SOLARIS_TINY, solarisDom.getAttributeValue(ICON_SOLARIS_TINY)); return Collections.unmodifiableMap(solaris); } public boolean getWindowsUseIco() { Element winDom = dom.getChild("win"); if (winDom == null) { return false; } boolean useIco = Boolean.parseBoolean(winDom.getAttributeValue("useIco")); return useIco; } public Map getWindowsIcon() { Element winDom = dom.getChild("win"); if (winDom == null) { return Collections.emptyMap(); } Map windows = new HashMap<>(); if (getWindowsUseIco()) { Element ico = winDom.getChild("ico"); if (ico != null) { putIfNotNull(windows, ICON_WINDOWS_ICO_PATH, ico.getAttributeValue(ICON_WINDOWS_ICO_PATH)); } } else { Element bmp = winDom.getChild("bmp"); if (bmp != null) { putIfNotNull(windows, ICON_WINDOWS_SMALL_HIGH, bmp.getAttributeValue(ICON_WINDOWS_SMALL_HIGH)); putIfNotNull(windows, ICON_WINDOWS_SMALL_LOW, bmp.getAttributeValue(ICON_WINDOWS_SMALL_LOW)); putIfNotNull(windows, ICON_WINDOWS_MEDIUM_HIGH, bmp.getAttributeValue(ICON_WINDOWS_MEDIUM_HIGH)); putIfNotNull(windows, ICON_WINDOWS_MEDIUM_LOW, bmp.getAttributeValue(ICON_WINDOWS_MEDIUM_LOW)); putIfNotNull(windows, ICON_WINDOWS_LARGE_HIGH, bmp.getAttributeValue(ICON_WINDOWS_LARGE_HIGH)); putIfNotNull(windows, ICON_WINDOWS_LARGE_LOW, bmp.getAttributeValue(ICON_WINDOWS_LARGE_LOW)); putIfNotNull(windows, ICON_WINDOWS_EXTRA_LARGE_HIGH, bmp.getAttributeValue(ICON_WINDOWS_EXTRA_LARGE_HIGH)); } } return Collections.unmodifiableMap(windows); } private void putIfNotNull(Map map, String key, String value) { if (value != null) { map.put(key, value); } } } diff --git a/tycho-metadata-model/src/main/java/org/eclipse/tycho/model/ProductConfiguration.java b/tycho-metadata-model/src/main/java/org/eclipse/tycho/model/ProductConfiguration.java index c450a741..7363c330 100644 --- a/tycho-metadata-model/src/main/java/org/eclipse/tycho/model/ProductConfiguration.java +++ b/tycho-metadata-model/src/main/java/org/eclipse/tycho/model/ProductConfiguration.java @@ -1,342 +1,362 @@ /******************************************************************************* * Copyright (c) 2008, 2014 Sonatype Inc. and others. * 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: * Sonatype Inc. - initial API and implementation *******************************************************************************/ package org.eclipse.tycho.model; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Writer; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.codehaus.plexus.util.IOUtil; import de.pdark.decentxml.Attribute; import de.pdark.decentxml.Document; import de.pdark.decentxml.Element; import de.pdark.decentxml.Node; import de.pdark.decentxml.XMLIOSource; import de.pdark.decentxml.XMLParser; import de.pdark.decentxml.XMLWriter; /** * As of eclipse 3.5.1, file format does not seem to be documented. There are most likely multiple * parser implementations. org.eclipse.equinox.internal.p2.publisher.eclipse.ProductFile */ public class ProductConfiguration { private static final XMLParser parser = new XMLParser(); public static ProductConfiguration read(File file) throws IOException { InputStream is = new BufferedInputStream(new FileInputStream(file)); return read(is); // closes the stream } public static ProductConfiguration read(InputStream input) throws IOException { try { return new ProductConfiguration(parser.parse(new XMLIOSource(input))); } finally { IOUtil.close(input); } } public static void write(ProductConfiguration product, File file) throws IOException { OutputStream os = new BufferedOutputStream(new FileOutputStream(file)); Document document = product.document; try { String enc = document.getEncoding() != null ? document.getEncoding() : "UTF-8"; Writer w = new OutputStreamWriter(os, enc); XMLWriter xw = new XMLWriter(w); try { document.toXML(xw); } finally { xw.flush(); } } finally { IOUtil.close(os); } } private Element dom; private Document document; public ProductConfiguration(Document document) { this.document = document; this.dom = document.getRootElement(); } public String getProduct() { return dom.getAttributeValue("id"); } public String getApplication() { return dom.getAttributeValue("application"); } public List getFeatures() throws ModelFileSyntaxException { Element featuresDom = dom.getChild("features"); if (featuresDom == null) { return Collections.emptyList(); } ArrayList features = new ArrayList<>(); for (Element featureDom : featuresDom.getChildren()) { features.add(parseFeature(featureDom)); } return Collections.unmodifiableList(features); } private static FeatureRef parseFeature(Element featureDom) throws ModelFileSyntaxException { // knowing the name of the parent element is useful for the error message, so we check the name here if (!"feature".equals(featureDom.getName())) { throw new ModelFileSyntaxException("Invalid child element \"" + featureDom.getName() + "\" in \"features\""); } return new FeatureRef(featureDom); } // TODO 428889 remove once p2 handles installMode="root" features public void removeRootInstalledFeatures() { Element featuresDom = dom.getChild("features"); if (featuresDom != null) { for (int childIx = featuresDom.getNodes().size() - 1; childIx > 0; --childIx) { Node nodeDom = featuresDom.getNode(childIx); if (nodeDom instanceof Element) { Element elementDom = (Element) nodeDom; if (parseFeature(elementDom).getInstallMode() == FeatureRef.InstallMode.root) { featuresDom.removeNode(childIx); } } } } } public String getId() { return dom.getAttributeValue("uid"); } public Launcher getLauncher() { Element domLauncher = dom.getChild("launcher"); if (domLauncher == null) { return null; } return new Launcher(domLauncher); } public String getName() { return dom.getAttributeValue("name"); } public List getPlugins() { Element pluginsDom = dom.getChild("plugins"); if (pluginsDom == null) { return Collections.emptyList(); } ArrayList plugins = new ArrayList<>(); for (Element pluginDom : pluginsDom.getChildren("plugin")) { plugins.add(new PluginRef(pluginDom)); } return Collections.unmodifiableList(plugins); } public boolean useFeatures() { return Boolean.parseBoolean(dom.getAttributeValue("useFeatures")); } public boolean includeLaunchers() { String attribute = dom.getAttributeValue("includeLaunchers"); return attribute == null ? true : Boolean.parseBoolean(attribute); } public String getVersion() { return dom.getAttributeValue("version"); } public void setVersion(String version) { dom.setAttribute("version", version); } public List getW32Icons() { Element domLauncher = dom.getChild("launcher"); if (domLauncher == null) { return null; } Element win = domLauncher.getChild("win"); if (win == null) { return null; } List icons = new ArrayList<>(); String useIco = win.getAttributeValue("useIco"); if (Boolean.valueOf(useIco)) { // for (Element ico : win.getChildren("ico")) { Element ico = win.getChild("ico"); // should be only 1 icons.add(ico.getAttributeValue("path")); } } else { for (Element bmp : win.getChildren("bmp")) { List attibuteNames = bmp.getAttributes(); if (attibuteNames != null && attibuteNames.size() > 0) icons.add(attibuteNames.get(0).getValue()); } } return icons; } public String getLinuxIcon() { Element domLauncher = dom.getChild("launcher"); if (domLauncher == null) { return null; } Element linux = domLauncher.getChild("linux"); if (linux == null) { return null; } return linux.getAttributeValue("icon"); } + public String getFreeBSDIcon() { + Element domLauncher = dom.getChild("launcher"); + if (domLauncher == null) { + + return null; + } + Element freebsd = domLauncher.getChild("freebsd"); + if (freebsd == null) { + return null; + } + + return freebsd.getAttributeValue("icon"); + } + public Map getPluginConfiguration() { Element configurationsDom = dom.getChild("configurations"); if (configurationsDom == null) { return null; } Map configs = new HashMap<>(); for (Element pluginDom : configurationsDom.getChildren("plugin")) { configs.put(pluginDom.getAttributeValue("id"), new BundleConfiguration(pluginDom)); } return Collections.unmodifiableMap(configs); } public List getConfigurationProperties() { Element configurationsDom = dom.getChild("configurations"); if (configurationsDom == null) { return null; } List propertyDoms = configurationsDom.getChildren("property"); if (propertyDoms == null) { return null; } List properties = new ArrayList<>(); for (Element properyDom : propertyDoms) { properties.add(new ConfigurationProperty(properyDom)); } return Collections.unmodifiableList(properties); } public String getMacIcon() { Element domLauncher = dom.getChild("launcher"); if (domLauncher == null) { return null; } Element linux = domLauncher.getChild("macosx"); if (linux == null) { return null; } return linux.getAttributeValue("icon"); } public ConfigIni getConfigIni() { Element configIniElement = dom.getChild("configIni"); if (configIniElement == null) { return null; } return new ConfigIni(configIniElement); } public static class ConfigIni { private String linuxConfigIni; + private String freebsdConfigIni; private String macosxConfigIni; private String solarisConfigIni; private String win32ConfigIni; private boolean useDefault = true; private ConfigIni(Element configIniElement) { useDefault = "default".equals(configIniElement.getAttributeValue("use")); linuxConfigIni = getOsSpecificConfigIni(configIniElement, "linux"); + freebsdConfigIni = getOsSpecificConfigIni(configIniElement, "freebsd"); macosxConfigIni = getOsSpecificConfigIni(configIniElement, "macosx"); solarisConfigIni = getOsSpecificConfigIni(configIniElement, "solaris"); win32ConfigIni = getOsSpecificConfigIni(configIniElement, "win32"); } public boolean isUseDefault() { return useDefault; } private String getOsSpecificConfigIni(Element configIniElement, String os) { Element osElement = configIniElement.getChild(os); if (osElement != null) { String trimmedValue = osElement.getTrimmedText(); if (trimmedValue.length() > 0) { return trimmedValue; } } return null; } public String getLinuxConfigIni() { return linuxConfigIni; } + public String getFreeBSDConfigIni() { + return freebsdConfigIni; + } + public String getMacosxConfigIni() { return macosxConfigIni; } public String getSolarisConfigIni() { return solarisConfigIni; } public String getWin32ConfigIni() { return win32ConfigIni; } } public static class ConfigurationProperty { private final Element dom; public ConfigurationProperty(Element dom) { this.dom = dom; } public String getName() { return dom.getAttributeValue("name"); } public String getValue() { return dom.getAttributeValue("value"); } public void setValue(String value) { dom.setAttribute("value", value); } } } diff --git a/tycho-metadata-model/src/test/java/org/eclipse/tycho/maven/test/ProductConfigurationTest.java b/tycho-metadata-model/src/test/java/org/eclipse/tycho/maven/test/ProductConfigurationTest.java index 49994a36..d64e8a5d 100644 --- a/tycho-metadata-model/src/test/java/org/eclipse/tycho/maven/test/ProductConfigurationTest.java +++ b/tycho-metadata-model/src/test/java/org/eclipse/tycho/maven/test/ProductConfigurationTest.java @@ -1,153 +1,154 @@ /******************************************************************************* * Copyright (c) 2008, 2014 Sonatype Inc. and others. * 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: * Sonatype Inc. - initial API and implementation *******************************************************************************/ package org.eclipse.tycho.maven.test; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.tycho.model.BundleConfiguration; import org.eclipse.tycho.model.FeatureRef; import org.eclipse.tycho.model.FeatureRef.InstallMode; import org.eclipse.tycho.model.Launcher; import org.eclipse.tycho.model.PluginRef; import org.eclipse.tycho.model.ProductConfiguration; import org.junit.Assert; import org.junit.Test; public class ProductConfigurationTest { @Test public void testProductConfigurationParse() throws Exception { ProductConfiguration config = ProductConfiguration.read(getClass().getResourceAsStream( "/product/MyFirstRCP.product")); Assert.assertEquals("My First RCP", config.getName()); Assert.assertEquals("MyFirstRCP.product1", config.getProduct()); Assert.assertEquals("MyFirstRCP.application", config.getApplication()); Assert.assertEquals(false, config.useFeatures()); /* * ConfigIni configIni = config.getConfigIni(); Assert.assertNotNull(configIni); * Assert.assertEquals("linux.ini", configIni.getLinuxIcon()); * Assert.assertEquals("macosx.ini", configIni.getMacosxIcon()); * Assert.assertEquals("solaris.ini", configIni.getSolarisIcon()); * Assert.assertEquals("win32.ini", configIni.getWin32()); * * LauncherArguments launcherArgs = config.getLauncherArgs(); * Assert.assertNotNull(launcherArgs); Assert.assertEquals("-all args", * launcherArgs.getProgramArgs()); Assert.assertEquals("-linux args", * launcherArgs.getProgramArgsLin()); Assert.assertEquals("-mac args", * launcherArgs.getProgramArgsMac()); Assert.assertEquals("-solaris args", * launcherArgs.getProgramArgsSol()); Assert.assertEquals("-win32 args", * launcherArgs.getProgramArgsWin()); Assert.assertEquals("-all vm", * launcherArgs.getVmArgs()); Assert.assertEquals("-linux vm", launcherArgs.getVmArgsLin()); * Assert.assertEquals("-mac vm", launcherArgs.getVmArgsMac()); * Assert.assertEquals("-solaris vm", launcherArgs.getVmArgsSol()); * Assert.assertEquals("-win32 vm", launcherArgs.getVmArgsWin()); */ Launcher launcher = config.getLauncher(); Assert.assertNotNull(launcher); Assert.assertEquals("launchername", launcher.getName()); Assert.assertEquals("XPM", launcher.getLinuxIcon().get(Launcher.ICON_LINUX)); + Assert.assertEquals("XPM", launcher.getFreeBSDIcon().get(Launcher.ICON_FREEBSD)); Assert.assertEquals("icns", launcher.getMacosxIcon().get(Launcher.ICON_MAC)); Assert.assertEquals("large", launcher.getSolarisIcon().get(Launcher.ICON_SOLARIS_LARGE)); Assert.assertEquals("medium", launcher.getSolarisIcon().get(Launcher.ICON_SOLARIS_MEDIUM)); Assert.assertEquals("small", launcher.getSolarisIcon().get(Launcher.ICON_SOLARIS_SMALL)); Assert.assertEquals("tiny", launcher.getSolarisIcon().get(Launcher.ICON_SOLARIS_TINY)); Assert.assertEquals(false, launcher.getWindowsUseIco()); // Assert.assertEquals("iconon", launcher.getWindowsIcon().getIco().getPath()); Assert.assertEquals("16-32", launcher.getWindowsIcon().get(Launcher.ICON_WINDOWS_SMALL_HIGH)); Assert.assertEquals("16-8", launcher.getWindowsIcon().get(Launcher.ICON_WINDOWS_SMALL_LOW)); Assert.assertEquals("32-32", launcher.getWindowsIcon().get(Launcher.ICON_WINDOWS_MEDIUM_HIGH)); Assert.assertEquals("32-8", launcher.getWindowsIcon().get(Launcher.ICON_WINDOWS_MEDIUM_LOW)); Assert.assertEquals("48-32", launcher.getWindowsIcon().get(Launcher.ICON_WINDOWS_LARGE_HIGH)); Assert.assertEquals("48-8", launcher.getWindowsIcon().get(Launcher.ICON_WINDOWS_LARGE_LOW)); Assert.assertEquals("256-32", launcher.getWindowsIcon().get(Launcher.ICON_WINDOWS_EXTRA_LARGE_HIGH)); List plugins = config.getPlugins(); Assert.assertNotNull(plugins); Assert.assertEquals(2, plugins.size()); PluginRef plugin = plugins.get(0); Assert.assertNotNull(plugin); Assert.assertEquals("HeadlessProduct", plugin.getId()); Assert.assertNull(plugin.getVersion()); List features = config.getFeatures(); Assert.assertNotNull(features); Assert.assertEquals(2, features.size()); FeatureRef feature = features.get(0); Assert.assertNotNull(feature); Assert.assertEquals("HeadlessFeature", feature.getId()); Assert.assertEquals("1.0.0", feature.getVersion()); } @Test public void testProductConfigurationParseWithStartLevel() throws Exception { ProductConfiguration config = ProductConfiguration.read(getClass().getResourceAsStream( "/product/MyProduct.product")); Map bundles = config.getPluginConfiguration(); // BundleConfiguration contentType = bundles.get("org.eclipse.core.contenttype"); Assert.assertNotNull(contentType); Assert.assertTrue(contentType.isAutoStart()); Assert.assertEquals(1, contentType.getStartLevel()); // BundleConfiguration headlessProduct = bundles.get("HeadlessProduct"); Assert.assertNotNull(headlessProduct); Assert.assertFalse(headlessProduct.isAutoStart()); Assert.assertEquals(2, headlessProduct.getStartLevel()); } @Test public void testFeatureInstallMode() throws Exception { ProductConfiguration config = ProductConfiguration.read(getClass().getResourceAsStream( "/product/rootFeatures.product")); Map modes = getInstallModes(config); assertThat(modes.get("org.eclipse.rcp"), is(InstallMode.include)); assertThat(modes.get("org.eclipse.e4.rcp"), is(InstallMode.include)); assertThat(modes.get("org.eclipse.help"), is(InstallMode.root)); assertThat(modes.get("org.eclipse.egit"), is(InstallMode.root)); assertThat(modes.size(), is(4)); } @Test public void testRemoveRootFeatures() throws Exception { ProductConfiguration config = ProductConfiguration.read(getClass().getResourceAsStream( "/product/rootFeatures.product")); config.removeRootInstalledFeatures(); Map modes = getInstallModes(config); assertThat(modes.get("org.eclipse.rcp"), is(InstallMode.include)); assertThat(modes.get("org.eclipse.e4.rcp"), is(InstallMode.include)); assertThat(modes.size(), is(2)); } private static Map getInstallModes(ProductConfiguration config) { Map modes = new HashMap<>(); for (FeatureRef featureRef : config.getFeatures()) { modes.put(featureRef.getId(), featureRef.getInstallMode()); } return modes; } } diff --git a/tycho-metadata-model/src/test/resources/product/MyFirstRCP.product b/tycho-metadata-model/src/test/resources/product/MyFirstRCP.product index 511e2a52..18d31a22 100644 --- a/tycho-metadata-model/src/test/resources/product/MyFirstRCP.product +++ b/tycho-metadata-model/src/test/resources/product/MyFirstRCP.product @@ -1,59 +1,63 @@ linux.ini macosx.ini solaris.ini win32.ini + freebsd.ini -all args -linux args + -freebsd args -mac args -solaris args -win32 args -all vm -linux vm + -freebsd vm -mac vm -solaris vm -win32 vm + diff --git a/tycho-p2/tycho-p2-director-plugin/src/main/java/org/eclipse/tycho/plugins/p2/director/AbstractProductMojo.java b/tycho-p2/tycho-p2-director-plugin/src/main/java/org/eclipse/tycho/plugins/p2/director/AbstractProductMojo.java index 377012ef..b4c26ddf 100644 --- a/tycho-p2/tycho-p2-director-plugin/src/main/java/org/eclipse/tycho/plugins/p2/director/AbstractProductMojo.java +++ b/tycho-p2/tycho-p2-director-plugin/src/main/java/org/eclipse/tycho/plugins/p2/director/AbstractProductMojo.java @@ -1,151 +1,152 @@ /******************************************************************************* * Copyright (c) 2010, 2014 SAP SE and others. * 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: * SAP SE - initial API and implementation *******************************************************************************/ package org.eclipse.tycho.plugins.p2.director; import java.io.File; import java.util.List; import org.apache.maven.execution.MavenSession; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.project.MavenProject; import org.eclipse.tycho.BuildOutputDirectory; import org.eclipse.tycho.core.TargetPlatformConfiguration; import org.eclipse.tycho.core.shared.TargetEnvironment; import org.eclipse.tycho.core.utils.TychoProjectUtils; abstract class AbstractProductMojo extends AbstractMojo { @Parameter(property = "project", readonly = true) private MavenProject project; @Parameter(property = "session", readonly = true) private MavenSession session; /** *

* Selection of products to be installed and configuration per product. *

*

* If the project contains more than one product file, you need to choose for which ones you * want to create distribution archives. If you choose to install more than one product, you * need to specify the attachId (which becomes a part of the classifier) to make the * classifiers unique. Example: * *

      * <plugin>
      *   <groupId>org.eclipse.tycho</groupId>
      *   <artifactId>tycho-p2-director-plugin</artifactId>
      *   <version>${tycho-version}</version>
      *   <executions>
      *     <execution>
      *       <id>create-distributions</id>
      *       <goals>
      *         <goal>materialize-products</goal>
      *         <goal>archive-products</goal>
      *       </goals>
      *     </execution>
      *   </executions>
      *   <configuration>
      *     <products>
      *       <product>
      *         <!-- select product with ID product.id; the archives get the classifiers "<os>.<ws>.<arch>" -->
      *         <id>product.id</id>
      *       </product>
      *       <product>
      *         <!-- select product with ID other.product.id for the classifiers "other-<os>.<ws>.<arch>" -->
      *         <id>other.product.id</id>
      *         <attachId>other</attachId>
      *       </product>
      *     </products>
      *   </configuration>
      * </plugin>
      * 
* * The following snippet shows the optional parameters which can be specified per product: * *
      *   <configuration>
      *     <products>
      *       <product>
      *         <id>product.id</id>
      *         <!-- optional parameters -->
      *         <rootFolder></rootFolder>
      *         <rootFolders>
      *           <macosx></macosx>
      *           <linux></linux>
+     *           <freebsd></freebsd>
      *           <win32></win32>
      *         </rootFolders>
      *       </product>
      *       ...
      *     </products>
      *   </configuration>
      * 
* * Details on the product-specific configuration parameters: *
    *
  • rootFolder - The path where the installed product shall be stored in the * archive, e.g. "eclipse". By default, the product is stored in the archive root.
  • *
  • * rootFolders - OS-specific installation root folders, overriding rootFolder. - * Allowed children are <macosx>, <win32> and <linux> or any - * other OS supported by p2. Since 0.18.0
  • + * Allowed children are <macosx>, <win32>, <linux> and + * <freebsd> or any other OS supported by p2. Since 0.18.0 *
* */ @Parameter private List products; /** * Kill the forked process after a certain number of seconds. If set to 0, wait forever for the * process, never timing out. */ @Parameter(property = "p2.timeout", defaultValue = "0") private int forkedProcessTimeoutInSeconds; int getForkedProcessTimeoutInSeconds() { return forkedProcessTimeoutInSeconds; } MavenProject getProject() { return project; } MavenSession getSession() { return session; } BuildOutputDirectory getBuildDirectory() { return new BuildOutputDirectory(getProject().getBuild().getDirectory()); } File getProductsBuildDirectory() { return getBuildDirectory().getChild("products"); } File getProductMaterializeDirectory(Product product, TargetEnvironment env) { return new File(getProductsBuildDirectory(), product.getId() + "/" + getOsWsArch(env, '/')); } List getEnvironments() { TargetPlatformConfiguration configuration = TychoProjectUtils.getTargetPlatformConfiguration(project); return configuration.getEnvironments(); } ProductConfig getProductConfig() throws MojoFailureException { return new ProductConfig(products, TychoProjectUtils.getDependencySeeds(project)); } static String getOsWsArch(TargetEnvironment env, char separator) { return env.getOs() + separator + env.getWs() + separator + env.getArch(); } } diff --git a/tycho-packaging-plugin/src/main/java/org/eclipse/tycho/packaging/ProductExportMojo.java b/tycho-packaging-plugin/src/main/java/org/eclipse/tycho/packaging/ProductExportMojo.java index ed9eac9e..2112a25f 100644 --- a/tycho-packaging-plugin/src/main/java/org/eclipse/tycho/packaging/ProductExportMojo.java +++ b/tycho-packaging-plugin/src/main/java/org/eclipse/tycho/packaging/ProductExportMojo.java @@ -1,782 +1,794 @@ /******************************************************************************* * Copyright (c) 2008, 2017 Sonatype Inc. and others. * 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: * Sonatype Inc. - initial API and implementation *******************************************************************************/ package org.eclipse.tycho.packaging; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.StringWriter; import java.util.Arrays; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; import java.util.Set; import java.util.StringTokenizer; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugins.annotations.Component; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; 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.logging.Logger; import org.codehaus.plexus.util.DirectoryScanner; import org.codehaus.plexus.util.FileUtils; import org.codehaus.plexus.util.IOUtil; import org.codehaus.plexus.util.SelectorUtils; import org.codehaus.plexus.util.io.RawInputStreamFacade; import org.eclipse.pde.internal.swt.tools.IconExe; import org.eclipse.tycho.ArtifactDescriptor; import org.eclipse.tycho.ArtifactType; import org.eclipse.tycho.PackagingType; import org.eclipse.tycho.core.ArtifactDependencyVisitor; import org.eclipse.tycho.core.ArtifactDependencyWalker; import org.eclipse.tycho.core.PluginDescription; import org.eclipse.tycho.core.osgitools.BundleReader; import org.eclipse.tycho.core.resolver.shared.PlatformPropertiesUtils; import org.eclipse.tycho.core.shared.TargetEnvironment; import org.eclipse.tycho.core.utils.TychoProjectUtils; import org.eclipse.tycho.locking.facade.FileLockService; import org.eclipse.tycho.locking.facade.FileLocker; import org.eclipse.tycho.model.BundleConfiguration; import org.eclipse.tycho.model.ProductConfiguration; @Mojo(name = "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(property = "productConfiguration", defaultValue = "${project.basedir}/${project.artifactId}.product") private File productConfigurationFile; @Parameter(defaultValue = "${productConfiguration}/../p2.inf") private File p2inf; /** * Location of generated .product file with all versions replaced with their expanded values. */ @Parameter(defaultValue = "${project.build.directory}/${project.artifactId}.product") private File expandedProductFile; /** * Parsed product configuration file */ private ProductConfiguration productConfiguration; /** * @deprecated use target-platform-configuration element */ @Parameter private TargetEnvironment[] environments; @Parameter(property = "tycho.product.createArchive", defaultValue = "true") private boolean createProductArchive; @Parameter(defaultValue = "false") private boolean includeSources; /** * If true (the default), produce separate directory structure for each supported runtime * environment. */ @Parameter(defaultValue = "true") private boolean separateEnvironments = true; /** * If true, all included features and bundles will be packed. If false (the default), all * features will be unpacked and bundles will honour unpack value of element. */ @Parameter(defaultValue = "false") private boolean forcePackedDependencies; @Component private BundleReader manifestReader; @Component private Logger logger; @Component private FileLockService fileLockService; @Override public void execute() throws MojoExecutionException, MojoFailureException { getLog().warn( "The packaging type 'eclipse-application' is deprecated; use 'eclipse-repository' instead. " + "See http://wiki.eclipse.org/Tycho_Messages_Explained#Eclipse_Application"); 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); } // build results will vary from system to system without explicit target environment configuration boolean implicitTargetEnvironment = TychoProjectUtils.getTargetPlatformConfiguration(project) .isImplicitTargetEnvironment(); if (productConfiguration.includeLaunchers() && implicitTargetEnvironment && environments == null) { throw new MojoFailureException("Product includes native launcher but no target environment was specified"); } if (separateEnvironments) { for (TargetEnvironment environment : getEnvironments()) { File target = getTarget(environment); File targetEclipse = new File(target, "eclipse"); targetEclipse.mkdirs(); generateDotEclipseProduct(targetEclipse); generateConfigIni(environment, targetEclipse); includeRootFiles(environment, targetEclipse); ProductAssembler assembler = new ProductAssembler(session, manifestReader, targetEclipse, environment); assembler.setIncludeSources(includeSources); getDependencyWalker(environment).walk(assembler); if (productConfiguration.includeLaunchers()) { copyExecutable(environment, targetEclipse); } if (createProductArchive) { createProductArchive(target, toString(environment)); } } } else { File target = getTarget(null); File targetEclipse = new File(target, "eclipse"); targetEclipse.mkdirs(); generateDotEclipseProduct(targetEclipse); generateConfigIni(null, targetEclipse); for (TargetEnvironment environment : getEnvironments()) { includeRootFiles(environment, targetEclipse); } ProductAssembler assembler = new ProductAssembler(session, manifestReader, targetEclipse, null); assembler.setIncludeSources(includeSources); if (forcePackedDependencies) { assembler.setUnpackFeatures(false); assembler.setUnpackPlugins(false); } getDependencyWalker().walk(assembler); if (productConfiguration.includeLaunchers()) { for (TargetEnvironment environment : getEnvironments()) { copyExecutable(environment, targetEclipse); } } if (createProductArchive) { createProductArchive(target, null); } } // String version = getTychoProjectFacet().getArtifactKey( project ).getVersion(); // String productVersion = VersioningHelper.getExpandedVersion( project, version ); // 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 ArtifactDependencyWalker getDependencyWalker(TargetEnvironment environment) { return getTychoProjectFacet(PackagingType.TYPE_ECLIPSE_APPLICATION).getDependencyWalker(project, environment); } private List getEnvironments() { if (environments != null) { getLog().warn( "tycho-packaging-plugin is deprecated. use target-platform-configuration ."); return Arrays.asList(environments); } return TychoProjectUtils.getTargetPlatformConfiguration(project).getEnvironments(); } private File getTarget(TargetEnvironment environment) { File target; if (separateEnvironments) { target = new File(project.getBuild().getDirectory(), toString(environment)); } else { target = new File(project.getBuild().getDirectory(), "product"); } 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(); } /** * 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. * *
      * root=
      * root.=
      * root.folder.=
      * root..folder.=
      * 
* * 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) { return; } Properties rootProperties = new Properties(); try (FileInputStream stream = new FileInputStream(new File(project.getBasedir(), generatedBuildProperties))) { rootProperties.load(stream); } 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); } String config = getConfig(environment); String root = "root"; String rootConfig = "root." + config; String rootFolder = "root.folder."; String rootConfigFolder = "root." + config + ".folder."; Set> entrySet = rootProperties.entrySet(); for (Iterator iterator = entrySet.iterator(); iterator.hasNext();) { Entry entry = (Entry) 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()); } } } /** * @param rootFileEntry * files and directories seperated by semicolons, the syntax is: *
    *
  • for a relative file: file:license.html,...
  • *
  • for a absolute file: absolute:file:/eclipse/about.html,...
  • *
  • for a relative folder: rootfiles,...
  • *
  • for a absolute folder: absolute:/eclipse/rootfiles,...
  • *
* @param subFolder * the sub folder to which the root file entries are copied to * @throws MojoExecutionException */ private void handleRootEntry(File target, String rootFileEntries, String subFolder) throws MojoExecutionException { 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); } try { if (source.isFile()) { FileUtils.copyFileToDirectory(source, destination); } else if (source.isDirectory()) { FileUtils.copyDirectoryStructure(source, destination); } else { getLog().warn("Skipping root entry " + rootFileEntry); } } catch (IOException e) { throw new MojoExecutionException("Coult not copy root entry " + fileName, e); } } } private String getConfig(TargetEnvironment environment) { String os = environment.getOs(); String ws = environment.getWs(); String arch = environment.getArch(); StringBuffer config = new StringBuffer(os).append(".").append(ws).append(".").append(arch); return config.toString(); } private void createProductArchive(File target, String classifier) throws MojoExecutionException { ZipArchiver zipper; try { zipper = (ZipArchiver) plexus.lookup(ZipArchiver.ROLE, "zip"); } catch (ComponentLookupException e) { throw new MojoExecutionException("Unable to resolve ZipArchiver", e); } StringBuilder filename = new StringBuilder(project.getBuild().getFinalName()); if (separateEnvironments) { 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 (separateEnvironments) { projectHelper.attachArtifact(project, destFile, classifier); } else { // main artifact project.getArtifact().setFile(destFile); } } 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.getProduct(); 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"); generateOSGiBundles(props, environment); File configsFolder = new File(target, "configuration"); configsFolder.mkdirs(); File configIni = new File(configsFolder, "config.ini"); FileOutputStream fos = null; try { fos = new FileOutputStream(configIni); props.store(fos, "Product Runtime Configuration File"); } catch (IOException e) { throw new MojoExecutionException("Error creating .eclipseproduct file.", e); } finally { IOUtil.close(fos); } } private void generateOSGiBundles(Properties props, TargetEnvironment environment) throws MojoFailureException { Map bundlesToStart = productConfiguration.getPluginConfiguration(); if (bundlesToStart == null) { bundlesToStart = new HashMap<>(); // This is the wellknown set of bundles for Eclipse based application for 3.3 and 3.4 without p2 bundlesToStart.put("org.eclipse.equinox.common", // new BundleConfiguration("org.eclipse.equinox.common", 2, true)); bundlesToStart.put("org.eclipse.core.runtime", // new BundleConfiguration("org.eclipse.core.runtime", -1, true)); } Map bundles = new LinkedHashMap<>(getBundles(environment)); StringBuilder osgiBundles = new StringBuilder(); for (PluginDescription plugin : bundles.values()) { String bundleId = plugin.getKey().getId(); // reverse engineering discovered // this plugin is not present on config.ini, and if so nothing // starts if ("org.eclipse.osgi".equals(bundleId)) { continue; } if (osgiBundles.length() > 0) { osgiBundles.append(','); } osgiBundles.append(bundleId); BundleConfiguration startup = bundlesToStart.get(bundleId); if (startup != null) { osgiBundles.append('@'); if (startup.getStartLevel() > 0) { osgiBundles.append(startup.getStartLevel()); } if (startup.isAutoStart()) { if (startup.getStartLevel() > 0) { osgiBundles.append(':'); } osgiBundles.append("start"); } } } setPropertyIfNotNull(props, "osgi.bundles", osgiBundles.toString()); } private Map getBundles(TargetEnvironment environment) { final Map bundles = new LinkedHashMap<>(); getDependencyWalker(environment).walk(new ArtifactDependencyVisitor() { @Override public void visitPlugin(PluginDescription plugin) { bundles.put(plugin.getKey().getId(), plugin); } }); return bundles; } private void copyExecutable(TargetEnvironment environment, File target) throws MojoExecutionException, MojoFailureException { getLog().debug("Creating launcher"); ArtifactDescriptor artifact = getDependencyArtifacts().getArtifact(ArtifactType.TYPE_ECLIPSE_FEATURE, "org.eclipse.equinox.executable", null); if (artifact == null) { throw new MojoExecutionException("Native launcher is not found for " + environment.toString()); } File location = artifact.getLocation(); String os = environment.getOs(); String ws = environment.getWs(); String arch = environment.getArch(); try { String launcherRelPath = "bin/" + ws + "/" + os + "/" + arch + "/"; String excludes = "**/eclipsec*"; if (location.isDirectory()) { copyDirectory(new File(location, launcherRelPath), target, excludes); } else { unzipDirectory(location, launcherRelPath, target, excludes); } } 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, logger); } 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 = FileUtils.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 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_FREEBSD.equals(os)) { + String icon = productConfiguration.getFreeBSDIcon(); + 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 = readFileToString(iniFile); int pos = buf.indexOf("Eclipse.icns"); buf.replace(pos, pos + 12, source.getName()); writeStringToFile(iniFile, buf.toString()); } } catch (Exception e) { throw new MojoExecutionException("Unable to create macosx icon", e); } } } } } private void writeStringToFile(File iniFile, String string) throws IOException { OutputStream os = new BufferedOutputStream(new FileOutputStream(iniFile)); try { IOUtil.copy(string, os); } finally { IOUtil.close(os); } } private StringBuffer readFileToString(File iniFile) throws IOException { InputStream is = new BufferedInputStream(new FileInputStream(iniFile)); try { StringWriter buffer = new StringWriter(); IOUtil.copy(is, buffer, "UTF-8"); return buffer.getBuffer(); } finally { IOUtil.close(is); } } private void unzipDirectory(File source, String sourceRelPath, File target, String excludes) throws IOException { FileLocker locker = fileLockService.getFileLocker(source); locker.lock(); try { ZipFile zip = new ZipFile(source); try { Enumeration entries = zip.entries(); while (entries.hasMoreElements()) { ZipEntry entry = entries.nextElement(); if (entry.isDirectory()) { continue; } String name = entry.getName(); if (name.startsWith(sourceRelPath) && !SelectorUtils.matchPath(excludes, name)) { File targetFile = new File(target, name.substring(sourceRelPath.length())); targetFile.getParentFile().mkdirs(); FileUtils.copyStreamToFile(new RawInputStreamFacade(zip.getInputStream(entry)), targetFile); } } } finally { zip.close(); } } finally { locker.release(); } } private void copyDirectory(File source, File target, String excludes) throws IOException { DirectoryScanner ds = new DirectoryScanner(); ds.setBasedir(source); ds.setExcludes(new String[] { excludes }); ds.scan(); for (String relPath : ds.getIncludedFiles()) { File targetFile = new File(target, relPath); targetFile.getParentFile().mkdirs(); FileUtils.copyFile(new File(source, relPath), targetFile); } } 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)) { + || PlatformPropertiesUtils.OS_HPUX.equals(os) || PlatformPropertiesUtils.OS_AIX.equals(os) + || PlatformPropertiesUtils.OS_FREEBSD.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); } } } diff --git a/tycho-testing-harness/src/main/java/org/eclipse/tycho/test/util/EnvironmentUtil.java b/tycho-testing-harness/src/main/java/org/eclipse/tycho/test/util/EnvironmentUtil.java index 30338b0c..319129fc 100644 --- a/tycho-testing-harness/src/main/java/org/eclipse/tycho/test/util/EnvironmentUtil.java +++ b/tycho-testing-harness/src/main/java/org/eclipse/tycho/test/util/EnvironmentUtil.java @@ -1,114 +1,120 @@ /******************************************************************************* * Copyright (c) 2008, 2011 Sonatype Inc. and others. * 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: * Sonatype Inc. - initial API and implementation *******************************************************************************/ package org.eclipse.tycho.test.util; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.Properties; import org.eclipse.tycho.test.AbstractTychoIntegrationTest; /** * Provides system properties and certain properties from the test code build ("outer build"), like * the location of the local Maven repository. For this class to work, the outer build must * configure the maven-properties-plugin to capture the values in a file called * baseTest.properties (see tycho-its/pom.xml for an example). */ public class EnvironmentUtil { private static final Properties props; static { props = new Properties(); ClassLoader cl = AbstractTychoIntegrationTest.class.getClassLoader(); InputStream is = cl.getResourceAsStream("baseTest.properties"); if (is != null) { try { try { props.load(is); } finally { is.close(); } } catch (IOException e) { throw new RuntimeException(e); } } } static synchronized String getProperty(String key) { return props.getProperty(key); } private static final String WINDOWS_OS = "windows"; private static final String MAC_OS = "mac os x"; private static final String MAC_OS_DARWIN = "darwin"; private static final String LINUX_OS = "linux"; + private static final String FREEBSD_OS = "freebsd"; + private static final String OS = System.getProperty("os.name").toLowerCase(); public static boolean isWindows() { return OS.startsWith(WINDOWS_OS); } public static boolean isLinux() { return OS.startsWith(LINUX_OS); } + public static boolean isFreeBSD() { + return OS.startsWith(FREEBSD_OS); + } + public static boolean isMac() { return OS.startsWith(MAC_OS) || OS.startsWith(MAC_OS_DARWIN); } // TODO find a more reliable way public static boolean isEclipse32Platform() { return new File(getTargetPlatform(), "startup.jar").exists(); } public static String getTargetPlatform() { String systemValue = System.getProperty("tychodev-testTargetPlatform"); if (systemValue != null) { return systemValue; } return getProperty("its-target-platform"); } public static String getTestSettings() { String value = getProperty("its-settings"); if (value == null || value.contains("$")) return null; return value; } public static String getMavenHome() { String systemValue = System.getProperty("tychodev-maven.home"); if (systemValue != null) { return systemValue; } return getProperty("maven-dir"); } public static String getTychoVersion() { return getProperty("tycho-version"); } public static int getHttpServerPort() { String port = getProperty("server-port"); return Integer.parseInt(port); } public static String getLocalRepo() { return getProperty("local-repo"); } }