1 /******************************************************************************* 2 * Copyright (c) 2006, 2013 IBM Corporation and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * IBM Corporation - initial API and implementation 13 *******************************************************************************/ 14 package org.eclipse.pde.internal.core.exports; 15 16 import java.io.File; 17 import java.net.MalformedURLException; 18 import java.util.Map; 19 import java.util.regex.Pattern; 20 import org.eclipse.core.resources.IContainer; 21 import org.eclipse.core.resources.IFolder; 22 import org.eclipse.core.resources.IResource; 23 import org.eclipse.core.runtime.CoreException; 24 import org.eclipse.core.runtime.IProgressMonitor; 25 import org.eclipse.core.runtime.IStatus; 26 import org.eclipse.core.runtime.Path; 27 import org.eclipse.core.runtime.URIUtil; 28 import org.eclipse.core.runtime.jobs.MultiRule; 29 import org.eclipse.pde.internal.build.IBuildPropertiesConstants; 30 import org.eclipse.pde.internal.build.IXMLConstants; 31 import org.eclipse.pde.internal.core.P2Utils; 32 import org.eclipse.pde.internal.core.PDECore; 33 import org.eclipse.pde.internal.core.PDECoreMessages; 34 import org.eclipse.pde.internal.core.ifeature.IFeature; 35 import org.eclipse.pde.internal.core.ifeature.IFeatureModel; 36 import org.eclipse.pde.internal.core.isite.ISiteDescription; 37 import org.eclipse.pde.internal.core.isite.ISiteFeature; 38 import org.eclipse.pde.internal.core.isite.ISiteModel; 39 import org.eclipse.pde.internal.core.site.WorkspaceSiteModel; 40 import org.eclipse.pde.internal.core.util.PatternConstructor; 41 import org.osgi.framework.Version; 42 43 /** 44 * Performs a site build operation that will build any features needed by the site and generate 45 * p2 metadata for those features. 46 * 47 * @see FeatureBasedExportOperation 48 * @see FeatureExportOperation 49 */ 50 public class SiteBuildOperation extends FeatureBasedExportOperation { 51 52 private long fBuildTime; 53 54 private final IFeatureModel[] fFeatureModels; 55 private final ISiteModel fSiteModel; 56 private final IContainer fSiteContainer; 57 SiteBuildOperation(IFeatureModel[] features, ISiteModel site, String jobName)58 public SiteBuildOperation(IFeatureModel[] features, ISiteModel site, String jobName) { 59 super(getInfo(features, site), jobName); 60 fFeatureModels = features; 61 fSiteModel = site; 62 fSiteContainer = site.getUnderlyingResource().getParent(); 63 setRule(MultiRule.combine(fSiteContainer.getProject(), getRule())); 64 } 65 getInfo(IFeatureModel[] models, ISiteModel siteModel)66 private static FeatureExportInfo getInfo(IFeatureModel[] models, ISiteModel siteModel) { 67 FeatureExportInfo info = new FeatureExportInfo(); 68 info.useJarFormat = true; 69 info.toDirectory = true; 70 info.allowBinaryCycles = true; 71 info.destinationDirectory = siteModel.getUnderlyingResource().getParent().getLocation().toOSString(); 72 info.items = models; 73 return info; 74 } 75 76 @Override run(IProgressMonitor monitor)77 protected IStatus run(IProgressMonitor monitor) { 78 fBuildTime = System.currentTimeMillis(); 79 IStatus status = super.run(monitor); 80 try { 81 fSiteContainer.refreshLocal(IResource.DEPTH_INFINITE, monitor); 82 updateSiteFeatureVersions(); 83 } catch (CoreException ce) { 84 return ce.getStatus(); 85 } 86 return status; 87 } 88 updateSiteFeatureVersions()89 private void updateSiteFeatureVersions() throws CoreException { 90 for (IFeatureModel featureModel : fFeatureModels) { 91 IFeature feature = featureModel.getFeature(); 92 Version pvi = Version.parseVersion(feature.getVersion()); 93 94 if ("qualifier".equals(pvi.getQualifier())) { //$NON-NLS-1$ 95 String newVersion = findBuiltVersion(feature.getId(), pvi.getMajor(), pvi.getMinor(), pvi.getMicro()); 96 if (newVersion == null) { 97 continue; 98 } 99 ISiteFeature reVersionCandidate = findSiteFeature(feature, pvi); 100 if (reVersionCandidate != null) { 101 reVersionCandidate.setVersion(newVersion); 102 reVersionCandidate.setURL("features/" + feature.getId() + "_" //$NON-NLS-1$ //$NON-NLS-2$ 103 + newVersion + ".jar"); //$NON-NLS-1$ 104 } 105 } 106 } 107 ((WorkspaceSiteModel) fSiteModel).save(); 108 } 109 findSiteFeature(IFeature feature, Version pvi)110 private ISiteFeature findSiteFeature(IFeature feature, Version pvi) { 111 ISiteFeature reversionCandidate = null; 112 // first see if version with qualifier being qualifier is present among 113 // site features 114 ISiteFeature[] siteFeatures = fSiteModel.getSite().getFeatures(); 115 for (ISiteFeature siteFeature : siteFeatures) { 116 if (siteFeature.getId().equals(feature.getId()) && siteFeature.getVersion().equals(feature.getVersion())) { 117 return siteFeature; 118 } 119 } 120 String highestQualifier = null; 121 // then find feature with the highest qualifier 122 for (ISiteFeature siteFeature : siteFeatures) { 123 if (siteFeature.getId().equals(feature.getId())) { 124 Version candidatePvi = Version.parseVersion(siteFeature.getVersion()); 125 if (pvi.getMajor() == candidatePvi.getMajor() && pvi.getMinor() == candidatePvi.getMinor() && pvi.getMicro() == candidatePvi.getMicro()) { 126 if (reversionCandidate == null || candidatePvi.getQualifier().compareTo(highestQualifier) > 0) { 127 reversionCandidate = siteFeature; 128 highestQualifier = candidatePvi.getQualifier(); 129 } 130 } 131 } 132 } 133 return reversionCandidate; 134 } 135 136 /** 137 * Finds the highest version from feature jars. ID and version components 138 * are constant. Qualifier varies 139 * 140 * @param id 141 * @param major 142 * @param minor 143 * @param service 144 */ findBuiltVersion(String id, int major, int minor, int service)145 private String findBuiltVersion(String id, int major, int minor, int service) { 146 IFolder featuresFolder = fSiteContainer.getFolder(new Path("features")); //$NON-NLS-1$ 147 if (!featuresFolder.exists()) { 148 return null; 149 } 150 IResource[] featureJars = null; 151 try { 152 featureJars = featuresFolder.members(); 153 } catch (CoreException ce) { 154 return null; 155 } 156 Pattern pattern = PatternConstructor.createPattern(id + "_" //$NON-NLS-1$ 157 + major + "." //$NON-NLS-1$ 158 + minor + "." //$NON-NLS-1$ 159 + service + "*.jar", true); //$NON-NLS-1$ 160 // finding the newest feature archive 161 String newestName = null; 162 long newestTime = 0; 163 for (IResource featureJar : featureJars) { 164 File file = new File(featureJar.getLocation().toOSString()); 165 long jarTime = file.lastModified(); 166 String jarName = featureJar.getName(); 167 168 if (jarTime < fBuildTime) { 169 continue; 170 } 171 if (jarTime <= newestTime) { 172 continue; 173 } 174 if (pattern.matcher(jarName).matches()) { 175 newestName = featureJar.getName(); 176 newestTime = jarTime; 177 } 178 } 179 if (newestName == null) { 180 return null; 181 } 182 183 return newestName.substring(id.length() + 1, newestName.length() - 4); 184 } 185 186 @Override createPostProcessingFiles()187 protected void createPostProcessingFiles() { 188 createPostProcessingFile(new File(fFeatureLocation, FEATURE_POST_PROCESSING)); 189 createPostProcessingFile(new File(fFeatureLocation, PLUGIN_POST_PROCESSING)); 190 } 191 192 @Override publishingP2Metadata()193 protected boolean publishingP2Metadata() { 194 return true; 195 } 196 197 @Override setP2MetaDataProperties(Map<String, String> map)198 protected void setP2MetaDataProperties(Map<String, String> map) { 199 if (fInfo.toDirectory) { 200 map.put(IXMLConstants.TARGET_P2_METADATA, IBuildPropertiesConstants.TRUE); 201 map.put(IBuildPropertiesConstants.PROPERTY_P2_FLAVOR, P2Utils.P2_FLAVOR_DEFAULT); 202 map.put(IBuildPropertiesConstants.PROPERTY_P2_PUBLISH_ARTIFACTS, IBuildPropertiesConstants.TRUE); 203 map.put(IBuildPropertiesConstants.PROPERTY_P2_FINAL_MODE_OVERRIDE, IBuildPropertiesConstants.TRUE); 204 map.put(IBuildPropertiesConstants.PROPERTY_P2_COMPRESS, IBuildPropertiesConstants.TRUE); 205 map.put(IBuildPropertiesConstants.PROPERTY_P2_GATHERING, Boolean.toString(publishingP2Metadata())); 206 IResource siteXML = fSiteModel.getUnderlyingResource(); 207 if (siteXML.exists() && siteXML.getLocationURI() != null) { 208 map.put(IBuildPropertiesConstants.PROPERTY_P2_CATEGORY_SITE, URIUtil.toUnencodedString(siteXML.getLocationURI())); 209 } 210 211 ISiteDescription description = fSiteModel.getSite().getDescription(); 212 String name = description != null && description.getName() != null && description.getName().length() > 0 ? description.getName() : PDECoreMessages.SiteBuildOperation_0; 213 map.put(IBuildPropertiesConstants.PROPERTY_P2_METADATA_REPO_NAME, name); 214 map.put(IBuildPropertiesConstants.PROPERTY_P2_ARTIFACT_REPO_NAME, name); 215 216 try { 217 String destination = new File(fBuildTempMetadataLocation).toURL().toString(); 218 map.put(IBuildPropertiesConstants.PROPERTY_P2_BUILD_REPO, destination); 219 } catch (MalformedURLException e) { 220 PDECore.log(e); 221 } 222 } 223 } 224 225 } 226