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.

Thanks in advance.


Regards,

Dave Orme
_______________________________________________
p2-dev mailing list
[email protected]
https://dev.eclipse.org/mailman/listinfo/p2-dev

Reply via email to