1 /******************************************************************************* 2 * Copyright (c) 2000, 2017 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 - Initial API and implementation 13 *******************************************************************************/ 14 package org.eclipse.pde.internal.build; 15 16 import java.io.*; 17 import java.net.URI; 18 import java.net.URISyntaxException; 19 import java.util.*; 20 import org.eclipse.core.runtime.*; 21 import org.eclipse.equinox.internal.p2.engine.SimpleProfileRegistry; 22 import org.eclipse.equinox.internal.p2.publisher.eclipse.ProductFile; 23 import org.eclipse.equinox.p2.core.IAgentLocation; 24 import org.eclipse.equinox.p2.core.IProvisioningAgent; 25 import org.eclipse.equinox.p2.engine.IProfile; 26 import org.eclipse.equinox.p2.engine.IProfileRegistry; 27 import org.eclipse.equinox.p2.publisher.eclipse.FeatureEntry; 28 import org.eclipse.osgi.service.resolver.BundleDescription; 29 import org.eclipse.osgi.service.resolver.State; 30 import org.eclipse.osgi.util.NLS; 31 import org.eclipse.pde.internal.build.ant.AntScript; 32 import org.eclipse.pde.internal.build.builder.BuildDirector; 33 import org.eclipse.pde.internal.build.site.*; 34 import org.eclipse.pde.internal.build.site.compatibility.SiteManager; 35 import org.osgi.framework.Version; 36 37 /** 38 * Generic super-class for all script generator classes. 39 * It contains basic informations like the script, the configurations, and a location 40 */ 41 public abstract class AbstractScriptGenerator implements IXMLConstants, IPDEBuildConstants, IBuildPropertiesConstants { 42 private static final FilenameFilter METADATA_REPO_FILTER = (dir, name) -> name.startsWith("content.") || name.startsWith("compositeContent.") || //$NON-NLS-1$ //$NON-NLS-2$ 43 name.endsWith(".profile") || name.endsWith(".profile.gz"); //$NON-NLS-1$//$NON-NLS-2$ 44 45 private static final FilenameFilter ARTIFACT_REPO_FILTER = (dir, name) -> name.startsWith("artifacts.") || name.startsWith("compositeArtifacts."); //$NON-NLS-1$ //$NON-NLS-2$ 46 47 private static Properties immutableAntProperties = null; 48 protected static boolean embeddedSource = false; 49 protected static boolean forceUpdateJarFormat = false; 50 private static List<Config> configInfos; 51 protected static String workingDirectory; 52 protected URI[] contextMetadata = null; 53 protected URI[] contextArtifacts = null; 54 protected AntScript script; 55 protected Properties platformProperties; 56 protected String productQualifier; 57 58 private static PDEUIStateWrapper pdeUIState; 59 60 /** Location of the plug-ins and fragments. */ 61 protected String[] sitePaths; 62 protected String[] pluginPath; 63 protected BuildTimeSiteFactory siteFactory; 64 65 /** 66 * Indicate whether the content of the pdestate should only contain the plugins that are in the transitive closure of the features being built 67 */ 68 protected boolean filterState = false; 69 protected List<String> featuresForFilterRoots = new ArrayList<>(); 70 protected List<String> pluginsForFilterRoots = new ArrayList<>(); 71 protected boolean filterP2Base = false; 72 73 protected boolean reportResolutionErrors; 74 75 static { 76 // By default, a generic configuration is set 77 configInfos = new ArrayList<>(1); Config.genericConfig()78 configInfos.add(Config.genericConfig()); 79 } 80 getConfigInfos()81 public static List<Config> getConfigInfos() { 82 return configInfos; 83 } 84 85 /** 86 * Starting point for script generation. See subclass implementations for 87 * individual comments. 88 * 89 * @throws CoreException 90 */ generate()91 public abstract void generate() throws CoreException; 92 setStaticAntProperties(Properties properties)93 protected static void setStaticAntProperties(Properties properties) { 94 if (properties == null) { 95 immutableAntProperties = new Properties(); 96 BuildDirector.p2Gathering = false; 97 } else 98 immutableAntProperties = properties; 99 if (getImmutableAntProperty(IBuildPropertiesConstants.PROPERTY_PACKAGER_MODE) == null) { 100 immutableAntProperties.setProperty(IBuildPropertiesConstants.PROPERTY_PACKAGER_MODE, "false"); //$NON-NLS-1$ 101 } 102 //When we are generating build scripts, the normalization needs to be set, and when doing packaging the default is to set normalization to true for backward compatibility 103 if (!getPropertyAsBoolean(IBuildPropertiesConstants.PROPERTY_PACKAGER_MODE) || getImmutableAntProperty(IBuildPropertiesConstants.PROPERTY_PACKAGER_AS_NORMALIZER) == null) { 104 immutableAntProperties.setProperty(IBuildPropertiesConstants.PROPERTY_PACKAGER_AS_NORMALIZER, "true"); //$NON-NLS-1$ 105 } 106 107 if (getPropertyAsBoolean(IBuildPropertiesConstants.PROPERTY_P2_GATHERING)) 108 BuildDirector.p2Gathering = true; 109 } 110 getImmutableAntProperty(String key)111 public static String getImmutableAntProperty(String key) { 112 return getImmutableAntProperty(key, null); 113 } 114 getPropertyAsBoolean(String key)115 public static boolean getPropertyAsBoolean(String key) { 116 String booleanValue = getImmutableAntProperty(key, null); 117 if ("true".equalsIgnoreCase(booleanValue)) //$NON-NLS-1$ 118 return true; 119 return false; 120 } 121 getImmutableAntProperty(String key, String defaultValue)122 public static String getImmutableAntProperty(String key, String defaultValue) { 123 if (immutableAntProperties == null || !immutableAntProperties.containsKey(key)) 124 return defaultValue; 125 Object obj = immutableAntProperties.get(key); 126 return (obj instanceof String) ? (String) obj : null; 127 } 128 setConfigInfo(String spec)129 public static void setConfigInfo(String spec) throws CoreException { 130 String[] configs = Utils.getArrayFromStringWithBlank(spec, "&"); //$NON-NLS-1$ 131 List<Config> infos = new ArrayList<>(configs.length); 132 String[] os = new String[configs.length]; 133 String[] ws = new String[configs.length]; 134 String[] archs = new String[configs.length]; 135 for (int i = 0; i < configs.length; i++) { 136 String[] configElements = Utils.getArrayFromStringWithBlank(configs[i], ","); //$NON-NLS-1$ 137 if (configElements.length != 3) { 138 IStatus error = new Status(IStatus.ERROR, IPDEBuildConstants.PI_PDEBUILD, IPDEBuildConstants.EXCEPTION_CONFIG_FORMAT, NLS.bind(Messages.error_configWrongFormat, configs[i]), null); 139 throw new CoreException(error); 140 } 141 Config aConfig = new Config(configs[i]); 142 if (aConfig.equals(Config.genericConfig())) { 143 infos.add(Config.genericConfig()); 144 } else { 145 infos.add(aConfig); 146 } 147 148 // create a list of all ws, os and arch to feed the SiteManager 149 os[i] = aConfig.getOs(); 150 ws[i] = aConfig.getWs(); 151 archs[i] = aConfig.getArch(); 152 } 153 SiteManager.setOS(Utils.getStringFromArray(os, ",")); //$NON-NLS-1$ 154 SiteManager.setWS(Utils.getStringFromArray(ws, ",")); //$NON-NLS-1$ 155 SiteManager.setArch(Utils.getStringFromArray(archs, ",")); //$NON-NLS-1$ 156 configInfos = infos; 157 } 158 setWorkingDirectory(String location)159 public void setWorkingDirectory(String location) { 160 workingDirectory = location; 161 } 162 163 /** 164 * Return the file system location for the given plug-in model object. 165 * 166 * @param model the plug-in 167 * @return String 168 */ getLocation(BundleDescription model)169 public String getLocation(BundleDescription model) { 170 return model.getLocation(); 171 } 172 173 static public class MissingProperties extends Properties { 174 private static final long serialVersionUID = 3546924667060303927L; 175 private static MissingProperties singleton; 176 MissingProperties()177 private MissingProperties() { 178 //nothing to do; 179 } 180 181 @Override setProperty(String key, String value)182 public synchronized Object setProperty(String key, String value) { 183 throw new UnsupportedOperationException(); 184 } 185 186 @Override put(Object key, Object value)187 public synchronized Object put(Object key, Object value) { 188 throw new UnsupportedOperationException(); 189 } 190 getInstance()191 public static MissingProperties getInstance() { 192 if (singleton == null) 193 singleton = new MissingProperties(); 194 return singleton; 195 } 196 } 197 readProperties(String location, String fileName, int errorLevel)198 public static Properties readProperties(String location, String fileName, int errorLevel) throws CoreException { 199 if (location == null) { 200 if (errorLevel != IStatus.INFO && errorLevel != IStatus.OK) { 201 String message = NLS.bind(Messages.exception_missingFile, fileName); 202 BundleHelper.getDefault().getLog().log(new Status(errorLevel, PI_PDEBUILD, EXCEPTION_READING_FILE, message, null)); 203 } 204 return MissingProperties.getInstance(); 205 } 206 207 Properties result = new Properties(); 208 File file = new File(location, fileName); 209 try (InputStream input = new BufferedInputStream(new FileInputStream(file))) { 210 result.load(input); 211 } catch (FileNotFoundException e) { 212 if (errorLevel != IStatus.INFO && errorLevel != IStatus.OK) { 213 String message = NLS.bind(Messages.exception_missingFile, file); 214 BundleHelper.getDefault().getLog().log(new Status(errorLevel, PI_PDEBUILD, EXCEPTION_READING_FILE, message, null)); 215 } 216 result = MissingProperties.getInstance(); 217 } catch (IOException e) { 218 String message = NLS.bind(Messages.exception_readingFile, file); 219 throw new CoreException(new Status(IStatus.ERROR, PI_PDEBUILD, EXCEPTION_READING_FILE, message, e)); 220 } 221 return result; 222 } 223 openScript(String scriptLocation, String scriptName)224 public void openScript(String scriptLocation, String scriptName) throws CoreException { 225 if (script != null) 226 return; 227 script = newAntScript(scriptLocation, scriptName); 228 } 229 newAntScript(String scriptLocation, String scriptName)230 protected static AntScript newAntScript(String scriptLocation, String scriptName) throws CoreException { 231 AntScript result = null; 232 try { 233 OutputStream scriptStream = new BufferedOutputStream(new FileOutputStream(scriptLocation + '/' + scriptName)); 234 try { 235 result = new AntScript(scriptStream); 236 } catch (IOException e) { 237 try { 238 scriptStream.close(); 239 String message = NLS.bind(Messages.exception_writingFile, scriptLocation + '/' + scriptName); 240 throw new CoreException(new Status(IStatus.ERROR, PI_PDEBUILD, EXCEPTION_WRITING_FILE, message, e)); 241 } catch (IOException e1) { 242 // Ignored 243 } 244 } 245 } catch (FileNotFoundException e) { 246 String message = NLS.bind(Messages.exception_writingFile, scriptLocation + '/' + scriptName); 247 throw new CoreException(new Status(IStatus.ERROR, PI_PDEBUILD, EXCEPTION_WRITING_FILE, message, e)); 248 } 249 return result; 250 } 251 closeScript()252 public void closeScript() { 253 script.close(); 254 } 255 getWorkingDirectory()256 public static String getWorkingDirectory() { 257 return workingDirectory; 258 } 259 getDefaultOutputFormat()260 public static String getDefaultOutputFormat() { 261 return "zip"; //$NON-NLS-1$ 262 } 263 getDefaultEmbeddedSource()264 public static boolean getDefaultEmbeddedSource() { 265 return false; 266 } 267 setEmbeddedSource(boolean embed)268 public static void setEmbeddedSource(boolean embed) { 269 embeddedSource = embed; 270 } 271 getForceUpdateJarFormat()272 public static boolean getForceUpdateJarFormat() { 273 return false; 274 } 275 setForceUpdateJar(boolean force)276 public static void setForceUpdateJar(boolean force) { 277 forceUpdateJarFormat = force; 278 } 279 getDefaultConfigInfos()280 public static String getDefaultConfigInfos() { 281 return "*, *, *"; //$NON-NLS-1$ 282 } 283 loadP2Class()284 protected static boolean loadP2Class() { 285 try { 286 BundleHelper.getDefault().getClass().getClassLoader().loadClass("org.eclipse.equinox.p2.publisher.Publisher"); //$NON-NLS-1$ 287 return true; 288 } catch (Throwable e) { 289 return false; 290 } 291 } 292 293 /** 294 * Return a build time site referencing things to be built. 295 * @param refresh : indicate if a refresh must be performed. Although this flag is set to true, a new site is not rebuild if the urls of the site did not changed 296 * @return BuildTimeSite 297 * @throws CoreException 298 */ getSite(boolean refresh)299 public BuildTimeSite getSite(boolean refresh) throws CoreException { 300 if (siteFactory != null && refresh == false) 301 return siteFactory.createSite(); 302 303 //If there is an exception from createSite(), we will discard the factory 304 BuildTimeSiteFactory factory = new BuildTimeSiteFactory(); 305 factory.setFilterState(filterState); 306 factory.setFilterRoots(featuresForFilterRoots, pluginsForFilterRoots); 307 factory.setReportResolutionErrors(reportResolutionErrors); 308 factory.setFilterP2Base(filterP2Base); 309 factory.setSitePaths(getPaths()); 310 factory.setEESources(getEESources()); 311 factory.setInitialState(pdeUIState); 312 313 BuildTimeSite result = factory.createSite(); 314 siteFactory = factory; 315 316 if (platformProperties != null) 317 result.setPlatformPropeties(platformProperties); 318 319 File baseProfile = result.getSiteContentProvider().getBaseProfile(); 320 if (baseProfile != null) { 321 List<URI> repos = getAssociatedRepositories(baseProfile); 322 if (repos.size() > 0) { 323 addContextRepos(repos.toArray(new URI[repos.size()])); 324 } 325 } 326 327 return result; 328 } 329 330 /** 331 * Method getPaths. These are the paths used for the BuildTimeSite 332 * @return URL[] 333 */ getPaths()334 private String[] getPaths() { 335 if (sitePaths == null) { 336 if (pluginPath != null) { 337 sitePaths = new String[pluginPath.length + 1]; 338 System.arraycopy(pluginPath, 0, sitePaths, 0, pluginPath.length); 339 sitePaths[sitePaths.length - 1] = workingDirectory; 340 } else { 341 sitePaths = new String[] {workingDirectory}; 342 } 343 } 344 345 return sitePaths; 346 } 347 getEESources()348 protected String[] getEESources() { 349 return null; 350 } 351 setBuildSiteFactory(BuildTimeSiteFactory siteFactory)352 public void setBuildSiteFactory(BuildTimeSiteFactory siteFactory) { 353 this.siteFactory = siteFactory; 354 } 355 356 /** 357 * Return the path of the plugins //TODO Do we need to add support for features, or do we simply consider one list of URL? It is just a matter of style/ 358 * @return URL[] 359 */ getPluginPath()360 public String[] getPluginPath() { 361 return pluginPath; 362 } 363 364 /** 365 * Sets the pluginPath. 366 * 367 * @param path 368 */ setPluginPath(String[] path)369 public void setPluginPath(String[] path) { 370 pluginPath = path; 371 } 372 setPDEState(State state)373 public void setPDEState(State state) { 374 ensurePDEUIStateNotNull(); 375 pdeUIState.setState(state); 376 } 377 setStateExtraData(HashMap<Long, String[]> classpath, Map<Long, String> patchData)378 public void setStateExtraData(HashMap<Long, String[]> classpath, Map<Long, String> patchData) { 379 setStateExtraData(classpath, patchData, null); 380 } 381 setStateExtraData(HashMap<Long, String[]> classpath, Map<Long, String> patchData, Map<String, Map<String, Set<IPath>>> outputFolders)382 public void setStateExtraData(HashMap<Long, String[]> classpath, Map<Long, String> patchData, Map<String, Map<String, Set<IPath>>> outputFolders) { 383 ensurePDEUIStateNotNull(); 384 pdeUIState.setExtraData(classpath, patchData, outputFolders); 385 } 386 setNextId(long nextId)387 public void setNextId(long nextId) { 388 ensurePDEUIStateNotNull(); 389 pdeUIState.setNextId(nextId); 390 } 391 flushState()392 protected void flushState() { 393 pdeUIState = null; 394 } 395 ensurePDEUIStateNotNull()396 private void ensurePDEUIStateNotNull() { 397 if (pdeUIState == null) 398 pdeUIState = new PDEUIStateWrapper(); 399 } 400 havePDEUIState()401 protected boolean havePDEUIState() { 402 return pdeUIState != null; 403 } 404 loadProduct(String product)405 public ProductFile loadProduct(String product) throws CoreException { 406 //the ProductFile uses the OS to determine which icons to return, we don't care so can use null 407 //this is better since this generator may be used for multiple OS's 408 return loadProduct(product, null); 409 } 410 loadProduct(String product, String os)411 public ProductFile loadProduct(String product, String os) throws CoreException { 412 if (product == null || product.startsWith("${") || product.length() == 0) { //$NON-NLS-1$ 413 return null; 414 } 415 String productPath = findFile(product, false); 416 File f = null; 417 if (productPath != null) { 418 f = new File(productPath); 419 } else { 420 // couldn't find productFile, try it as a path directly 421 f = new File(product); 422 if (!f.exists() || !f.isFile()) { 423 // doesn't exist, try it as a path relative to the working directory 424 f = new File(getWorkingDirectory(), product); 425 if (!f.exists() || !f.isFile()) { 426 f = new File(getWorkingDirectory() + "/" + DEFAULT_PLUGIN_LOCATION, product); //$NON-NLS-1$ 427 if (!f.exists() || !f.isFile()) { 428 f = new File(getWorkingDirectory() + '/' + DEFAULT_FEATURE_LOCATION, product); 429 } 430 } 431 } 432 } 433 return new ProductFile(f.getAbsolutePath(), os); 434 } 435 436 //Find a file in a bundle or a feature. 437 //location is assumed to be structured like : /<featureId | pluginId>/path.to.the.file findFile(String location, boolean makeRelative)438 protected String findFile(String location, boolean makeRelative) { 439 if (location == null || location.length() == 0) 440 return null; 441 442 //shortcut building the site if we don't need to 443 if (new File(location).exists()) 444 return location; 445 446 PDEState state; 447 try { 448 state = getSite(false).getRegistry(); 449 } catch (CoreException e) { 450 BundleHelper.getDefault().getLog().log(e.getStatus()); 451 return null; 452 } 453 Path path = new Path(location); 454 String id = path.segment(0); 455 BundleDescription[] matches = state.getState().getBundles(id); 456 if (matches != null && matches.length != 0) { 457 BundleDescription bundle = matches[0]; 458 if (bundle != null) { 459 String result = checkFile(new Path(bundle.getLocation()), path, makeRelative); 460 if (result != null) 461 return result; 462 } 463 } 464 // Couldn't find the file in any of the plugins, try in a feature. 465 BuildTimeFeature feature = null; 466 try { 467 feature = getSite(false).findFeature(id, null, false); 468 } catch (CoreException e) { 469 BundleHelper.getDefault().getLog().log(e.getStatus()); 470 } 471 if (feature == null) 472 return null; 473 474 String featureRoot = feature.getRootLocation(); 475 if (featureRoot != null) 476 return checkFile(new Path(featureRoot), path, makeRelative); 477 return null; 478 } 479 findConfigFile(ProductFile productFile, String os)480 protected String findConfigFile(ProductFile productFile, String os) { 481 String path = productFile.getConfigIniPath(os); 482 if (path == null) 483 return null; 484 485 String result = findFile(path, false); 486 if (result != null) 487 return result; 488 489 // couldn't find productFile, try it as a path directly 490 File f = new File(path); 491 if (f.exists() && f.isFile()) 492 return f.getAbsolutePath(); 493 494 // relative to the working directory 495 f = new File(getWorkingDirectory(), path); 496 if (f.exists() && f.isFile()) 497 return f.getAbsolutePath(); 498 499 // relative to the working directory/plugins 500 f = new File(getWorkingDirectory() + "/" + DEFAULT_PLUGIN_LOCATION, path); //$NON-NLS-1$ 501 if (f.exists() && f.isFile()) 502 return f.getAbsolutePath(); 503 504 //relative to .product file 505 f = new File(productFile.getLocation().getParent(), path); 506 if (f.exists() && f.isFile()) 507 return f.getAbsolutePath(); 508 509 return null; 510 } 511 checkFile(IPath base, Path target, boolean makeRelative)512 private String checkFile(IPath base, Path target, boolean makeRelative) { 513 IPath path = base.append(target.removeFirstSegments(1)); 514 String result = path.toOSString(); 515 if (!new File(result).exists()) 516 return null; 517 if (makeRelative) 518 return Utils.makeRelative(path, new Path(workingDirectory)).toOSString(); 519 return result; 520 } 521 setFilterState(boolean filter)522 public void setFilterState(boolean filter) { 523 filterState = filter; 524 } 525 setFilterP2Base(boolean filter)526 public void setFilterP2Base(boolean filter) { 527 filterP2Base = filter; 528 } 529 getDownloadCacheLocation(IProvisioningAgent agent)530 static private URI getDownloadCacheLocation(IProvisioningAgent agent) { 531 IAgentLocation location = (IAgentLocation) agent.getService(IAgentLocation.SERVICE_NAME); 532 if (location == null) 533 return null; 534 return URIUtil.append(location.getDataArea("org.eclipse.equinox.p2.core"), "cache/"); //$NON-NLS-1$ //$NON-NLS-2$ 535 } 536 setContextArtifacts(URI[] uris)537 protected void setContextArtifacts(URI[] uris) { 538 contextArtifacts = uris; 539 } 540 setContextMetadata(URI[] uris)541 protected void setContextMetadata(URI[] uris) { 542 contextMetadata = uris; 543 } 544 setContextMetadataRepositories(URI[] uris)545 public void setContextMetadataRepositories(URI[] uris) { 546 Set<URI> uriSet = new HashSet<>(); 547 uriSet.addAll(Arrays.asList(uris)); 548 549 for (int i = 0; i < uris.length; i++) { 550 //try and find additional repos associated with a profile 551 File uriFile = URIUtil.toFile(uris[i]); 552 uriSet.addAll(getAssociatedRepositories(uriFile)); 553 } 554 555 addContextRepos(uriSet.toArray(new URI[uriSet.size()])); 556 } 557 addContextRepos(URI[] repos)558 protected void addContextRepos(URI[] repos) { 559 List<URI> metadata = filterRepos(repos, METADATA_REPO_FILTER); 560 List<URI> artifacts = filterRepos(repos, ARTIFACT_REPO_FILTER); 561 562 if (contextMetadata != null) { 563 Set<URI> uriSet = new HashSet<>(); 564 uriSet.addAll(Arrays.asList(contextMetadata)); 565 uriSet.addAll(metadata); 566 contextMetadata = uriSet.toArray(new URI[uriSet.size()]); 567 } else { 568 contextMetadata = metadata.toArray(new URI[metadata.size()]); 569 } 570 571 if (contextArtifacts != null) { 572 Set<URI> uriSet = new HashSet<>(); 573 uriSet.addAll(Arrays.asList(contextArtifacts)); 574 uriSet.addAll(artifacts); 575 contextArtifacts = uriSet.toArray(new URI[uriSet.size()]); 576 } else { 577 contextArtifacts = artifacts.toArray(new URI[artifacts.size()]); 578 } 579 } 580 581 //return only the metadata repos, and also the ones we aren't sure about filterRepos(URI[] contexts, FilenameFilter repoFilter)582 private List<URI> filterRepos(URI[] contexts, FilenameFilter repoFilter) { 583 if (contexts == null) 584 return null; 585 ArrayList<URI> result = new ArrayList<>(); 586 for (int i = 0; i < contexts.length; i++) { 587 File repo = URIUtil.toFile(contexts[i]); 588 if (repo == null) { 589 //remote, not sure, just use it 590 result.add(contexts[i]); 591 } else { 592 String[] list = repo.list(repoFilter); 593 if (list != null && list.length > 0) 594 result.add(contexts[i]); 595 } 596 } 597 return result; 598 } 599 getAssociatedRepositories(File profileFile)600 private List<URI> getAssociatedRepositories(File profileFile) { 601 if (profileFile == null || !profileFile.exists() || !profileFile.getName().endsWith(".profile")) //$NON-NLS-1$ 602 return Collections.emptyList(); 603 604 ArrayList<URI> result = new ArrayList<>(); 605 URI profileURI = profileFile.toURI(); 606 result.add(profileURI); 607 608 Map<String, Object> profileInfo = extractProfileInformation(profileFile); 609 if (profileInfo == null) 610 return result; 611 612 File areaFile = new File((String) profileInfo.get(PROFILE_DATA_AREA)); 613 if (areaFile.exists()) { 614 IProvisioningAgent agent = BundleHelper.getDefault().getProvisioningAgent(areaFile.toURI()); 615 if (agent != null) { 616 IProfileRegistry registry = new SimpleProfileRegistry(agent, (File) profileInfo.get(PROFILE_REGISTRY), null, false); 617 try { 618 long timestamp = ((Long) profileInfo.get(PROFILE_TIMESTAMP)).longValue(); 619 String profileId = (String) profileInfo.get(PROFILE_ID); 620 if (timestamp == -1L) { 621 long[] timestamps = registry.listProfileTimestamps(profileId); 622 if (timestamps.length > 0) 623 timestamp = timestamps[timestamps.length - 1]; 624 } 625 626 //specifying the timestamp avoids attempting to lock the profile registry 627 //which could be a problem if it is read only. 628 if (timestamp > 0) { 629 IProfile profile = registry.getProfile(profileId, timestamp); 630 if (profile != null) { 631 String cache = profile.getProperty(IProfile.PROP_CACHE); 632 if (cache != null) { 633 File cacheFolder = new File(cache); 634 if (cacheFolder.exists()) { 635 result.add(cacheFolder.toURI()); 636 } else { 637 //if cache does not exist, this could be a roaming profile that has not 638 //been run yet, lets guess and use the parent of the p2 data area 639 result.add(areaFile.getParentFile().toURI()); 640 } 641 } 642 String sharedCache = profile.getProperty(IProfile.PROP_SHARED_CACHE); 643 if (sharedCache != null) 644 result.add(new File(cache).toURI()); 645 String dropinRepositories = profile.getProperty("org.eclipse.equinox.p2.cache.extensions"); //$NON-NLS-1$ 646 if (dropinRepositories != null) { 647 // #filterRepos will remove any dropin folders that require synchronization 648 StringTokenizer tokenizer = new StringTokenizer(dropinRepositories, "|"); //$NON-NLS-1$ 649 while (tokenizer.hasMoreTokens()) { 650 try { 651 result.add(new URI(tokenizer.nextToken())); 652 } catch (URISyntaxException e) { 653 //skip 654 } 655 } 656 } 657 } 658 } 659 } catch (IllegalStateException e) { 660 //unable to read profile, may be read only 661 result.add(areaFile.getParentFile().toURI()); 662 } 663 664 //download cache 665 URI download = getDownloadCacheLocation(agent); 666 if (URIUtil.toFile(download).exists()) 667 result.add(download); 668 } 669 } 670 return result; 671 } 672 673 private static String PROFILE_TIMESTAMP = "timestamp"; //$NON-NLS-1$ 674 private static String PROFILE_ID = "profileId"; //$NON-NLS-1$ 675 private static String PROFILE_DATA_AREA = "dataArea"; //$NON-NLS-1$ 676 private static String PROFILE_REGISTRY = "registry"; //$NON-NLS-1$ 677 extractProfileInformation(File target)678 private static Map<String, Object> extractProfileInformation(File target) { 679 if (target == null || !target.exists()) 680 return null; 681 682 IPath path = new Path(target.getAbsolutePath()); 683 if (!path.lastSegment().endsWith(PROFILE) && !path.lastSegment().endsWith(PROFILE_GZ)) 684 return null; 685 686 //expect at least "p2/org.eclipse.equinox.p2.engine/profileRegistry/Profile.profile" 687 if (path.segmentCount() < 4) 688 return null; 689 690 Map<String, Object> results = new HashMap<>(); 691 results.put(PROFILE_TIMESTAMP, Long.valueOf(-1)); 692 693 String profileId = null; 694 if (target.isFile()) { 695 //p2/org.eclipse.equinox.p2.engine/profileRegistry/Profile.profile/123456.profile.gz 696 if (path.segmentCount() < 5) 697 return null; 698 699 String timestamp = path.lastSegment(); 700 int idx = timestamp.indexOf('.'); 701 if (idx > 0) { 702 timestamp = timestamp.substring(0, idx); 703 try { 704 results.put(PROFILE_TIMESTAMP, Long.valueOf(timestamp)); 705 } catch (NumberFormatException e) { 706 //not a timestamp? 707 } 708 } 709 710 path = path.removeLastSegments(1); 711 profileId = path.removeFileExtension().lastSegment(); 712 } else { 713 //target is the profile folder 714 profileId = path.removeFileExtension().lastSegment(); 715 } 716 717 profileId = SimpleProfileRegistry.unescape(profileId); 718 results.put(PROFILE_ID, profileId); 719 720 //remove Profile.profile to get the registry folder 721 path = path.removeLastSegments(1); 722 results.put(PROFILE_REGISTRY, path.toFile()); 723 724 //removing "org.eclipse.equinox.p2.engine/profileRegistry" 725 path = path.removeLastSegments(2); 726 results.put(PROFILE_DATA_AREA, path.toOSString()); 727 728 return results; 729 } 730 getContextMetadata()731 public URI[] getContextMetadata() { 732 return contextMetadata; 733 } 734 getContextArtifacts()735 public URI[] getContextArtifacts() { 736 return contextArtifacts; 737 } 738 setProductQualifier(String value)739 public void setProductQualifier(String value) { 740 productQualifier = value; 741 } 742 743 /* 744 * If the user has specified a platform properties then load it. 745 */ setPlatformProperties(String filename)746 public void setPlatformProperties(String filename) { 747 if (filename == null || filename.trim().length() == 0) 748 return; 749 File file = new File(filename); 750 if (!file.exists()) 751 return; 752 platformProperties = new Properties(); 753 InputStream input = null; 754 try { 755 input = new BufferedInputStream(new FileInputStream(file)); 756 platformProperties.load(input); 757 } catch (IOException e) { 758 platformProperties = null; 759 String message = NLS.bind(Messages.error_loading_platform_properties, filename); 760 IStatus status = new Status(IStatus.WARNING, IPDEBuildConstants.PI_PDEBUILD, message, e); 761 BundleHelper.getDefault().getLog().log(status); 762 } finally { 763 if (input != null) 764 try { 765 input.close(); 766 } catch (IOException e) { 767 // ignore 768 } 769 } 770 } 771 generateProductReplaceTask(ProductFile product, String productFilePath, AssemblyInformation assemblyInfo)772 protected void generateProductReplaceTask(ProductFile product, String productFilePath, AssemblyInformation assemblyInfo) { 773 if (product == null) 774 return; 775 776 BuildTimeSite site = null; 777 try { 778 site = getSite(false); 779 } catch (CoreException e1) { 780 return; 781 } 782 783 String version = product.getVersion(); 784 if (version.endsWith(PROPERTY_QUALIFIER)) { 785 Version oldVersion = new Version(version); 786 version = oldVersion.getMajor() + "." + oldVersion.getMinor() + "." + oldVersion.getMicro() + "." + Utils.getPropertyFormat(PROPERTY_P2_PRODUCT_QUALIFIER); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ 787 } 788 789 List<FeatureEntry> productEntries = product.getProductEntries(); 790 String mappings = Utils.getEntryVersionMappings(productEntries.toArray(new FeatureEntry[productEntries.size()]), site, assemblyInfo); 791 792 script.println("<eclipse.idReplacer productFilePath=\"" + AntScript.getEscaped(productFilePath) + "\""); //$NON-NLS-1$ //$NON-NLS-2$ 793 script.println(" selfVersion=\"" + version + "\" "); //$NON-NLS-1$ //$NON-NLS-2$ 794 if (product.useFeatures()) 795 script.println(" featureIds=\"" + mappings + "\"/>"); //$NON-NLS-1$ //$NON-NLS-2$ 796 else 797 script.println(" pluginIds=\"" + mappings + "\"/>"); //$NON-NLS-1$ //$NON-NLS-2$ 798 799 return; 800 } 801 } 802