PageRenderTime 56ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/tycho-0.14.x/tycho-p2/tycho-p2-publisher-plugin/src/main/java/org/eclipse/tycho/plugins/p2/publisher/PublishProductMojo.java

#
Java | 328 lines | 241 code | 36 blank | 51 comment | 39 complexity | 55d6783471f3dde46843073ad1002608 MD5 | raw file
  1. /*******************************************************************************
  2. * Copyright (c) 2010, 2012 SAP AG and others.
  3. * All rights reserved. This program and the accompanying materials
  4. * are made available under the terms of the Eclipse Public License v1.0
  5. * which accompanies this distribution, and is available at
  6. * http://www.eclipse.org/legal/epl-v10.html
  7. *
  8. * Contributors:
  9. * SAP AG - initial API and implementation
  10. *******************************************************************************/
  11. package org.eclipse.tycho.plugins.p2.publisher;
  12. import java.io.File;
  13. import java.io.IOException;
  14. import java.util.ArrayList;
  15. import java.util.Collection;
  16. import java.util.Collections;
  17. import java.util.List;
  18. import java.util.Properties;
  19. import org.apache.maven.execution.MavenSession;
  20. import org.apache.maven.plugin.MojoExecutionException;
  21. import org.apache.maven.plugin.MojoFailureException;
  22. import org.apache.maven.project.MavenProject;
  23. import org.apache.maven.settings.Settings;
  24. import org.codehaus.plexus.archiver.ArchiverException;
  25. import org.codehaus.plexus.archiver.UnArchiver;
  26. import org.codehaus.plexus.interpolation.InterpolationException;
  27. import org.codehaus.plexus.interpolation.Interpolator;
  28. import org.codehaus.plexus.interpolation.PrefixedObjectValueSource;
  29. import org.codehaus.plexus.interpolation.SingleResponseValueSource;
  30. import org.codehaus.plexus.interpolation.StringSearchInterpolator;
  31. import org.codehaus.plexus.interpolation.ValueSource;
  32. import org.codehaus.plexus.util.FileUtils;
  33. import org.eclipse.tycho.ArtifactDescriptor;
  34. import org.eclipse.tycho.ArtifactKey;
  35. import org.eclipse.tycho.artifacts.DependencyArtifacts;
  36. import org.eclipse.tycho.buildversion.VersioningHelper;
  37. import org.eclipse.tycho.core.facade.BuildOutputDirectory;
  38. import org.eclipse.tycho.core.utils.TychoProjectUtils;
  39. import org.eclipse.tycho.locking.facade.FileLockService;
  40. import org.eclipse.tycho.locking.facade.FileLocker;
  41. import org.eclipse.tycho.model.FeatureRef;
  42. import org.eclipse.tycho.model.Launcher;
  43. import org.eclipse.tycho.model.PluginRef;
  44. import org.eclipse.tycho.model.ProductConfiguration;
  45. import org.eclipse.tycho.model.ProductConfiguration.ConfigIni;
  46. import org.eclipse.tycho.model.ProductConfiguration.ConfigurationProperty;
  47. import org.eclipse.tycho.p2.tools.FacadeException;
  48. import org.eclipse.tycho.p2.tools.publisher.facade.PublisherService;
  49. /**
  50. * This goal invokes the product publisher for each product file found.
  51. *
  52. * @see http://wiki.eclipse.org/Equinox/p2/Publisher
  53. * @goal publish-products
  54. */
  55. public final class PublishProductMojo extends AbstractPublishMojo {
  56. /**
  57. * @parameter default-value="tooling"
  58. */
  59. private String flavor;
  60. /**
  61. * @component role="org.codehaus.plexus.archiver.UnArchiver" role-hint="zip"
  62. */
  63. private UnArchiver deflater;
  64. /**
  65. * @component
  66. */
  67. private FileLockService fileLockService;
  68. @Override
  69. protected Collection<?> publishContent(PublisherService publisherService) throws MojoExecutionException,
  70. MojoFailureException {
  71. List<Object> productIUs = new ArrayList<Object>();
  72. for (File producFile : getEclipseRepositoryProject().getProductFiles(getProject())) {
  73. try {
  74. ProductConfiguration productConfiguration = ProductConfiguration.read(producFile);
  75. final Product buildProduct = prepareBuildProduct(producFile, productConfiguration, getBuildDirectory(),
  76. getQualifier(), newInterpolator());
  77. Collection<?> ius = publisherService.publishProduct(buildProduct.productFile,
  78. productConfiguration.includeLaunchers() ? getEquinoxExecutableFeature() : null, flavor);
  79. productIUs.addAll(ius);
  80. } catch (FacadeException e) {
  81. throw new MojoExecutionException("Exception while publishing product " + producFile.getAbsolutePath(),
  82. e);
  83. } catch (IOException e) {
  84. throw new MojoExecutionException(
  85. "I/O exception while writing product definition or copying launcher icons", e);
  86. }
  87. }
  88. return productIUs;
  89. }
  90. /**
  91. * Prepare the product file for the Eclipse publisher application.
  92. * <p>
  93. * Copies the product file and, if present, corresponding p2 advice file and other files
  94. * referenced in the .product file via relative path to a working directory. The folder is named
  95. * after the product ID (stored in the 'uid' attribute!), and the p2 advice file is renamed to
  96. * "p2.inf" so that the publisher application finds it.
  97. * </p>
  98. */
  99. static Product prepareBuildProduct(File productFile, ProductConfiguration productConfiguration,
  100. BuildOutputDirectory targetDir, String qualifier, Interpolator interpolator) throws MojoExecutionException,
  101. IOException {
  102. qualifyVersions(productConfiguration, qualifier);
  103. List<ConfigurationProperty> properties = productConfiguration.getConfigurationProperties();
  104. if (properties != null && interpolator != null) {
  105. for (ConfigurationProperty property : properties) {
  106. try {
  107. property.setValue(interpolator.interpolate(property.getValue()));
  108. } catch (InterpolationException e) {
  109. throw new MojoExecutionException("Could not interpolate product configuration property "
  110. + property.getName(), e);
  111. }
  112. }
  113. }
  114. final String productId = productConfiguration.getId();
  115. if (productId == null) {
  116. throw new MojoExecutionException("The product file " + productFile.getName()
  117. + " does not contain the mandatory attribute 'uid'");
  118. }
  119. File buildProductDir = targetDir.getChild("products/" + productId);
  120. buildProductDir.mkdirs();
  121. final Product buildProduct = new Product(new File(buildProductDir, productFile.getName()), new File(
  122. buildProductDir, "p2.inf"));
  123. ProductConfiguration.write(productConfiguration, buildProduct.productFile);
  124. copyP2Inf(getSourceP2InfFile(productFile), buildProduct.p2infFile);
  125. copyReferencedFiles(productConfiguration, productFile.getParentFile(), buildProductDir);
  126. return buildProduct;
  127. }
  128. private static void copyReferencedFiles(ProductConfiguration productConfiguration, File sourceDir, File targetDir)
  129. throws IOException {
  130. Launcher launcher = productConfiguration.getLauncher();
  131. List<String> relativePaths = new ArrayList<String>();
  132. if (launcher != null) {
  133. relativePaths.addAll(launcher.getLinuxIcon().values());
  134. relativePaths.addAll(launcher.getWindowsIcon().values());
  135. relativePaths.addAll(launcher.getSolarisIcon().values());
  136. relativePaths.addAll(launcher.getMacosxIcon().values());
  137. }
  138. ConfigIni configIni = productConfiguration.getConfigIni();
  139. if (configIni != null) {
  140. relativePaths.add(configIni.getLinuxConfigIni());
  141. relativePaths.add(configIni.getWin32ConfigIni());
  142. relativePaths.add(configIni.getSolarisConfigIni());
  143. relativePaths.add(configIni.getMacosxConfigIni());
  144. }
  145. copyFiles(sourceDir, targetDir, relativePaths);
  146. }
  147. private static void copyFiles(File sourceDir, File targetDir, List<String> relativePaths) throws IOException {
  148. for (String relativePath : relativePaths) {
  149. if (relativePath == null) {
  150. continue;
  151. }
  152. File sourceFile = new File(sourceDir, relativePath);
  153. if (sourceFile.isFile()) {
  154. FileUtils.copyFile(sourceFile, new File(targetDir, relativePath));
  155. }
  156. }
  157. }
  158. static void copyP2Inf(final File sourceP2Inf, final File buildP2Inf) throws IOException {
  159. if (sourceP2Inf.exists()) {
  160. FileUtils.copyFile(sourceP2Inf, buildP2Inf);
  161. }
  162. }
  163. /**
  164. * Value class identifying a product file (and optionally an associated p2.inf file) for the
  165. * {@link PublishProductMojo}.
  166. */
  167. static class Product {
  168. private final File productFile;
  169. private final File p2infFile;
  170. public Product(File productFile) {
  171. this(productFile, getSourceP2InfFile(productFile));
  172. }
  173. public Product(File productFile, File p2infFile) {
  174. this.productFile = productFile;
  175. this.p2infFile = p2infFile;
  176. }
  177. public File getProductFile() {
  178. return productFile;
  179. }
  180. public File getP2infFile() {
  181. return p2infFile;
  182. }
  183. }
  184. /**
  185. * We expect an p2 advice file called "xx.p2.inf" next to a product file "xx.product".
  186. */
  187. static File getSourceP2InfFile(File productFile) {
  188. // This must match org.eclipse.tycho.p2.impl.publisher.ProductDependenciesAction.addPublisherAdvice(IPublisherInfo)
  189. final int indexOfExtension = productFile.getName().indexOf(".product");
  190. final String p2infFilename = productFile.getName().substring(0, indexOfExtension) + ".p2.inf";
  191. return new File(productFile.getParentFile(), p2infFilename);
  192. }
  193. static void qualifyVersions(ProductConfiguration productConfiguration, String buildQualifier) {
  194. // we need to expand the version otherwise the published artifact still has the '.qualifier'
  195. String productVersion = productConfiguration.getVersion();
  196. if (productVersion != null) {
  197. productVersion = replaceQualifier(productVersion, buildQualifier);
  198. productConfiguration.setVersion(productVersion);
  199. }
  200. // now same for the features and bundles that version would be something else than "0.0.0"
  201. for (FeatureRef featRef : productConfiguration.getFeatures()) {
  202. if (featRef.getVersion() != null && featRef.getVersion().indexOf(VersioningHelper.QUALIFIER) != -1) {
  203. String newVersion = replaceQualifier(featRef.getVersion(), buildQualifier);
  204. featRef.setVersion(newVersion);
  205. }
  206. }
  207. for (PluginRef plugRef : productConfiguration.getPlugins()) {
  208. if (plugRef.getVersion() != null && plugRef.getVersion().indexOf(VersioningHelper.QUALIFIER) != -1) {
  209. String newVersion = replaceQualifier(plugRef.getVersion(), buildQualifier);
  210. plugRef.setVersion(newVersion);
  211. }
  212. }
  213. }
  214. private static String replaceQualifier(final String productVersion, final String qualifier) {
  215. String replaceVersion = productVersion;
  216. if (productVersion.endsWith("." + VersioningHelper.QUALIFIER)) {
  217. int qualifierIndex = productVersion.length() - VersioningHelper.QUALIFIER.length();
  218. String unqualifiedVersion = productVersion.substring(0, qualifierIndex - 1);
  219. if (qualifier == null || "".equals(qualifier)) {
  220. replaceVersion = unqualifiedVersion;
  221. } else {
  222. replaceVersion = unqualifiedVersion + "." + qualifier;
  223. }
  224. }
  225. return replaceVersion;
  226. }
  227. /**
  228. * Same code than in the ProductExportMojo. Needed to get the launcher binaries.
  229. */
  230. // TODO implement at eclipse: have product publisher take the executables from the context repositories
  231. private File getEquinoxExecutableFeature() throws MojoExecutionException, MojoFailureException {
  232. // TODO 364134 take the executable feature from the target platform instead
  233. DependencyArtifacts dependencyArtifacts = TychoProjectUtils.getDependencyArtifacts(getProject());
  234. ArtifactDescriptor artifact = dependencyArtifacts.getArtifact(ArtifactKey.TYPE_ECLIPSE_FEATURE,
  235. "org.eclipse.equinox.executable", null);
  236. if (artifact == null) {
  237. throw new MojoExecutionException("Unable to locate the equinox launcher feature (aka delta-pack)");
  238. }
  239. File equinoxExecFeature = artifact.getLocation();
  240. if (equinoxExecFeature.isDirectory()) {
  241. return equinoxExecFeature.getAbsoluteFile();
  242. } else {
  243. File unzipped = new File(getProject().getBuild().getOutputDirectory(), artifact.getKey().getId() + "-"
  244. + artifact.getKey().getVersion());
  245. if (unzipped.exists()) {
  246. return unzipped.getAbsoluteFile();
  247. }
  248. try {
  249. FileLocker locker = fileLockService.getFileLocker(equinoxExecFeature);
  250. locker.lock();
  251. try {
  252. // unzip now then:
  253. unzipped.mkdirs();
  254. deflater.setSourceFile(equinoxExecFeature);
  255. deflater.setDestDirectory(unzipped);
  256. deflater.extract();
  257. return unzipped.getAbsoluteFile();
  258. } finally {
  259. locker.release();
  260. }
  261. } catch (ArchiverException e) {
  262. throw new MojoFailureException("Unable to unzip the eqiuinox executable feature", e);
  263. }
  264. }
  265. }
  266. protected Interpolator newInterpolator() {
  267. final MavenProject mavenProject = getProject();
  268. final MavenSession mavenSession = getSession();
  269. final Properties baseProps = new Properties();
  270. baseProps.putAll(mavenProject.getProperties());
  271. baseProps.putAll(mavenSession.getSystemProperties());
  272. baseProps.putAll(mavenSession.getUserProperties());
  273. final Settings settings = mavenSession.getSettings();
  274. // roughly match resources plugin behaviour
  275. final StringSearchInterpolator interpolator = new StringSearchInterpolator();
  276. interpolator.addValueSource(new PrefixedObjectValueSource("project", mavenProject));
  277. interpolator.addValueSource(new PrefixedObjectValueSource("settings", settings));
  278. interpolator.addValueSource(new SingleResponseValueSource("localRepository", settings.getLocalRepository()));
  279. interpolator.addValueSource(new ValueSource() {
  280. public Object getValue(String expression) {
  281. return baseProps.getProperty(expression);
  282. }
  283. public void clearFeedback() {
  284. }
  285. @SuppressWarnings("rawtypes")
  286. public List getFeedback() {
  287. return Collections.EMPTY_LIST;
  288. }
  289. });
  290. return interpolator;
  291. }
  292. }