Blame SOURCES/0002-Implement-a-custom-resolver-for-Tycho-in-local-mode.patch

84bf7c
From 623916240bd0626e7fd5146bfb2acfe9c77502da Mon Sep 17 00:00:00 2001
84bf7c
From: Roland Grunberg <rgrunber@redhat.com>
84bf7c
Date: Tue, 12 Jun 2012 10:38:51 -0400
84bf7c
Subject: [PATCH 2/6] Implement a custom resolver for Tycho in local mode.
84bf7c
84bf7c
When running in local mode, dependencies should be resolved by looking
84bf7c
on the local system. Remote repositories should be ignored unless
84bf7c
offline mode is disabled.
84bf7c
84bf7c
Use fedoraproject-p2 to resolve bundles from their system location.
84bf7c
84bf7c
Relax constraints for bundles used in Tycho's Equinox runtime.
84bf7c
84bf7c
Since Fedora 17, we need an Execution Environment of at least JavaSE-1.6
84bf7c
for Eclipse bundles. Eclipse Juno platform bundles depend on
84bf7c
javax.annotation. In Fedora this is provided by geronimo-annotation, but
84bf7c
has a dependency on javax.lang.model (since 1.6).
84bf7c
84bf7c
Use the defined target environments in local mode when the property
84bf7c
tycho.local.keepTarget is set.
84bf7c
84bf7c
In situations where Tycho must resolve maven artifacts, upstream's
84bf7c
implementation only looks in the reactor cache. In Fedora, maven
84bf7c
artifacts may be located on the system using repository layouts
84bf7c
understood by XMvn. Therefore, when an artifact is not found in the
84bf7c
reactor cache, resolution should be attempted using the XMvn Resolver.
84bf7c
84bf7c
Upstream/Fedora Tycho differ in the kind of OSGi Runtime used
84bf7c
(org.eclipse.tycho:tycho-bundles-external:zip) so use separate location
84bf7c
for our runtime (fedora-eclipse) to avoid collisions.
84bf7c
84bf7c
Change-Id: Ia1ece07ece2412bc4a88901631f3f651ad2b634b
84bf7c
---
84bf7c
 .../internal/DefaultEquinoxEmbedder.java      | 11 ++++-
84bf7c
 .../remote/RemoteRepositoryCacheManager.java  | 11 +++++
84bf7c
 .../p2/target/TargetDefinitionResolver.java   | 17 +++++--
84bf7c
 .../target/TargetPlatformBundlePublisher.java | 15 ++-----
84bf7c
 .../p2/target/TargetPlatformFactoryImpl.java  | 45 +++++++++++++++++--
84bf7c
 .../p2/repository/LocalRepositoryReader.java  | 44 +++++++++++++++++-
84bf7c
 .../TargetPlatformConfigurationStub.java      |  6 ++-
84bf7c
 .../tycho-bundles-external.product            |  3 ++
84bf7c
 .../tycho/core/locking/FileLockerImpl.java    | 26 ++++++++---
84bf7c
 .../maven/TychoMavenLifecycleParticipant.java | 13 ++++++
84bf7c
 .../core/osgitools/AbstractTychoProject.java  | 23 ++++++++++
84bf7c
 .../core/osgitools/OsgiBundleProject.java     |  5 ++-
84bf7c
 ...aultTargetPlatformConfigurationReader.java |  6 ++-
84bf7c
 .../osgi/runtime/TychoOsgiRuntimeLocator.java | 27 ++++++++---
84bf7c
 tycho-p2/tycho-p2-facade/pom.xml              |  5 +++
84bf7c
 .../p2/resolver/P2DependencyResolver.java     |  8 ++++
84bf7c
 16 files changed, 227 insertions(+), 38 deletions(-)
84bf7c
84bf7c
diff --git a/sisu-equinox/sisu-equinox-embedder/src/main/java/org/eclipse/sisu/equinox/embedder/internal/DefaultEquinoxEmbedder.java b/sisu-equinox/sisu-equinox-embedder/src/main/java/org/eclipse/sisu/equinox/embedder/internal/DefaultEquinoxEmbedder.java
84bf7c
index 359c464..b644539 100644
84bf7c
--- a/sisu-equinox/sisu-equinox-embedder/src/main/java/org/eclipse/sisu/equinox/embedder/internal/DefaultEquinoxEmbedder.java
84bf7c
+++ b/sisu-equinox/sisu-equinox-embedder/src/main/java/org/eclipse/sisu/equinox/embedder/internal/DefaultEquinoxEmbedder.java
84bf7c
@@ -240,7 +240,14 @@ public class DefaultEquinoxEmbedder extends AbstractLogEnabled
84bf7c
                     if (verIdx > 0) {
84bf7c
                         bundles.append(name.substring(0, verIdx));
84bf7c
                     } else {
84bf7c
-                        throw new EquinoxEmbedderException("File name doesn't match expected pattern: " + file);
84bf7c
+                        // In Fedora, NAME_VERSION.QUALIFIER.jar is too fragile.
84bf7c
+                        // Let's also accept NAME.jar
84bf7c
+                        verIdx = name.lastIndexOf(".jar");
84bf7c
+                        if (verIdx > 0) {
84bf7c
+                            bundles.append(name.substring(0, verIdx));
84bf7c
+                        } else {
84bf7c
+                            throw new EquinoxEmbedderException("File name doesn't match expected pattern: " + file);
84bf7c
+                        }
84bf7c
                     }
84bf7c
                 }
84bf7c
             }
84bf7c
@@ -248,7 +255,7 @@ public class DefaultEquinoxEmbedder extends AbstractLogEnabled
84bf7c
     }
84bf7c
 
84bf7c
     protected boolean isFrameworkBundle(File file) {
84bf7c
-        return file.getName().startsWith("org.eclipse.osgi_");
84bf7c
+        return file.getName().startsWith("org.eclipse.osgi_") || file.getName().equals("org.eclipse.osgi.jar");
84bf7c
     }
84bf7c
 
84bf7c
     String getReferenceUrl(File file) {
84bf7c
diff --git a/tycho-bundles/org.eclipse.tycho.p2.resolver.impl/src/main/java/org/eclipse/tycho/p2/remote/RemoteRepositoryCacheManager.java b/tycho-bundles/org.eclipse.tycho.p2.resolver.impl/src/main/java/org/eclipse/tycho/p2/remote/RemoteRepositoryCacheManager.java
84bf7c
index 1f233e1..c9a6dc1 100644
84bf7c
--- a/tycho-bundles/org.eclipse.tycho.p2.resolver.impl/src/main/java/org/eclipse/tycho/p2/remote/RemoteRepositoryCacheManager.java
84bf7c
+++ b/tycho-bundles/org.eclipse.tycho.p2.resolver.impl/src/main/java/org/eclipse/tycho/p2/remote/RemoteRepositoryCacheManager.java
84bf7c
@@ -12,14 +12,18 @@ package org.eclipse.tycho.p2.remote;
84bf7c
 
84bf7c
 import java.io.File;
84bf7c
 import java.io.IOException;
84bf7c
+import java.net.MalformedURLException;
84bf7c
 import java.net.URI;
84bf7c
+import java.net.URL;
84bf7c
 
84bf7c
 import org.eclipse.core.runtime.IProgressMonitor;
84bf7c
 import org.eclipse.core.runtime.IStatus;
84bf7c
 import org.eclipse.core.runtime.Status;
84bf7c
 import org.eclipse.equinox.internal.p2.repository.CacheManager;
84bf7c
+import org.eclipse.equinox.internal.p2.repository.Messages;
84bf7c
 import org.eclipse.equinox.internal.p2.repository.Transport;
84bf7c
 import org.eclipse.equinox.p2.core.ProvisionException;
84bf7c
+import org.eclipse.osgi.util.NLS;
84bf7c
 import org.eclipse.tycho.core.shared.MavenContext;
84bf7c
 import org.eclipse.tycho.core.shared.MavenLogger;
84bf7c
 import org.eclipse.tycho.p2.impl.Activator;
84bf7c
@@ -51,6 +55,13 @@ class RemoteRepositoryCacheManager extends CacheManager {
84bf7c
     @Override
84bf7c
     public File createCache(URI repositoryLocation, String prefix, IProgressMonitor monitor)
84bf7c
             throws IOException, ProvisionException {
84bf7c
+        try {
84bf7c
+            new URL(repositoryLocation.toASCIIString());
84bf7c
+        } catch (MalformedURLException e) {
84bf7c
+            throw new ProvisionException(new Status(IStatus.ERROR, org.eclipse.equinox.internal.p2.repository.Activator.ID,
84bf7c
+                    ProvisionException.REPOSITORY_NOT_FOUND, NLS.bind(Messages.CacheManager_CannotLoadNonUrlLocation,
84bf7c
+                            repositoryLocation), null));
84bf7c
+        }
84bf7c
         File cacheFile = getCache(repositoryLocation, prefix);
84bf7c
         if (offline) {
84bf7c
             if (cacheFile != null) {
84bf7c
diff --git a/tycho-bundles/org.eclipse.tycho.p2.resolver.impl/src/main/java/org/eclipse/tycho/p2/target/TargetDefinitionResolver.java b/tycho-bundles/org.eclipse.tycho.p2.resolver.impl/src/main/java/org/eclipse/tycho/p2/target/TargetDefinitionResolver.java
84bf7c
index e5e99a1..1cf8089 100644
84bf7c
--- a/tycho-bundles/org.eclipse.tycho.p2.resolver.impl/src/main/java/org/eclipse/tycho/p2/target/TargetDefinitionResolver.java
84bf7c
+++ b/tycho-bundles/org.eclipse.tycho.p2.resolver.impl/src/main/java/org/eclipse/tycho/p2/target/TargetDefinitionResolver.java
84bf7c
@@ -20,6 +20,7 @@ import java.util.Set;
84bf7c
 
84bf7c
 import org.eclipse.core.runtime.IProgressMonitor;
84bf7c
 import org.eclipse.core.runtime.NullProgressMonitor;
84bf7c
+import org.eclipse.core.runtime.URIUtil;
84bf7c
 import org.eclipse.equinox.p2.core.IProvisioningAgent;
84bf7c
 import org.eclipse.equinox.p2.core.ProvisionException;
84bf7c
 import org.eclipse.equinox.p2.metadata.IInstallableUnit;
84bf7c
@@ -121,7 +122,12 @@ public final class TargetDefinitionResolver {
84bf7c
                 resolverRun.addLocation((InstallableUnitLocation) locationDefinition);
84bf7c
 
84bf7c
                 for (Repository repository : ((InstallableUnitLocation) locationDefinition).getRepositories()) {
84bf7c
-                    artifactRepositories.add(repository.getLocation());
84bf7c
+                    // We cannot resolve a non-file URI in local mode
84bf7c
+                    if ((System.getProperty("TYCHO_MVN_LOCAL") == null && System.getProperty("TYCHO_MVN_RPMBUILD") == null)
84bf7c
+                            || URIUtil.isFileURI(repository.getLocation())
84bf7c
+                            || "fedora".equals(repository.getLocation().getScheme())) {
84bf7c
+                        artifactRepositories.add(repository.getLocation());
84bf7c
+                    }
84bf7c
                 }
84bf7c
             } else {
84bf7c
                 logger.warn("Target location type '" + locationDefinition.getTypeDescription() + "' is not supported");
84bf7c
@@ -278,8 +284,13 @@ public final class TargetDefinitionResolver {
84bf7c
 
84bf7c
             loadedRepositories = new ArrayList<>();
84bf7c
             for (Repository repository : locationDefinition.getRepositories()) {
84bf7c
-                repositoryIdManager.addMapping(repository.getId(), repository.getLocation());
84bf7c
-                loadedRepositories.add(loadRepository(repository));
84bf7c
+                // We cannot resolve a non-file URI in local mode
84bf7c
+                if ((System.getProperty("TYCHO_MVN_LOCAL") == null && System.getProperty("TYCHO_MVN_RPMBUILD") == null)
84bf7c
+                        || URIUtil.isFileURI(repository.getLocation())
84bf7c
+                        || "fedora".equals(repository.getLocation().getScheme())) {
84bf7c
+                    repositoryIdManager.addMapping(repository.getId(), repository.getLocation());
84bf7c
+                    loadedRepositories.add(loadRepository(repository));
84bf7c
+                }
84bf7c
             }
84bf7c
         }
84bf7c
 
84bf7c
diff --git a/tycho-bundles/org.eclipse.tycho.p2.resolver.impl/src/main/java/org/eclipse/tycho/p2/target/TargetPlatformBundlePublisher.java b/tycho-bundles/org.eclipse.tycho.p2.resolver.impl/src/main/java/org/eclipse/tycho/p2/target/TargetPlatformBundlePublisher.java
84bf7c
index 6a59c2a..0d15db9 100644
84bf7c
--- a/tycho-bundles/org.eclipse.tycho.p2.resolver.impl/src/main/java/org/eclipse/tycho/p2/target/TargetPlatformBundlePublisher.java
84bf7c
+++ b/tycho-bundles/org.eclipse.tycho.p2.resolver.impl/src/main/java/org/eclipse/tycho/p2/target/TargetPlatformBundlePublisher.java
84bf7c
@@ -28,6 +28,7 @@ import org.eclipse.tycho.core.shared.MavenLogger;
84bf7c
 import org.eclipse.tycho.p2.impl.publisher.MavenPropertiesAdvice;
84bf7c
 import org.eclipse.tycho.p2.impl.publisher.repo.TransientArtifactRepository;
84bf7c
 import org.eclipse.tycho.p2.metadata.IArtifactFacade;
84bf7c
+import org.eclipse.tycho.p2.repository.LocalRepositoryReader;
84bf7c
 import org.eclipse.tycho.p2.repository.MavenRepositoryCoordinates;
84bf7c
 import org.eclipse.tycho.repository.local.GAVArtifactDescriptor;
84bf7c
 import org.eclipse.tycho.repository.p2base.artifact.provider.IRawArtifactFileProvider;
84bf7c
@@ -216,15 +217,6 @@ public class TargetPlatformBundlePublisher {
84bf7c
             GAVArtifactDescriptor descriptorForRepository = new GAVArtifactDescriptor(baseDescriptor,
84bf7c
                     repositoryCoordinates);
84bf7c
 
84bf7c
-            File requiredArtifactLocation = new File(getBaseDir(),
84bf7c
-                    descriptorForRepository.getMavenCoordinates().getLocalRepositoryPath());
84bf7c
-            File actualArtifactLocation = mavenArtifact.getLocation();
84bf7c
-            if (!equivalentPaths(requiredArtifactLocation, actualArtifactLocation)) {
84bf7c
-                throw new AssertionFailedException(
84bf7c
-                        "The Maven artifact to be added to the target platform is not stored at the required location on disk: required \""
84bf7c
-                                + requiredArtifactLocation + "\" but was \"" + actualArtifactLocation + "\"");
84bf7c
-            }
84bf7c
-
84bf7c
             internalAddInternalDescriptor(descriptorForRepository);
84bf7c
         }
84bf7c
 
84bf7c
@@ -257,8 +249,9 @@ public class TargetPlatformBundlePublisher {
84bf7c
 
84bf7c
         @Override
84bf7c
         protected File internalGetArtifactStorageLocation(IArtifactDescriptor descriptor) {
84bf7c
-            String relativePath = toInternalDescriptor(descriptor).getMavenCoordinates().getLocalRepositoryPath();
84bf7c
-            return new File(getBaseDir(), relativePath);
84bf7c
+            MavenRepositoryCoordinates coord = toInternalDescriptor(descriptor).getMavenCoordinates();
84bf7c
+            LocalRepositoryReader reader = new LocalRepositoryReader(getBaseDir());
84bf7c
+            return reader.getLocalArtifactLocation(coord.getGav(), coord.getClassifier(), coord.getExtensionOrDefault());
84bf7c
         }
84bf7c
 
84bf7c
         private File getBaseDir() {
84bf7c
diff --git a/tycho-bundles/org.eclipse.tycho.p2.resolver.impl/src/main/java/org/eclipse/tycho/p2/target/TargetPlatformFactoryImpl.java b/tycho-bundles/org.eclipse.tycho.p2.resolver.impl/src/main/java/org/eclipse/tycho/p2/target/TargetPlatformFactoryImpl.java
84bf7c
index 7854bca..2247be6 100644
84bf7c
--- a/tycho-bundles/org.eclipse.tycho.p2.resolver.impl/src/main/java/org/eclipse/tycho/p2/target/TargetPlatformFactoryImpl.java
84bf7c
+++ b/tycho-bundles/org.eclipse.tycho.p2.resolver.impl/src/main/java/org/eclipse/tycho/p2/target/TargetPlatformFactoryImpl.java
84bf7c
@@ -32,6 +32,9 @@ import org.eclipse.core.runtime.URIUtil;
84bf7c
 import org.eclipse.equinox.p2.core.IProvisioningAgent;
84bf7c
 import org.eclipse.equinox.p2.core.ProvisionException;
84bf7c
 import org.eclipse.equinox.p2.metadata.IInstallableUnit;
84bf7c
+import org.eclipse.equinox.p2.metadata.expression.ExpressionUtil;
84bf7c
+import org.eclipse.equinox.p2.metadata.expression.IExpression;
84bf7c
+import org.eclipse.equinox.p2.query.IQuery;
84bf7c
 import org.eclipse.equinox.p2.query.IQueryResult;
84bf7c
 import org.eclipse.equinox.p2.query.QueryUtil;
84bf7c
 import org.eclipse.equinox.p2.repository.artifact.IArtifactRepositoryManager;
84bf7c
@@ -273,9 +276,43 @@ public class TargetPlatformFactoryImpl implements TargetPlatformFactory {
84bf7c
             metadataRepositories.add(localMetadataRepository);
84bf7c
         }
84bf7c
 
84bf7c
-        for (IMetadataRepository repository : metadataRepositories) {
84bf7c
-            IQueryResult<IInstallableUnit> matches = repository.query(QueryUtil.ALL_UNITS, monitor);
84bf7c
-            result.addAll(matches.toUnmodifiableSet());
84bf7c
+        if (System.getProperty("TYCHO_MVN_LOCAL") != null) {
84bf7c
+            final IExpression notmatchIU_ID = ExpressionUtil.parse("id != $0");
84bf7c
+            Set<IMetadataRepository> fedoraRepos = new HashSet<IMetadataRepository> ();
84bf7c
+
84bf7c
+            // Sanity check even though the repo we want should be at index 1
84bf7c
+            for (IMetadataRepository repository : metadataRepositories) {
84bf7c
+                if ("fedora".equals(repository.getLocation().getScheme())) {
84bf7c
+                    fedoraRepos.add(repository);
84bf7c
+                }
84bf7c
+            }
84bf7c
+
84bf7c
+            IQuery<IInstallableUnit> noLocalIUs = QueryUtil.createIUAnyQuery();
84bf7c
+
84bf7c
+            // Create a conjunction query that negates all IUs on the local system
84bf7c
+            for (IMetadataRepository repo : fedoraRepos) {
84bf7c
+                for (IInstallableUnit unit : repo.query(QueryUtil.ALL_UNITS, null).toUnmodifiableSet()) {
84bf7c
+                    noLocalIUs = QueryUtil.createCompoundQuery(noLocalIUs,
84bf7c
+                            QueryUtil.createMatchQuery(notmatchIU_ID, unit.getId()), true);
84bf7c
+                }
84bf7c
+            }
84bf7c
+
84bf7c
+            for (IMetadataRepository repository : metadataRepositories) {
84bf7c
+                IQueryResult<IInstallableUnit> matches;
84bf7c
+                if ("fedora".equals(repository.getLocation().getScheme())) {
84bf7c
+                    matches = repository.query(QueryUtil.ALL_UNITS, monitor);
84bf7c
+                } else {
84bf7c
+                    // Don't collect any remote IUs that can be found on the system
84bf7c
+                    // This will favour IUs in the system local p2 repository
84bf7c
+                    matches = repository.query(noLocalIUs, monitor);
84bf7c
+                }
84bf7c
+                result.addAll(matches.toUnmodifiableSet());
84bf7c
+            }
84bf7c
+        } else {
84bf7c
+            for (IMetadataRepository repository : metadataRepositories) {
84bf7c
+                IQueryResult<IInstallableUnit> matches = repository.query(QueryUtil.ALL_UNITS, monitor);
84bf7c
+                result.addAll(matches.toUnmodifiableSet());
84bf7c
+            }
84bf7c
         }
84bf7c
 
84bf7c
         result.addAll(pomDependenciesContent.gatherMavenInstallableUnits());
84bf7c
@@ -329,7 +366,7 @@ public class TargetPlatformFactoryImpl implements TargetPlatformFactory {
84bf7c
         List<URI> allRemoteArtifactRepositories = new ArrayList<>();
84bf7c
 
84bf7c
         for (MavenRepositoryLocation location : completeRepositories) {
84bf7c
-            if (!offline || URIUtil.isFileURI(location.getURL())) {
84bf7c
+            if (!offline || URIUtil.isFileURI(location.getURL()) || "fedora".equals(location.getURL().getScheme())) {
84bf7c
                 allRemoteArtifactRepositories.add(location.getURL());
84bf7c
             }
84bf7c
         }
84bf7c
diff --git a/tycho-bundles/org.eclipse.tycho.p2.resolver.shared/src/main/java/org/eclipse/tycho/p2/repository/LocalRepositoryReader.java b/tycho-bundles/org.eclipse.tycho.p2.resolver.shared/src/main/java/org/eclipse/tycho/p2/repository/LocalRepositoryReader.java
84bf7c
index e05f871..74b8028 100644
84bf7c
--- a/tycho-bundles/org.eclipse.tycho.p2.resolver.shared/src/main/java/org/eclipse/tycho/p2/repository/LocalRepositoryReader.java
84bf7c
+++ b/tycho-bundles/org.eclipse.tycho.p2.resolver.shared/src/main/java/org/eclipse/tycho/p2/repository/LocalRepositoryReader.java
84bf7c
@@ -11,6 +11,8 @@
84bf7c
 package org.eclipse.tycho.p2.repository;
84bf7c
 
84bf7c
 import java.io.File;
84bf7c
+import java.lang.reflect.Constructor;
84bf7c
+import java.lang.reflect.Method;
84bf7c
 
84bf7c
 public class LocalRepositoryReader implements RepositoryReader {
84bf7c
 
84bf7c
@@ -21,8 +23,46 @@ public class LocalRepositoryReader implements RepositoryReader {
84bf7c
     }
84bf7c
 
84bf7c
     @Override
84bf7c
+    @SuppressWarnings({ "unchecked", "rawtypes" })
84bf7c
     public File getLocalArtifactLocation(GAV gav, String classifier, String extension) {
84bf7c
-        return new File(localMavenRepositoryRoot, RepositoryLayoutHelper.getRelativePath(gav, classifier, extension));
84bf7c
-    }
84bf7c
+        File file = new File(localMavenRepositoryRoot, RepositoryLayoutHelper.getRelativePath(gav, classifier,
84bf7c
+                extension));
84bf7c
+        // In Fedora the artifact may be in an XMvn-defined repository location (not in reactor cache)
84bf7c
+        if (!file.exists()) {
84bf7c
+            try {
84bf7c
+                // Create Plexus config
84bf7c
+                Class pcclazz = Class.forName("org.codehaus.plexus.ContainerConfiguration");
84bf7c
+                Object conf = Class.forName("org.codehaus.plexus.DefaultContainerConfiguration").newInstance();
84bf7c
+                pcclazz.getMethod("setAutoWiring", boolean.class).invoke(conf, true);
84bf7c
+                pcclazz.getMethod("setClassPathScanning", String.class).invoke(conf, "index");
84bf7c
+
84bf7c
+                // Use plexus container to lookup the reader
84bf7c
+                Class pclazz = Class.forName("org.codehaus.plexus.DefaultPlexusContainer");
84bf7c
+                Object plexus = pclazz.getConstructor(pcclazz).newInstance(conf);
84bf7c
+
84bf7c
+                // Retrieve the workspace reader from the plexus container
84bf7c
+                Method mLookup = pclazz.getMethod("lookup", String.class, String.class);
84bf7c
+                Object reader = mLookup.invoke(plexus, "org.eclipse.aether.repository.WorkspaceReader", "ide");
84bf7c
 
84bf7c
+                // Create an Aether Artifact based on GAV, classifier, and extension
84bf7c
+                Class iartclazz = Class.forName("org.eclipse.aether.artifact.Artifact");
84bf7c
+                Class artclazz = Class.forName("org.eclipse.aether.artifact.DefaultArtifact");
84bf7c
+                Constructor cNew = artclazz.getConstructor(String.class, String.class, String.class, String.class,
84bf7c
+                        String.class);
84bf7c
+                Object artifact = cNew.newInstance(gav.getGroupId(), gav.getArtifactId(), classifier, extension,
84bf7c
+                        gav.getVersion());
84bf7c
+
84bf7c
+                // Invoke "findArtifact" method of the workspace reader on the artifact
84bf7c
+                Method mfindArtifact = reader.getClass().getMethod("findArtifact", iartclazz);
84bf7c
+                File newFile = (File) mfindArtifact.invoke(reader, artifact);
84bf7c
+                if (newFile != null) {
84bf7c
+                    file = newFile;
84bf7c
+                }
84bf7c
+            } catch (Exception e) {
84bf7c
+                e.printStackTrace();
84bf7c
+            }
84bf7c
+        }
84bf7c
+        return file;
84bf7c
+
84bf7c
+    }
84bf7c
 }
84bf7c
diff --git a/tycho-bundles/org.eclipse.tycho.p2.resolver.shared/src/main/java/org/eclipse/tycho/p2/target/facade/TargetPlatformConfigurationStub.java b/tycho-bundles/org.eclipse.tycho.p2.resolver.shared/src/main/java/org/eclipse/tycho/p2/target/facade/TargetPlatformConfigurationStub.java
84bf7c
index 19d12c6..abe89e8 100644
84bf7c
--- a/tycho-bundles/org.eclipse.tycho.p2.resolver.shared/src/main/java/org/eclipse/tycho/p2/target/facade/TargetPlatformConfigurationStub.java
84bf7c
+++ b/tycho-bundles/org.eclipse.tycho.p2.resolver.shared/src/main/java/org/eclipse/tycho/p2/target/facade/TargetPlatformConfigurationStub.java
84bf7c
@@ -56,7 +56,11 @@ public class TargetPlatformConfigurationStub {
84bf7c
     }
84bf7c
 
84bf7c
     public void addP2Repository(MavenRepositoryLocation location) {
84bf7c
-        this.repositories.add(location);
84bf7c
+        // We cannot resolve a non-file URI in local mode while offline
84bf7c
+        if (System.getProperty("TYCHO_MVN_RPMBUILD") == null || "file".equalsIgnoreCase(location.getURL().getScheme())
84bf7c
+                || "fedora".equalsIgnoreCase(location.getURL().getScheme())) {
84bf7c
+            this.repositories.add(location);
84bf7c
+        }
84bf7c
     }
84bf7c
 
84bf7c
     // convenience method for tests
84bf7c
diff --git a/tycho-bundles/tycho-bundles-external/tycho-bundles-external.product b/tycho-bundles/tycho-bundles-external/tycho-bundles-external.product
84bf7c
index 11b7c8b..182122d 100644
84bf7c
--- a/tycho-bundles/tycho-bundles-external/tycho-bundles-external.product
84bf7c
+++ b/tycho-bundles/tycho-bundles-external/tycho-bundles-external.product
84bf7c
@@ -79,6 +79,9 @@
84bf7c
       <plugin id="org.sat4j.core"/>
84bf7c
       <plugin id="org.sat4j.pb"/>
84bf7c
       <plugin id="org.tukaani.xz"/>
84bf7c
+      <plugin id="org.kxml2"/>
84bf7c
+      <plugin id="org.xmlpull"/>
84bf7c
+      <plugin id="org.fedoraproject.p2"/>
84bf7c
    </plugins>
84bf7c
 
84bf7c
    <configurations>
84bf7c
diff --git a/tycho-core/src/main/java/org/eclipse/tycho/core/locking/FileLockerImpl.java b/tycho-core/src/main/java/org/eclipse/tycho/core/locking/FileLockerImpl.java
84bf7c
index e4612c3..3abcc5d 100644
84bf7c
--- a/tycho-core/src/main/java/org/eclipse/tycho/core/locking/FileLockerImpl.java
84bf7c
+++ b/tycho-core/src/main/java/org/eclipse/tycho/core/locking/FileLockerImpl.java
84bf7c
@@ -27,22 +27,36 @@ public class FileLockerImpl implements FileLocker {
84bf7c
     final File lockMarkerFile;
84bf7c
 
84bf7c
     public FileLockerImpl(File file, Location anyLocation) {
84bf7c
+        File lockFileCandidate = null;
84bf7c
         try {
84bf7c
             if (file.isDirectory()) {
84bf7c
-                this.lockMarkerFile = new File(file, LOCKFILE_SUFFIX).getCanonicalFile();
84bf7c
+                lockFileCandidate = new File(file, LOCKFILE_SUFFIX).getCanonicalFile();
84bf7c
             } else {
84bf7c
-                this.lockMarkerFile = new File(file.getParentFile(), file.getName() + LOCKFILE_SUFFIX)
84bf7c
-                        .getCanonicalFile();
84bf7c
+                lockFileCandidate = new File(file.getParentFile(), file.getName() + LOCKFILE_SUFFIX).getCanonicalFile();
84bf7c
             }
84bf7c
-            if (lockMarkerFile.isDirectory()) {
84bf7c
-                throw new RuntimeException("Lock marker file " + lockMarkerFile + " already exists and is a directory");
84bf7c
+
84bf7c
+            if (lockFileCandidate.isDirectory()) {
84bf7c
+                throw new RuntimeException("Lock marker file " + lockFileCandidate + " already exists and is a directory");
84bf7c
             }
84bf7c
-            File parentDir = lockMarkerFile.getParentFile();
84bf7c
+            File parentDir = lockFileCandidate.getParentFile();
84bf7c
             if (!parentDir.isDirectory() && !parentDir.mkdirs()) {
84bf7c
                 throw new RuntimeException("Could not create parent directory " + parentDir + " of lock marker file");
84bf7c
             }
84bf7c
+
84bf7c
+            String baseDir = System.getProperty("user.dir");
84bf7c
+            String reactorCache = baseDir + "/.m2/";
84bf7c
+            // In Fedora we can only assume reactor cache is safe for read/write.
84bf7c
+            if (!lockFileCandidate.getAbsolutePath().startsWith(reactorCache)) {
84bf7c
+                String lockFileDir = reactorCache + LOCKFILE_SUFFIX;
84bf7c
+                // If the file is located within baseDir, no need to repeat
84bf7c
+                String lockFileName = file.getAbsolutePath().replace(baseDir, "").replace("/", "-").replaceFirst("-", "/") + LOCKFILE_SUFFIX;
84bf7c
+                lockFileCandidate = new File(lockFileDir, lockFileName);
84bf7c
+            }
84bf7c
+
84bf7c
+            this.lockMarkerFile = lockFileCandidate;
84bf7c
             this.lockFileLocation = anyLocation.createLocation(null, null, false);
84bf7c
             this.lockFileLocation.set(lockMarkerFile.toURL(), false, lockMarkerFile.getAbsolutePath());
84bf7c
+
84bf7c
         } catch (MalformedURLException e) {
84bf7c
             throw new RuntimeException(e);
84bf7c
         } catch (IOException e) {
84bf7c
diff --git a/tycho-core/src/main/java/org/eclipse/tycho/core/maven/TychoMavenLifecycleParticipant.java b/tycho-core/src/main/java/org/eclipse/tycho/core/maven/TychoMavenLifecycleParticipant.java
84bf7c
index f733774..1bd97e6 100644
84bf7c
--- a/tycho-core/src/main/java/org/eclipse/tycho/core/maven/TychoMavenLifecycleParticipant.java
84bf7c
+++ b/tycho-core/src/main/java/org/eclipse/tycho/core/maven/TychoMavenLifecycleParticipant.java
84bf7c
@@ -30,6 +30,7 @@ import org.apache.maven.project.MavenProject;
84bf7c
 import org.codehaus.plexus.PlexusContainer;
84bf7c
 import org.codehaus.plexus.component.annotations.Component;
84bf7c
 import org.codehaus.plexus.component.annotations.Requirement;
84bf7c
+import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
84bf7c
 import org.codehaus.plexus.logging.Logger;
84bf7c
 import org.eclipse.tycho.ReactorProject;
84bf7c
 import org.eclipse.tycho.core.osgitools.BundleReader;
84bf7c
@@ -86,6 +87,18 @@ public class TychoMavenLifecycleParticipant extends AbstractMavenLifecyclePartic
84bf7c
 
84bf7c
             configureComponents(session);
84bf7c
 
84bf7c
+            try {
84bf7c
+                if (plexus.lookup("org.fedoraproject.xmvn.resolver.Resolver") != null) {
84bf7c
+                    if (session.isOffline()) {
84bf7c
+                        System.setProperty("TYCHO_MVN_RPMBUILD", "");
84bf7c
+                    } else {
84bf7c
+                        System.setProperty("TYCHO_MVN_LOCAL", "");
84bf7c
+                    }
84bf7c
+                }
84bf7c
+            } catch (ComponentLookupException e) {
84bf7c
+                // No XMvn (Upstream Maven in use)
84bf7c
+            }
84bf7c
+
84bf7c
             for (MavenProject project : projects) {
84bf7c
                 resolver.setupProject(session, project, DefaultReactorProject.adapt(project));
84bf7c
             }
84bf7c
diff --git a/tycho-core/src/main/java/org/eclipse/tycho/core/osgitools/AbstractTychoProject.java b/tycho-core/src/main/java/org/eclipse/tycho/core/osgitools/AbstractTychoProject.java
84bf7c
index 94b02f1..f833854 100644
84bf7c
--- a/tycho-core/src/main/java/org/eclipse/tycho/core/osgitools/AbstractTychoProject.java
84bf7c
+++ b/tycho-core/src/main/java/org/eclipse/tycho/core/osgitools/AbstractTychoProject.java
84bf7c
@@ -19,6 +19,9 @@ import org.eclipse.tycho.artifacts.DependencyArtifacts;
84bf7c
 import org.eclipse.tycho.core.TargetPlatformConfiguration;
84bf7c
 import org.eclipse.tycho.core.TychoConstants;
84bf7c
 import org.eclipse.tycho.core.TychoProject;
84bf7c
+import org.eclipse.tycho.core.ee.ExecutionEnvironmentUtils;
84bf7c
+import org.eclipse.tycho.core.ee.UnknownEnvironmentException;
84bf7c
+import org.eclipse.tycho.core.ee.shared.ExecutionEnvironment;
84bf7c
 import org.eclipse.tycho.core.ee.shared.ExecutionEnvironmentConfiguration;
84bf7c
 import org.eclipse.tycho.core.osgitools.targetplatform.LocalDependencyResolver;
84bf7c
 import org.eclipse.tycho.core.osgitools.targetplatform.MultiEnvironmentDependencyArtifacts;
84bf7c
@@ -94,15 +97,35 @@ public abstract class AbstractTychoProject extends AbstractLogEnabled implements
84bf7c
 
84bf7c
         String configuredForcedProfile = tpConfiguration.getExecutionEnvironment();
84bf7c
         if (configuredForcedProfile != null) {
84bf7c
+            configuredForcedProfile = overrideToAtLeastJavaSE16(configuredForcedProfile);
84bf7c
             sink.overrideProfileConfiguration(configuredForcedProfile,
84bf7c
                     "target-platform-configuration <executionEnvironment>");
84bf7c
         }
84bf7c
 
84bf7c
         String configuredDefaultProfile = tpConfiguration.getExecutionEnvironmentDefault();
84bf7c
         if (configuredDefaultProfile != null) {
84bf7c
+            configuredDefaultProfile = overrideToAtLeastJavaSE16(configuredDefaultProfile);
84bf7c
             sink.setProfileConfiguration(configuredDefaultProfile,
84bf7c
                     "target-platform-configuration <executionEnvironmentDefault>");
84bf7c
         }
84bf7c
     }
84bf7c
 
84bf7c
+    public String overrideToAtLeastJavaSE16 (String profile) {
84bf7c
+        try {
84bf7c
+            ExecutionEnvironment ee = ExecutionEnvironmentUtils.getExecutionEnvironment(profile);
84bf7c
+
84bf7c
+            if (System.getProperty("TYCHO_MVN_LOCAL") != null || System.getProperty("TYCHO_MVN_RPMBUILD") != null) {
84bf7c
+                // EE must be at least JavaSE-1.6
84bf7c
+                final ExecutionEnvironment javaSE16 = ExecutionEnvironmentUtils.getExecutionEnvironment("JavaSE-1.6");
84bf7c
+                if (! ee.isCompatibleCompilerTargetLevel(javaSE16.getCompilerTargetLevelDefault())) {
84bf7c
+                    ee = javaSE16;
84bf7c
+                }
84bf7c
+            }
84bf7c
+
84bf7c
+            return ee.getProfileName();
84bf7c
+        } catch (UnknownEnvironmentException e) {
84bf7c
+            // can't happen, ee is validated during configuration parsing
84bf7c
+            return null;
84bf7c
+        }
84bf7c
+    }
84bf7c
 }
84bf7c
diff --git a/tycho-core/src/main/java/org/eclipse/tycho/core/osgitools/OsgiBundleProject.java b/tycho-core/src/main/java/org/eclipse/tycho/core/osgitools/OsgiBundleProject.java
84bf7c
index 13ed51d..bd21204 100644
84bf7c
--- a/tycho-core/src/main/java/org/eclipse/tycho/core/osgitools/OsgiBundleProject.java
84bf7c
+++ b/tycho-core/src/main/java/org/eclipse/tycho/core/osgitools/OsgiBundleProject.java
84bf7c
@@ -504,6 +504,7 @@ public class OsgiBundleProject extends AbstractTychoProject implements BundlePro
84bf7c
         String pdeProfile = getEclipsePluginProject(DefaultReactorProject.adapt(project)).getBuildProperties()
84bf7c
                 .getJreCompilationProfile();
84bf7c
         if (pdeProfile != null) {
84bf7c
+            pdeProfile = overrideToAtLeastJavaSE16(pdeProfile);
84bf7c
             sink.setProfileConfiguration(pdeProfile.trim(), "build.properties");
84bf7c
 
84bf7c
         } else {
84bf7c
@@ -514,13 +515,13 @@ public class OsgiBundleProject extends AbstractTychoProject implements BundlePro
84bf7c
 
84bf7c
                 switch (tpConfiguration.getBREEHeaderSelectionPolicy()) {
84bf7c
                 case first:
84bf7c
-                    sink.setProfileConfiguration(manifestBREEs[0].getProfileName(),
84bf7c
+                    sink.setProfileConfiguration(overrideToAtLeastJavaSE16(manifestBREEs[0].getProfileName()),
84bf7c
                             "Bundle-RequiredExecutionEnvironment (first entry)");
84bf7c
                     break;
84bf7c
 
84bf7c
                 case minimal:
84bf7c
                     ExecutionEnvironment manifestMinimalEE = Collections.min(Arrays.asList(manifestBREEs));
84bf7c
-                    sink.setProfileConfiguration(manifestMinimalEE.getProfileName(),
84bf7c
+                    sink.setProfileConfiguration(overrideToAtLeastJavaSE16(manifestMinimalEE.getProfileName()),
84bf7c
                             "Bundle-RequiredExecutionEnvironment (minimal entry)");
84bf7c
                 }
84bf7c
 
84bf7c
diff --git a/tycho-core/src/main/java/org/eclipse/tycho/core/resolver/DefaultTargetPlatformConfigurationReader.java b/tycho-core/src/main/java/org/eclipse/tycho/core/resolver/DefaultTargetPlatformConfigurationReader.java
84bf7c
index ed413e1..0b89bae 100644
84bf7c
--- a/tycho-core/src/main/java/org/eclipse/tycho/core/resolver/DefaultTargetPlatformConfigurationReader.java
84bf7c
+++ b/tycho-core/src/main/java/org/eclipse/tycho/core/resolver/DefaultTargetPlatformConfigurationReader.java
84bf7c
@@ -68,7 +68,11 @@ public class DefaultTargetPlatformConfigurationReader {
84bf7c
                             + configuration.toString());
84bf7c
                 }
84bf7c
 
84bf7c
-                addTargetEnvironments(result, project, configuration);
84bf7c
+                // Use the defined environments only in local mode with tycho.local.keepTarget
84bf7c
+                if ((System.getProperty("TYCHO_MVN_LOCAL") == null && System.getProperty("TYCHO_MVN_RPMBUILD") == null)
84bf7c
+                        || System.getProperty("tycho.local.keepTarget") != null) {
84bf7c
+                    addTargetEnvironments(result, project, configuration);
84bf7c
+                }
84bf7c
 
84bf7c
                 setTargetPlatformResolver(result, configuration);
84bf7c
 
84bf7c
diff --git a/tycho-core/src/main/java/org/eclipse/tycho/osgi/runtime/TychoOsgiRuntimeLocator.java b/tycho-core/src/main/java/org/eclipse/tycho/osgi/runtime/TychoOsgiRuntimeLocator.java
84bf7c
index 35f1b6b..b64653e 100644
84bf7c
--- a/tycho-core/src/main/java/org/eclipse/tycho/osgi/runtime/TychoOsgiRuntimeLocator.java
84bf7c
+++ b/tycho-core/src/main/java/org/eclipse/tycho/osgi/runtime/TychoOsgiRuntimeLocator.java
84bf7c
@@ -12,6 +12,8 @@ package org.eclipse.tycho.osgi.runtime;
84bf7c
 
84bf7c
 import java.io.File;
84bf7c
 import java.io.IOException;
84bf7c
+import java.nio.file.Files;
84bf7c
+import java.nio.file.StandardCopyOption;
84bf7c
 import java.util.ArrayList;
84bf7c
 import java.util.List;
84bf7c
 import java.util.Map;
84bf7c
@@ -163,36 +165,49 @@ public class TychoOsgiRuntimeLocator implements EquinoxRuntimeLocator {
84bf7c
             File artifactFile = new File(session.getLocalRepository().getBasedir(), session.getLocalRepository()
84bf7c
                     .pathOf(artifact));
84bf7c
             File eclipseDir = new File(artifactFile.getParentFile(), "eclipse");
84bf7c
+            File eclipseSaveDir = new File(artifactFile.getParentFile(), "eclipse-save");
84bf7c
+            File fedoraDir = new File(artifactFile.getParentFile(), "fedora-eclipse");
84bf7c
 
84bf7c
             FileLocker locker = fileLockService.getFileLocker(artifactFile);
84bf7c
             locker.lock();
84bf7c
             try {
84bf7c
-                if (!eclipseDir.exists() || artifact.isSnapshot()) {
84bf7c
+                if (!fedoraDir.exists() || artifact.isSnapshot()) {
84bf7c
                     logger.debug("Extracting Tycho's OSGi runtime");
84bf7c
 
84bf7c
-                    if (artifact.getFile().lastModified() > eclipseDir.lastModified()) {
84bf7c
+                    if (artifact.getFile().lastModified() > fedoraDir.lastModified()) {
84bf7c
                         logger.debug("Unpacking Tycho's OSGi runtime to " + eclipseDir);
84bf7c
                         try {
84bf7c
-                            FileUtils.deleteDirectory(eclipseDir);
84bf7c
+                            FileUtils.deleteDirectory(fedoraDir);
84bf7c
+                            if (eclipseDir.exists()) {
84bf7c
+                                FileUtils.rename(eclipseDir, eclipseSaveDir);
84bf7c
+                            }
84bf7c
                         } catch (IOException e) {
84bf7c
-                            logger.warn("Failed to delete Tycho's OSGi runtime " + eclipseDir + ": " + e.getMessage());
84bf7c
+                            logger.warn("Failed to delete Tycho's OSGi runtime " + fedoraDir + ": " + e.getMessage());
84bf7c
                         }
84bf7c
                         unArchiver.setSourceFile(artifact.getFile());
84bf7c
                         unArchiver.setDestDirectory(eclipseDir.getParentFile());
84bf7c
                         try {
84bf7c
                             unArchiver.extract();
84bf7c
+                            logger.debug("Moving Tycho's OSGi runtime to " + fedoraDir);
84bf7c
+                            FileUtils.rename(eclipseDir, fedoraDir);
84bf7c
+                            if (eclipseSaveDir.exists()) {
84bf7c
+                                FileUtils.rename(eclipseSaveDir, eclipseDir);
84bf7c
+                            }
84bf7c
                         } catch (ArchiverException e) {
84bf7c
                             throw new MavenExecutionException("Failed to unpack Tycho's OSGi runtime: "
84bf7c
                                     + e.getMessage(), e);
84bf7c
+                        } catch (IOException e) {
84bf7c
+                            throw new MavenExecutionException("Failed to move Tycho's OSGi runtime: " + e.getMessage(),
84bf7c
+                                    e);
84bf7c
                         }
84bf7c
 
84bf7c
-                        eclipseDir.setLastModified(artifact.getFile().lastModified());
84bf7c
+                        fedoraDir.setLastModified(artifact.getFile().lastModified());
84bf7c
                     }
84bf7c
                 }
84bf7c
             } finally {
84bf7c
                 locker.release();
84bf7c
             }
84bf7c
-            description.addInstallation(eclipseDir);
84bf7c
+            description.addInstallation(fedoraDir);
84bf7c
         } else {
84bf7c
             description.addBundle(artifact.getFile());
84bf7c
         }
84bf7c
diff --git a/tycho-p2/tycho-p2-facade/pom.xml b/tycho-p2/tycho-p2-facade/pom.xml
84bf7c
index 9c59b14..54cc384 100644
84bf7c
--- a/tycho-p2/tycho-p2-facade/pom.xml
84bf7c
+++ b/tycho-p2/tycho-p2-facade/pom.xml
84bf7c
@@ -57,6 +57,11 @@
84bf7c
 			<artifactId>junit</artifactId>
84bf7c
 			<scope>test</scope>
84bf7c
 		</dependency>
84bf7c
+		<dependency>
84bf7c
+			<groupId>org.fedoraproject.p2</groupId>
84bf7c
+			<artifactId>org.fedoraproject.p2</artifactId>
84bf7c
+			<version>0.0.1-SNAPSHOT</version>
84bf7c
+		</dependency>
84bf7c
 	</dependencies>
84bf7c
 
84bf7c
 	<build>
84bf7c
diff --git a/tycho-p2/tycho-p2-facade/src/main/java/org/eclipse/tycho/p2/resolver/P2DependencyResolver.java b/tycho-p2/tycho-p2-facade/src/main/java/org/eclipse/tycho/p2/resolver/P2DependencyResolver.java
84bf7c
index d5be20c..8405058 100644
84bf7c
--- a/tycho-p2/tycho-p2-facade/src/main/java/org/eclipse/tycho/p2/resolver/P2DependencyResolver.java
84bf7c
+++ b/tycho-p2/tycho-p2-facade/src/main/java/org/eclipse/tycho/p2/resolver/P2DependencyResolver.java
84bf7c
@@ -89,6 +89,7 @@ import org.eclipse.tycho.p2.resolver.facade.P2ResolverFactory;
84bf7c
 import org.eclipse.tycho.p2.target.facade.PomDependencyCollector;
84bf7c
 import org.eclipse.tycho.p2.target.facade.TargetPlatformConfigurationStub;
84bf7c
 import org.eclipse.tycho.repository.registry.facade.ReactorRepositoryManagerFacade;
84bf7c
+import org.fedoraproject.p2.EclipseSystemLayout;
84bf7c
 
84bf7c
 @Component(role = DependencyResolver.class, hint = P2DependencyResolver.ROLE_HINT, instantiationStrategy = "per-lookup")
84bf7c
 public class P2DependencyResolver extends AbstractLogEnabled implements DependencyResolver, Initializable {
84bf7c
@@ -209,6 +210,13 @@ public class P2DependencyResolver extends AbstractLogEnabled implements Dependen
84bf7c
             pomDependencies.setProjectLocation(project.getBasedir());
84bf7c
         }
84bf7c
 
84bf7c
+        // Add Fedora Local P2 Repository when running in local mode
84bf7c
+        if (System.getProperty("TYCHO_MVN_LOCAL") != null || System.getProperty("TYCHO_MVN_RPMBUILD") != null) {
84bf7c
+            for (URI uri : EclipseSystemLayout.getRepositories()) {
84bf7c
+                tpConfiguration.addP2Repository(new MavenRepositoryLocation(uri.getPath(), uri));
84bf7c
+            }
84bf7c
+        }
84bf7c
+
84bf7c
         for (ArtifactRepository repository : project.getRemoteArtifactRepositories()) {
84bf7c
             addEntireP2RepositoryToTargetPlatform(repository, tpConfiguration);
84bf7c
         }
84bf7c
-- 
84bf7c
2.20.1
84bf7c