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