diff options
7 files changed, 876 insertions, 0 deletions
diff --git a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/AbstractProvisioningTest.java b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/AbstractProvisioningTest.java index 19fee34da..65a7dcd2f 100644 --- a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/AbstractProvisioningTest.java +++ b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/AbstractProvisioningTest.java @@ -1020,6 +1020,10 @@ public abstract class AbstractProvisioningTest extends TestCase { req.setInstallableUnitInclusionRules(ius[i], strict ? ProfileInclusionRules.createStrictInclusionRule(ius[i]) : ProfileInclusionRules.createOptionalInclusionRule(ius[i])); } + return install(req, planner, engine); + } + + protected IStatus install(ProfileChangeRequest req, IPlanner planner, IEngine engine) { IProvisioningPlan plan = planner.getProvisioningPlan(req, null, null); if (plan.getStatus().getSeverity() == IStatus.ERROR || plan.getStatus().getSeverity() == IStatus.CANCEL) return plan.getStatus(); diff --git a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/IUDescription.java b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/IUDescription.java new file mode 100644 index 000000000..6b667f8d3 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/IUDescription.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * Copyright (c) 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 implementation and ideas + ******************************************************************************/ + +package org.eclipse.equinox.p2.tests; + +import java.lang.annotation.*; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD, ElementType.LOCAL_VARIABLE}) +public @interface IUDescription { + public String content(); +} diff --git a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/IULoader.java b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/IULoader.java new file mode 100644 index 000000000..ca17737bc --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/IULoader.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 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 implementation and ideas + ******************************************************************************/ +package org.eclipse.equinox.p2.tests; + +import java.io.*; +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; + +public class IULoader { + + private static Annotation[] annos; + + public static void loadIUs(Object o) { + Class<? extends Object> classWithIUs = o.getClass(); + annos = classWithIUs.getAnnotations(); + for (int i = 0; i < annos.length; i++) { + System.out.println(annos[i]); + } + + Field[] fields = classWithIUs.getFields(); + for (int i = 0; i < fields.length; i++) { + Annotation[] a = fields[i].getAnnotations(); + for (int j = 0; j < a.length; j++) { + if (a[j] instanceof IUDescription) { + IUDescription ml = (IUDescription) a[j]; // here it is !!! + ReducedCUDFParser parser = new ReducedCUDFParser(); + InputStream is = new ByteArrayInputStream(ml.content().getBytes()); + parser.parse(is, false, null); + try { + fields[i].set(o, parser.getIU()); + is.close(); + } catch (IllegalArgumentException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + } + } +} diff --git a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/ReducedCUDFParser.java b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/ReducedCUDFParser.java new file mode 100644 index 000000000..1f2917fb0 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/ReducedCUDFParser.java @@ -0,0 +1,608 @@ +/******************************************************************************* + * Copyright (c) 2009 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: + * IBM Corporation - initial implementation and ideas + * Sonatype Inc. - trim down for annotation work + ******************************************************************************/ + +package org.eclipse.equinox.p2.tests; + +import java.io.*; +import java.util.*; +import org.eclipse.equinox.internal.p2.metadata.*; +import org.eclipse.equinox.p2.metadata.*; +import org.eclipse.equinox.p2.metadata.MetadataFactory.InstallableUnitDescription; + +public class ReducedCUDFParser { + + private static final boolean DEBUG = false; //TO SET TO FALSE FOR COMPETITION + private static final boolean TIMING = true; //TO SET TO FALSE FOR COMPETITION + private InstallableUnitDescription currentIU = null; + // private ProfileChangeRequest currentRequest = null; + private List allIUs = new ArrayList(); + // private QueryableArray query = null; + private List currentKeepRequests = new ArrayList(); + + class Tuple { + String name; + String version; + String operator; + Set extraData; + + Tuple(String line) { + String[] tuple = new String[3]; + int i = 0; + for (StringTokenizer iter = new StringTokenizer(line, " \t"); iter.hasMoreTokens(); i++) + tuple[i] = iter.nextToken().trim(); + name = tuple[0]; + operator = tuple[1]; + version = tuple[2]; + } + } + + // + // public ProfileChangeRequest parse(File file) { + // return parse(file, false, null); + // } + // + // public ProfileChangeRequest parse(File file, boolean includeRecommends, String sumProperty) { + // try { + // return parse(new FileInputStream(file), includeRecommends, sumProperty); + // } catch (FileNotFoundException e) { + // e.printStackTrace(); + // return null; + // } + // } + // + // public ProfileChangeRequest parse(InputStream stream) { + // return parse(stream, false, null); + // } + // + // public ProfileChangeRequest parse(InputStream stream, String sumProperty) { + // return parse(stream, false, sumProperty); + // } + + public void parse(InputStream stream, boolean includeRecommends, String sumProperty) { + BufferedReader reader = null; + try { + reader = new BufferedReader(new InputStreamReader(stream, "UTF-8")); + String next = reader.readLine(); + while (true) { + + // look-ahead to check for line continuation + String line = next; + for (next = reader.readLine(); next != null && next.length() > 1 && next.charAt(0) == ' '; next = reader.readLine()) { + line = line + next.substring(1); + } + + // terminating condition of the loop... reached the end of the file + if (line == null) { + validateAndAddIU(); + break; + } + + // end of stanza + if (line.trim().length() == 0) { + validateAndAddIU(); + continue; + } + + // preamble stanza + if (line.startsWith("#") || line.startsWith("preamble: ") || line.startsWith("property: ") || line.startsWith("univ-checksum: ")) { + // ignore + } + + // // request stanza + // else if (line.startsWith("request: ")) { + // handleRequest(line); + // } else if (line.startsWith("install: ")) { + // handleInstall(line); + // } else if (line.startsWith("upgrade: ")) { + // handleUpgrade(line); + // } else if (line.startsWith("remove: ")) { + // handleRemove(line); + // } + + // package stanza + else if (line.startsWith("package: ")) { + handlePackage(line); + } else if (line.startsWith("version: ")) { + handleVersion(line); + // } else if (line.startsWith("installed: ")) { + // handleInstalled(line); + } else if (line.startsWith("depends: ")) { + handleDepends(line); + // } else if (line.startsWith("conflicts: ")) { + // handleConflicts(line); + } else if (line.startsWith("provides: ")) { + handleProvides(line); + } else if (line.startsWith("singleton:")) { + handleSingleton(line); + } + // } else if (line.startsWith("expected: ")) { + // handleExpected(line); + // } else if (line.startsWith("recommends: ") && includeRecommends) { + // handleRecommends(line); + // } else if (line.startsWith("keep: ")) { + // handleKeep(line); + // } else if (sumProperty != null && line.startsWith(sumProperty + ":")) { + // handleSumProperty(line, sumProperty); + // } + } + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (reader != null) + try { + reader.close(); + } catch (IOException e) { + // ignore + } + } + if (TIMING) + // Log.println("Time to parse:" + (System.currentTimeMillis() - start)); + if (DEBUG) + for (Iterator iter = allIUs.iterator(); iter.hasNext();) + debug((InstallableUnit) iter.next()); + // if (FORCE_QUERY) { + // if (query == null) + // initializeQueryableArray(); + // if (currentRequest == null) + // currentRequest = new ProfileChangeRequest(query); + // } + // debug(currentRequest); + // return currentRequest; + } + + // private void handleSumProperty(String line, String sumProperty) { + // String value = line.substring(sumProperty.length() + 1).trim(); + // try { + // currentIU.setSumProperty(Long.valueOf(value)); + // } catch (NumberFormatException ex) { + // throw new IllegalArgumentException("The value \"" + value + "\" of property \"" + sumProperty + "\" cannot be summed up"); + // } + // } + + // private void handleKeep(String line) { + // line = line.substring("keep: ".length()); + // if (line.contains("version")) { + // currentKeepRequests.add(MetadataFactory.createRequirement(IInstallableUnit.NAMESPACE_IU_ID, currentIU.getId(), new VersionRange(currentIU.getVersion(), true, currentIU.getVersion(), true), null, false, false, true)); + // return; + // } + // if (line.contains("package")) { + // currentKeepRequests.add(new RequiredCapability(currentIU.getId(), VersionRange.emptyRange, false)); + // return; + // } + // if (line.contains("none")) + // return; + // if (line.contains("feature")) { + // IProvidedCapability[] caps = currentIU.getProvidedCapabilities(); + // for (int i = 0; i < caps.length; i++) { + // if (!caps[i].getName().equals(currentIU.getId())) + // currentKeepRequests.add(new RequiredCapability(caps[i].getName(), caps[i].getVersion(), false)); + // } + // } + // + // } + + // private void handleExpected(String line) { + // currentRequest.setExpected(Integer.decode(line.substring("expected: ".length()).trim()).intValue()); + // } + + private void handleSingleton(String line) { + currentIU.setSingleton(line.contains("true") ? true : false); + } + + /* + * Ensure that the current IU that we have been building is validate and if so, then + * add it to our collected list of all converted IUs from the file. + */ + private void validateAndAddIU() { + if (currentIU == null) + return; + // For a package stanza, the id and version are the only mandatory elements + if (currentIU.getId() == null) + throw new IllegalStateException("Malformed \'package\' stanza. No package element found."); + if (currentIU.getVersion() == null) + throw new IllegalStateException("Malformed \'package\' stanza. Package " + currentIU.getId() + " does not have a version."); + if (currentIU.getProvidedCapabilities().size() == 0) { + currentIU.setCapabilities(new IProvidedCapability[] {MetadataFactory.createProvidedCapability(IInstallableUnit.NAMESPACE_IU_ID, currentIU.getId(), currentIU.getVersion()), MetadataFactory.createProvidedCapability(IInstallableUnit.NAMESPACE_IU_ID, currentIU.getId(), currentIU.getVersion())}); + } + currentIU.setUpdateDescriptor(MetadataFactory.createUpdateDescriptor(currentIU.getId(), new VersionRange(Version.emptyVersion, true, currentIU.getVersion(), false), IUpdateDescriptor.NORMAL, null)); + // if (currentIU.isInstalled()) { + // keepRequests.addAll(currentKeepRequests); + // } + allIUs.add(MetadataFactory.createInstallableUnit(currentIU)); + // reset to be ready for the next stanza + currentIU = null; + currentKeepRequests.clear(); + } + + // private void handleInstalled(String line) { + // String value = line.substring("installed: ".length()); + // if (value.length() != 0) { + // if (DEBUG) + // if (!Boolean.valueOf(value).booleanValue()) { + // System.err.println("Unexcepted value for installed."); + // return; + // } + // currentIU.setInstalled(true); + // preInstalled.add(new RequiredCapability(currentIU.getId(), new VersionRange(currentIU.getVersion()), true)); + // } + // } + + // private void handleInstall(String line) { + // line = line.substring("install: ".length()); + // List installRequest = createRequires(line, true, false, true); + // for (Iterator iterator = installRequest.iterator(); iterator.hasNext();) { + // currentRequest.addInstallableUnit((IRequiredCapability) iterator.next()); + // } + // return; + // } + + // private void handleRequest(String line) { + // initializeQueryableArray(); + // currentRequest = new ProfileChangeRequest(query); + // currentRequest.setPreInstalledIUs(preInstalled); + // currentRequest.setContrainstFromKeep(keepRequests); + // } + // + // private void handleRemove(String line) { + // line = line.substring("remove: ".length()); + // List removeRequest = createRequires(line, true, false, true); + // for (Iterator iterator = removeRequest.iterator(); iterator.hasNext();) { + // currentRequest.removeInstallableUnit((IRequiredCapability) iterator.next()); + // } + // return; + // } + + // private void initializeQueryableArray() { + // query = new QueryableArray((InstallableUnit[]) allIUs.toArray(new InstallableUnit[allIUs.size()])); + // } + + // private void handleUpgrade(String line) { + // line = line.substring("upgrade: ".length()); + // List updateRequest = createRequires(line, true, false, true); + // for (Iterator iterator = updateRequest.iterator(); iterator.hasNext();) { + // IRequiredCapability requirement = (IRequiredCapability) iterator.next(); + // currentRequest.upgradeInstallableUnit(requirement); + // + // //Add a requirement forcing uniqueness of the upgraded package in the resulting solution + // currentRequest.upgradeInstallableUnit(new RequiredCapability(requirement.getName(), VersionRange.emptyRange, 1)); + // + // //Add a requirement forcing the solution to be greater or equal to the highest installed version + // requirement = getHighestInstalledVersion(requirement); + // if (requirement != null) + // currentRequest.upgradeInstallableUnit(requirement); + // } + // return; + // } + // + // private IRequiredCapability getHighestInstalledVersion(IRequiredCapability req) { + // Version highestVersion = null; + // Collector c = query.query(new CapabilityQuery(req), new Collector(), null); + // for (Iterator iterator = c.iterator(); iterator.hasNext();) { + // InstallableUnit candidate = (InstallableUnit) iterator.next(); + // if (!candidate.isInstalled()) + // continue; + // if (candidate.getId().equals(req.getName())) { + // if (highestVersion == null || candidate.getVersion().getMajor() > highestVersion.getMajor()) + // highestVersion = candidate.getVersion(); + // } else { + // //Requesting the upgrade of a virtual package + // IProvidedCapability[] prov = candidate.getProvidedCapabilities(); + // for (int i = 0; i < prov.length; i++) { + // if (prov[i].getVersion().equals(VersionRange.emptyRange)) + // continue; + // if (prov[i].getName().equals(req.getName()) && (highestVersion == null || prov[i].getVersion().getMinimum().getMajor() > highestVersion.getMajor())) + // highestVersion = prov[i].getVersion().getMinimum(); + // } + // } + // } + // if (highestVersion == null) + // return null; + // return new RequiredCapability(req.getName(), new VersionRange(highestVersion, true, Version.maxVersion, true)); + // } + + /* + * Convert the version string to a version object and set it on the IU + */ + private void handleVersion(String line) { + currentIU.setVersion(Version.create(cudfPosintToInt(line.substring("version: ".length())))); + } + + private String cudfPosintToInt(String posint) { + if (posint.startsWith("+")) { + return posint.substring(1).trim(); + } + return posint.trim(); + } + + private void handleDepends(String line) { + mergeRequirements(createRequires(line.substring("depends: ".length()), true, false, true)); + } + + // private void handleRecommends(String line) { + // mergeRequirements(createRequires(line.substring("recommends: ".length()), true, true, true)); + // } + + /* + * Conflicts are like depends except NOT'd. + */ + //TODO Remove conflict for now + // private void handleConflicts(String line) { + // List reqs = createRequires(line.substring("conflicts: ".length()), false, false, false); + // List conflicts = new ArrayList(); + // for (Iterator iter = reqs.iterator(); iter.hasNext();) { + // IRequiredCapability req = (IRequiredCapability) iter.next(); + // if (currentIU.getId().equals(req.getName()) && req.getRange().equals(VersionRange.emptyRange)) { + // currentIU.setSingleton(true); + // } else { + // conflicts.add(new NotRequirement(req)); + // } + // } + // mergeRequirements(conflicts); + // } + + /* + * Set the given list of requirements on teh current IU. Merge if necessary. + */ + private void mergeRequirements(List requirements) { + if (currentIU.getRequiredCapabilities() != null) { + List<IRequirement> current = currentIU.getRequiredCapabilities(); + for (IRequirement iRequirement : current) { + requirements.add(iRequirement); + } + } + currentIU.setRequirements((IRequiredCapability[]) requirements.toArray(new IRequiredCapability[requirements.size()])); + } + + /* + * Returns a map where the key is the package name and the value is a Tuple. + * If there is more than one entry for a particular package, the extra entries are included + * in the extraData field of the Tuple. + */ + private List createPackageList(String line) { + StringTokenizer tokenizer = new StringTokenizer(line, ","); + List result = new ArrayList(tokenizer.countTokens()); + while (tokenizer.hasMoreElements()) { + result.add(new Tuple(tokenizer.nextToken())); + } + return result; + } + + private List createRequires(String line, boolean expandNotEquals, boolean optional, boolean dependency) { + ArrayList ands = new ArrayList(); + StringTokenizer s = new StringTokenizer(line, ","); + String subtoken; + while (s.hasMoreElements()) { + StringTokenizer subTokenizer = new StringTokenizer(s.nextToken(), "|"); + if (subTokenizer.countTokens() == 1) { //This token does not contain a |. + subtoken = subTokenizer.nextToken().trim(); + // FIXME should be handled differently in depends and conflicts. + if ("true!".equals(subtoken)) { + if (dependency) + continue; + throw new RuntimeException("Cannot have true! in a conflict!!!!!"); + } + if ("false!".equals(subtoken)) { + if (!dependency) + continue; + throw new RuntimeException("Cannot have false! in a dependency!!!!!"); + } + Object o = createRequire(subtoken, expandNotEquals, optional); + if (o instanceof IRequiredCapability) + ands.add(o); + else + ands.addAll((Collection) o); + continue; + } + + IRequiredCapability[] ors = new RequiredCapability[subTokenizer.countTokens()]; + int i = 0; + while (subTokenizer.hasMoreElements()) { + ors[i++] = (IRequiredCapability) createRequire(subTokenizer.nextToken().trim(), expandNotEquals, optional); + } + //TODO Remove OR'ing from requirements for now + // ands.add(new ORRequirement(ors, optional)); + } + return ands; + } + + private Object createRequire(String nextToken, boolean expandNotEquals, boolean optional) { + //>, >=, =, <, <=, != + StringTokenizer expressionTokens = new StringTokenizer(nextToken.trim(), ">=!<", true); + int tokenCount = expressionTokens.countTokens(); + + if (tokenCount == 1) // a + return MetadataFactory.createRequirement(IInstallableUnit.NAMESPACE_IU_ID, expressionTokens.nextToken().trim(), VersionRange.emptyRange, null, optional, false, true); + + if (tokenCount == 3) // a > 2, a < 2, a = 2 + return MetadataFactory.createRequirement(IInstallableUnit.NAMESPACE_IU_ID, expressionTokens.nextToken().trim(), createRange3(expressionTokens.nextToken(), expressionTokens.nextToken()), null, optional, false, true); + + if (tokenCount == 4) { //a >= 2, a <=2, a != 2 + String id = expressionTokens.nextToken().trim(); + String signFirstChar = expressionTokens.nextToken(); + expressionTokens.nextToken();//skip second char of the sign + String version = expressionTokens.nextToken().trim(); + if (!("!".equals(signFirstChar))) // a >= 2 a <= 2 + return MetadataFactory.createRequirement(IInstallableUnit.NAMESPACE_IU_ID, id, createRange4(signFirstChar, version), null, optional, false, true); + + // //a != 2 TODO To uncomment + // if (expandNotEquals) { + // return new ORRequirement(new IRequiredCapability[] {new RequiredCapability(id, createRange3("<", version), optional), new RequiredCapability(id, createRange3(">", version), optional)}, optional); + // } + ArrayList res = new ArrayList(2); + res.add(MetadataFactory.createRequirement(IInstallableUnit.NAMESPACE_IU_ID, id, createRange3("<", version), null, optional, false, true)); + res.add(MetadataFactory.createRequirement(IInstallableUnit.NAMESPACE_IU_ID, id, createRange3(">", version), null, optional, false, true)); + return res; + } + return null; + } + + private VersionRange createRange3(String sign, String versionAsString) { + int version = Integer.decode(cudfPosintToInt(versionAsString)).intValue(); + sign = sign.trim(); + if (">".equals(sign)) + return new VersionRange(Version.createOSGi(version, 0, 0), false, Version.MAX_VERSION, false); + if ("<".equals(sign)) + return new VersionRange(Version.emptyVersion, false, Version.createOSGi(version, 0, 0), false); + if ("=".equals(sign)) + return new VersionRange(Version.createOSGi(version, 0, 0), true, Version.createOSGi(version, 0, 0), true); + throw new IllegalArgumentException(sign); + } + + private VersionRange createRange4(String sign, String versionAsString) { + int version = Integer.decode(cudfPosintToInt(versionAsString)).intValue(); + if (">".equals(sign)) //THIS IS FOR >= + return new VersionRange(Version.createOSGi(version, 0, 0), true, Version.MAX_VERSION, false); + if ("<".equals(sign)) //THIS IS FOR <= + return new VersionRange(Version.emptyVersion, false, Version.createOSGi(version, 0, 0), true); + return null; + } + + private IProvidedCapability createProvidedCapability(Tuple tuple) { + //At this point the parser only deal with standard provided capabilities and not ranges like cudf does. + assert tuple.extraData == null; + assert tuple.operator == null; + return MetadataFactory.createProvidedCapability(IInstallableUnit.NAMESPACE_IU_ID, tuple.name, Version.create(tuple.version)); + // Set extraData = tuple.extraData; + // one constraint so simply return the capability + // if (extraData == null) + // return new ProvidedCapability(tuple.name, createVersionRange(tuple.operator, tuple.version)); + // // 2 constraints (e.g. a>=1, a<4) so create a real range like a[1,4) + // if (extraData.size() == 1) + // return new ProvidedCapability(tuple.name, createVersionRange(tuple, (Tuple) extraData.iterator().next())); + // // TODO merge more than 2 requirements (a>2, a<4, a>3) + // return new ProvidedCapability(tuple.name, createVersionRange(tuple.operator, tuple.version)); + } + + /* + * Create and return a version range object which merges the 2 given versions and operators. + * e.g a>=1 and a<4 becomes a[1,4) + */ + // private VersionRange createVersionRange(Tuple t1, Tuple t2) { + // Version one = Version.parseVersion(t1.version); + // Version two = Version.parseVersion(t2.version); + // if (one.compareTo(two) < 0) { + // return new VersionRange(one, include(t1.operator), two, include(t2.operator)); + // } else if (one.compareTo(two) == 0) { + // return new VersionRange(one, include(t1.operator), one, include(t1.operator)); + // } else if (one.compareTo(two) > 0) { + // return new VersionRange(two, include(t2.operator), one, include(t1.operator)); + // } + // // should never reach this. avoid compile error. + // return null; + // } + + /* + * Helper method for when we are creating version ranges and calculating "includeMin/Max". + */ + // private boolean include(String operator) { + // return "=".equals(operator) || "<=".equals(operator) || ">=".equals(operator); + // } + // + // /* + // * Create and return a version range based on the given operator and number. Note that != is + // * handled elsewhere. + // */ + // private VersionRange createVersionRange(String operator, String number) { + // if (operator == null || number == null) + // return VersionRange.emptyRange; + // if ("=".equals(operator)) + // return new VersionRange('[' + number + ',' + number + ']'); + // if ("<".equals(operator)) + // return new VersionRange("[0," + number + ')'); + // if (">".equals(operator)) + // return new VersionRange('(' + number + ',' + Integer.MAX_VALUE + ']'); + // if ("<=".equals(operator)) + // return new VersionRange("[0," + number + ']'); + // if (">=".equals(operator)) + // return new VersionRange('[' + number + ',' + Integer.MAX_VALUE + ']'); + // return VersionRange.emptyRange; + // } + + // package name matches: "^[a-zA-Z0-9+./@()%-]+$" + private void handlePackage(String readLine) { + currentIU = new MetadataFactory.InstallableUnitDescription(); + currentIU.setId(readLine.substring("package: ".length()).trim()); + } + + private void handleProvides(String line) { + line = line.substring("provides: ".length()); + List pkgs = createPackageList(line); + IProvidedCapability[] providedCapabilities = new ProvidedCapability[pkgs.size() + 2]; + int i = 0; + for (Iterator iter = pkgs.iterator(); iter.hasNext();) { + providedCapabilities[i++] = createProvidedCapability((Tuple) iter.next()); + } + providedCapabilities[i++] = MetadataFactory.createProvidedCapability(IInstallableUnit.NAMESPACE_IU_ID, currentIU.getId(), currentIU.getVersion()); + providedCapabilities[i++] = MetadataFactory.createProvidedCapability(IInstallableUnit.NAMESPACE_IU_ID, currentIU.getId(), currentIU.getVersion()); + currentIU.setCapabilities(providedCapabilities); + } + + // // copied from ProfileSynchronizer + // private void debug(ProfileChangeRequest request) { + // if (!DEBUG || request == null) + // return; + // // Log.println("\nProfile Change Request:"); + // // InstallableUnit[] toAdd = request.getAddedInstallableUnit(); + // // if (toAdd == null || toAdd.length == 0) { + // // Log.println("No installable units to add."); + // // } else { + // // for (int i = 0; i < toAdd.length; i++) + // // Log.println("Adding IU: " + toAdd[i].getId() + ' ' + toAdd[i].getVersion()); + // // } + // // Map propsToAdd = request.getInstallableUnitProfilePropertiesToAdd(); + // // if (propsToAdd == null || propsToAdd.isEmpty()) { + // // Log.println("No IU properties to add."); + // // } else { + // // for (Iterator iter = propsToAdd.keySet().iterator(); iter.hasNext();) { + // // Object key = iter.next(); + // // Log.println("Adding IU property: " + key + "->" + propsToAdd.get(key)); + // // } + // // } + // // + // // InstallableUnit[] toRemove = request.getRemovedInstallableUnits(); + // // if (toRemove == null || toRemove.length == 0) { + // // Log.println("No installable units to remove."); + // // } else { + // // for (int i = 0; i < toRemove.length; i++) + // // Log.println("Removing IU: " + toRemove[i].getId() + ' ' + toRemove[i].getVersion()); + // // } + // // Map propsToRemove = request.getInstallableUnitProfilePropertiesToRemove(); + // // if (propsToRemove == null || propsToRemove.isEmpty()) { + // // Log.println("No IU properties to remove."); + // // } else { + // // for (Iterator iter = propsToRemove.keySet().iterator(); iter.hasNext();) { + // // Object key = iter.next(); + // // Log.println("Removing IU property: " + key + "->" + propsToRemove.get(key)); + // // } + // // } + // } + + // dump info to console + private void debug(InstallableUnit unit) { + // if (!DEBUG) + // return; + // Log.println("\nInstallableUnit: " + unit.getId()); + // Log.println("Version: " + unit.getVersion()); + // if (unit.isInstalled()) + // Log.println("Installed: true"); + // IRequiredCapability[] reqs = unit.getRequiredCapabilities(); + // for (int i = 0; i < reqs.length; i++) { + // Log.println("Requirement: " + reqs[i]); + // } + } + + public IInstallableUnit getIU() { + assert allIUs.size() == 1; + return (IInstallableUnit) allIUs.get(0); + } +} diff --git a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/planner/LuckyHelper.java b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/planner/LuckyHelper.java new file mode 100644 index 000000000..70951f0ad --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/planner/LuckyHelper.java @@ -0,0 +1,87 @@ +package org.eclipse.equinox.p2.tests.planner; + +import java.util.*; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.equinox.internal.p2.director.ProfileChangeRequest; +import org.eclipse.equinox.internal.p2.metadata.query.UpdateQuery; +import org.eclipse.equinox.p2.engine.*; +import org.eclipse.equinox.p2.engine.query.IUProfilePropertyQuery; +import org.eclipse.equinox.p2.metadata.*; +import org.eclipse.equinox.p2.planner.*; +import org.eclipse.equinox.p2.query.*; + +public class LuckyHelper { + ProfileChangeRequest computeProfileChangeRequest(IProfile profile, IPlanner planner, ProfileChangeRequest request, ProvisioningContext context, IProgressMonitor monitor) { + // IProfileRegistry profileRegistry = (IProfileRegistry) session.getProvisioningAgent().getService(IProfileRegistry.SERVICE_NAME); + IPlanner plan = planner; //(IPlanner) session.getProvisioningAgent().getService(IPlanner.SERVICE_NAME); + IProfile prof = profile; //profileRegistry.getProfile(getProfileId()); + + final String INCLUSION_RULES = "org.eclipse.equinox.p2.internal.inclusion.rules"; //$NON-NLS-1$ + final String INCLUSION_OPTIONAL = "OPTIONAL"; //$NON-NLS-1$ + final String INCLUSION_STRICT = "STRICT"; //$NON-NLS-1$ + + IQueryResult<IInstallableUnit> strictRoots = prof.query(new IUProfilePropertyQuery(INCLUSION_RULES, INCLUSION_STRICT), null); + IQueryResult<IInstallableUnit> optionalRoots = prof.query(new IUProfilePropertyQuery(INCLUSION_RULES, INCLUSION_OPTIONAL), null); + Set<IInstallableUnit> tmpRoots = new HashSet<IInstallableUnit>(strictRoots.toUnmodifiableSet()); + tmpRoots.addAll(optionalRoots.toUnmodifiableSet()); + CollectionResult<IInstallableUnit> allRoots = new CollectionResult<IInstallableUnit>(tmpRoots); + + request = (ProfileChangeRequest) plan.createChangeRequest(prof); + Collection<IRequirement> limitingRequirements = new ArrayList<IRequirement>(); + + for (Iterator<IInstallableUnit> iterator = allRoots.query(QueryUtil.ALL_UNITS, null).iterator(); iterator.hasNext();) { + IInstallableUnit currentlyInstalled = iterator.next(); + + //find all the potential updates for the currentlyInstalled iu + IQueryResult<IInstallableUnit> updatesAvailable = plan.updatesFor(currentlyInstalled, context, null); + for (Iterator<IInstallableUnit> iterator2 = updatesAvailable.iterator(); iterator2.hasNext();) { + IInstallableUnit update = iterator2.next(); + request.add(update); + request.setInstallableUnitInclusionRules(update, ProfileInclusionRules.createOptionalInclusionRule(update)); + } + if (!updatesAvailable.isEmpty()) { + //force the original IU to optional, but make sure that the solution at least includes it + request.setInstallableUnitInclusionRules(currentlyInstalled, ProfileInclusionRules.createOptionalInclusionRule(currentlyInstalled)); + limitingRequirements.add(MetadataFactory.createRequirement(IInstallableUnit.NAMESPACE_IU_ID, currentlyInstalled.getId(), new VersionRange(currentlyInstalled.getVersion(), true, Version.MAX_VERSION, true), null, false, false)); + } + } + + IProvisioningPlan updateFinderPlan = plan.getProvisioningPlan(request, context, null); + if (updateFinderPlan.getAdditions().query(QueryUtil.ALL_UNITS, null).isEmpty()) { + return null; + } + + //Take into account all the removals + IProfileChangeRequest finalChangeRequest = plan.createChangeRequest(prof); + IQueryResult<IInstallableUnit> removals = updateFinderPlan.getRemovals().query(QueryUtil.ALL_UNITS, null); + for (Iterator<IInstallableUnit> iterator = removals.iterator(); iterator.hasNext();) { + IInstallableUnit iu = iterator.next(); + if (!allRoots.query(QueryUtil.createIUQuery(iu), null).isEmpty()) { + finalChangeRequest.remove(iu); + } + } + + //Take into account the additions for stricts + for (Iterator<IInstallableUnit> iterator = strictRoots.iterator(); iterator.hasNext();) { + IInstallableUnit formerRoot = iterator.next(); + IQueryResult<IInstallableUnit> update = updateFinderPlan.getAdditions().query(new UpdateQuery(formerRoot), null); + if (!update.isEmpty()) + finalChangeRequest.addAll(update.toUnmodifiableSet()); + } + + //Take into account the additions for optionals + for (Iterator<IInstallableUnit> iterator = optionalRoots.iterator(); iterator.hasNext();) { + IInstallableUnit formerRoot = iterator.next(); + IQueryResult<IInstallableUnit> update = updateFinderPlan.getAdditions().query(new UpdateQuery(formerRoot), null); + if (!update.isEmpty()) { + for (Iterator<IInstallableUnit> it = update.iterator(); it.hasNext();) { + IInstallableUnit updatedOptionalIU = it.next(); + finalChangeRequest.add(updatedOptionalIU); + finalChangeRequest.setInstallableUnitInclusionRules(updatedOptionalIU, ProfileInclusionRules.createOptionalInclusionRule(updatedOptionalIU)); + } + } + } + return (ProfileChangeRequest) finalChangeRequest; + } + +} diff --git a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/planner/LuckyTest.java b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/planner/LuckyTest.java new file mode 100644 index 000000000..ca9c08831 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/planner/LuckyTest.java @@ -0,0 +1,51 @@ +package org.eclipse.equinox.p2.tests.planner; + +import org.eclipse.equinox.internal.p2.director.ProfileChangeRequest; +import org.eclipse.equinox.p2.engine.*; +import org.eclipse.equinox.p2.metadata.IInstallableUnit; +import org.eclipse.equinox.p2.planner.IPlanner; +import org.eclipse.equinox.p2.tests.*; + +public class LuckyTest extends AbstractProvisioningTest { + @IUDescription(content = "package: sdk \n" + "singleton: true\n" + "version: 1 \n" + "depends: platform = 1") + public IInstallableUnit sdk1; + + @IUDescription(content = "package: platform \n" + "singleton: true\n" + "version: 1 \n") + public IInstallableUnit platform1; + + @IUDescription(content = "package: sdk \n" + "singleton: true\n" + "version: 2 \n" + "depends: platform = 2") + public IInstallableUnit sdk2; + + @IUDescription(content = "package: platform \n" + "singleton: true\n" + "version: 2 \n") + public IInstallableUnit platform2; + + IProfile profile = createProfile("TestProfile." + getName()); + + private IPlanner planner; + + private IEngine engine; + + @Override + protected void setUp() throws Exception { + super.setUp(); + IULoader.loadIUs(this); + createTestMetdataRepository(new IInstallableUnit[] {sdk1, platform1, sdk2, platform2}); + System.out.println(sdk1); + System.out.println(platform1); + System.out.println(sdk2); + System.out.println(platform2); + planner = createPlanner(); + engine = createEngine(); + assertOK(install(profile, new IInstallableUnit[] {sdk1}, true, planner, engine)); + } + + public void testInstallSDK2() { + assertNotOK(install(profile, new IInstallableUnit[] {platform2}, true, planner, engine)); + ProfileChangeRequest request = new ProfileChangeRequest(profile); + request.add(platform2); + ProfileChangeRequest res = new LuckyHelper().computeProfileChangeRequest(profile, planner, request, new ProvisioningContext(getAgent()), getMonitor()); + assertTrue(res.getAdditions().contains(sdk2)); + assertTrue(res.getRemovals().contains(sdk1)); + } + +} diff --git a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/planner/LuckyTest2.java b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/planner/LuckyTest2.java new file mode 100644 index 000000000..9a64d5a10 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/planner/LuckyTest2.java @@ -0,0 +1,57 @@ +package org.eclipse.equinox.p2.tests.planner; + +import org.eclipse.equinox.internal.p2.director.ProfileChangeRequest; +import org.eclipse.equinox.p2.engine.*; +import org.eclipse.equinox.p2.metadata.IInstallableUnit; +import org.eclipse.equinox.p2.planner.IPlanner; +import org.eclipse.equinox.p2.tests.*; + +public class LuckyTest2 extends AbstractProvisioningTest { + @IUDescription(content = "package: sdk \n" + "singleton: true\n" + "version: 1 \n" + "depends: platform = 1") + public IInstallableUnit sdk1; + + @IUDescription(content = "package: platform \n" + "singleton: true\n" + "version: 1 \n") + public IInstallableUnit platform1; + + @IUDescription(content = "package: sdk \n" + "singleton: true\n" + "version: 2 \n" + "depends: platform = 2") + public IInstallableUnit sdk2; + + @IUDescription(content = "package: platform \n" + "singleton: true\n" + "version: 2 \n") + public IInstallableUnit platform2; + + @IUDescription(content = "package: egit \n" + "singleton: true\n" + "version: 1 \n") + public IInstallableUnit egit1; + + IProfile profile = createProfile("TestProfile." + getName()); + + private IPlanner planner; + + private IEngine engine; + + @Override + protected void setUp() throws Exception { + super.setUp(); + IULoader.loadIUs(this); + createTestMetdataRepository(new IInstallableUnit[] {sdk1, platform1, sdk2, platform2, egit1}); + planner = createPlanner(); + engine = createEngine(); + assertOK(install(profile, new IInstallableUnit[] {sdk1, egit1}, true, planner, engine)); + } + + public void testInstallSDK2() { + assertNotOK(install(profile, new IInstallableUnit[] {platform2}, true, planner, engine)); + ProfileChangeRequest request = new ProfileChangeRequest(profile); + request.add(platform2); + + ProfileChangeRequest res = new LuckyHelper().computeProfileChangeRequest(profile, planner, request, new ProvisioningContext(getAgent()), getMonitor()); + assertEquals(1, res.getAdditions().size()); + assertTrue(res.getAdditions().contains(sdk2)); + assertEquals(1, res.getRemovals().size()); + assertTrue(res.getRemovals().contains(sdk1)); + + assertOK(install(res, planner, engine)); + assertProfileContains("validate new profile", profile, new IInstallableUnit[] {sdk2, platform2, egit1}); + assertEquals("STRICT", profile.getInstallableUnitProperty(sdk2, "org.eclipse.equinox.p2.internal.inclusion.rules")); + assertEquals("STRICT", profile.getInstallableUnitProperty(egit1, "org.eclipse.equinox.p2.internal.inclusion.rules")); + } +} |