*One more detail at the bottom:* On Mon, Dec 13, 2010 at 5:11 PM, David Orme <[email protected]>wrote:
> Hi Tomas, > > On Fri, Dec 10, 2010 at 5:58 PM, Thomas Hallgren <[email protected]> wrote: > >> The traverse query was written with the intention to replace the slicer >> but we never got around to actually do that in the 3.6 time frame. As it >> stands today, it's not a clean cut replacement. The slicer (permissive or >> non-permissive) will give you specific control over the query that is >> applicable for a couple of use-cases that is utilized by the PDE target >> platform provisioning system. One is for instance to guess whether a >> requirement stems from a PDE-feature 'include' or a PDE-feature 'requires' >> by looking at the version range (exact or not) in the requirement. >> > > Thanks for the clarification. > > >> The traverse query is generic and not capable of performing special >> considerations like that. It is however proven to be both faster and more >> memory conservative than the slicer so I guess the answer to your question >> all depends on your requirements. It would be easier to give a good answer >> if we knew more about what it is you want to accomplish. >> > > Sure; here's what's up* (short version)*: > > We have an headless installer/updater built on top of Update Manager that > I'm trying to move to P2. Basically right now I'm spiking various use-cases > in P2 with a view to forming an opinion about the best way to reimplement > this API on top of P2. > > But that's not all. At EclipseCon, we contributed our headless installer > API to E4 with a view to make it easy for others to build RCP applications > like we have: > > (a) When an application starts up, it checks for updates and automatically > downloads/installs them. > > (b) Alternatively, when a user logs in, the application contacts a > provisioning server and obtains a list of Features/Versions that the user is > permitted to use. We then call Update Manager and install/update ONLY those > Features/Versions and appropriate dependencies. > > So we'd love to have feedback/input from the community. > > *Detail:* > > We've got (a) above tackled using P2. We're struggling a bit with the API > to implement (b). > > The API that implements (b) is: > > public boolean update(URL[] updateSiteURLs, File downloadRootDir, > Set<FeatureVersionedIdentifier> featuresRequested) throws InstallError > > > In P2 terms, *updateSiteURLs *wind up being consolidated into a > compoundQueryable. > > I'm not sure what P2 terms are yet for *downloadRootDir*, but I'm guessing > that this has something to do with P2 Profiles? In Update Manager, this > specified a root directory where we would create your install site(s). The > purpose is to enable installations on Citrix or *nixes where the > installation directory might not be writable; this we have to support > putting updates somewhere else. > > *featuresRequested *is the set of Features that the current user is > allowed to use. It obviously must be a subset of the features on * > updateSiteURLs*. > > [[A *FeatureVersionedIdentifier *simply is a (String, String) pair where > the first String is the Feature ID and the second is either the exact > version, a version number without the qualifier, or "0.0.0" to specify the > latest version. (*IFeatureReference *doesn't implement equals/hashCode, > so we needed something that would be usable in collections. Plus we wanted > to be independent of Update Manager so we could later move to P2.) This > class is very similar to an *InstallableUnitDescription*, but just for > Features; maybe there's another even closer match in P2?]] > > *featuresRequested *is basically our query API. > > More or less current code can be found at: > > > http://git.eclipse.org/c/e4/org.eclipse.e4.installer.git/tree/bundles/org.eclipse.e4.enterprise.installer/src/org/eclipse/e4/enterprise/installer/BundleUpdater.java > > *Current questions:* > > My (spiked) update method looks like the following; (important lines > bolded): > > > //Loading repos > Collection<IMetadataRepository> metadataReposList = new > LinkedList<IMetadataRepository>(); > metadataReposList.add(metadataManager.loadRepository(new URI(P2SITE), > monitor)); > metadataReposList.add(metadataManager.loadRepository(new > URI(SECOND_P2SITE), monitor)); > metadataReposList.add(metadataManager.loadRepository(new URI(THIRD_P2SITE), > monitor)); > > artifactManager.loadRepository(new URI(P2SITE), monitor); > artifactManager.loadRepository(new URI(SECOND_P2SITE), monitor); > artifactManager.loadRepository(new URI(THIRD_P2SITE), monitor); > > //Querying > final String traverseQuery = "$0.traverse(parent | > parent.requirements.collect(rc | select(iu |iu ~= rc)).flatten())"; > > IQueryable<IInstallableUnit> allMetadataRepos = > QueryUtil.compoundQueryable(metadataReposList); > > Set<IInstallableUnit> toInstallOrUpdate = null; > ArrayList<IInstallableUnit> ius = getIUsToInstall(); > > try { > * if (ius.size() > 0) { > toInstallOrUpdate = allMetadataRepos.query( > QueryUtil.createQuery(traverseQuery, ius), > monitor).toUnmodifiableSet(); > } else { > > toInstallOrUpdate = allMetadataRepos.query( > QueryUtil.createIUAnyQuery(), monitor).toUnmodifiableSet(); > } > *} catch (Throwable t) { > IStatus result = error(t.getMessage(), t); > log(result); > return result; > } > > // Perform the install > InstallOperation installOperation = new InstallOperation(session, > toInstallOrUpdate); > resolveJob = installOperation.getResolveJob(monitor); > IStatus installStatus = syncRunJob(monitor, resolveJob); > if (null == resolveJob) { > return log(error("Unexpected: installOperation#getResolveJob returned > null!", new NullPointerException())); > } > log(info("Result of resolving install opearations: " + > installStatus.getMessage())); > if (installStatus.isOK()) { > log(info("Installing...")); > ProvisioningJob provisioningJob = > installOperation.getProvisioningJob(monitor); > if (null == provisioningJob) { > return log(error("Unexpected: installOperation#getProvisioningJob > returned null!", new NullPointerException())); > } > installStatus = syncRunJob(monitor, provisioningJob); > log(info("Install result: " + installStatus.getMessage())); > } else { > log(info("Install status returned !ok: " + > installStatus.getMessage())); > } > > > The key part is the "if" clause I bolded above. > > If there are no IUs in the list, we (in the spike) install everything, just > to prove that the rest of the code works right. When I go through that code > path, everything works fine. > > However, when I explicitly specify the .feature.group(s) to install, then > the IUs I get back from the query are exactly the .feature.group(s) I used > as input, and nothing else. No plugins, no included/dependent features, > nothing. Naturally, this fails. > > I'm not sure where to go next. > > In your opinion, is this the right approach or should I be using the > slicer? (It seems fine to me for our API, but I might be missing > something.) > > I'll try to get a small example together that I can upload somewhere. > > Here's the code I use to create an IU: private IInstallableUnit newIU(String id, String versionString) { InstallableUnitDescription iuDesc = new MetadataFactory.InstallableUnitDescription(); iuDesc.setId(id); Version version = Version.create(versionString); iuDesc.setVersion(version); ArrayList<IProvidedCapability> capabilities = new ArrayList<IProvidedCapability>(); capabilities.add(MetadataFactory.createProvidedCapability(id, id, version)); iuDesc.addProvidedCapabilities(capabilities); return MetadataFactory.createInstallableUnit(iuDesc); } Thanks again, Dave
_______________________________________________ p2-dev mailing list [email protected] https://dev.eclipse.org/mailman/listinfo/p2-dev
