Blame SOURCES/tycho-use-custom-resolver.patch

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