You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by cz...@apache.org on 2020/02/21 06:46:13 UTC
[sling-org-apache-sling-feature-io] branch master updated:
SLING-9098 : Provide support for directly downloading artifacts through mvn
This is an automated email from the ASF dual-hosted git repository.
cziegeler pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-feature-io.git
The following commit(s) were added to refs/heads/master by this push:
new 508836e SLING-9098 : Provide support for directly downloading artifacts through mvn
508836e is described below
commit 508836e49a4f42d5e99594a5ffaf2da485717d95
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Fri Feb 21 07:45:57 2020 +0100
SLING-9098 : Provide support for directly downloading artifacts through mvn
---
.../feature/io/artifacts/ArtifactHandler.java | 19 +++-
.../feature/io/artifacts/ArtifactManager.java | 120 ++++++++++++++++++++-
.../io/artifacts/ArtifactManagerConfig.java | 63 +++++++++--
3 files changed, 184 insertions(+), 18 deletions(-)
diff --git a/src/main/java/org/apache/sling/feature/io/artifacts/ArtifactHandler.java b/src/main/java/org/apache/sling/feature/io/artifacts/ArtifactHandler.java
index 044a8ef..c4d87ce 100644
--- a/src/main/java/org/apache/sling/feature/io/artifacts/ArtifactHandler.java
+++ b/src/main/java/org/apache/sling/feature/io/artifacts/ArtifactHandler.java
@@ -16,6 +16,8 @@
*/
package org.apache.sling.feature.io.artifacts;
+import java.io.File;
+import java.net.MalformedURLException;
import java.net.URL;
/**
@@ -29,7 +31,7 @@ public class ArtifactHandler {
/**
* Create a new handler.
- *
+ *
* @param url The url of the artifact
* @param localURL The local URL for the artifact
*/
@@ -39,8 +41,19 @@ public class ArtifactHandler {
}
/**
+ * Create a new handler.
+ *
+ * @param file The file for the artifact
+ * @throws MalformedURLException
+ * @since 1.1.0
+ */
+ public ArtifactHandler(final File file) throws MalformedURLException {
+ this(file.toURI().toString(), file.toURI().toURL());
+ }
+
+ /**
* Get the url of the artifact
- *
+ *
* @return The url.
*/
public String getUrl() {
@@ -49,7 +62,7 @@ public class ArtifactHandler {
/**
* Get a local url for the artifact
- *
+ *
* @return The file
*/
public URL getLocalURL() {
diff --git a/src/main/java/org/apache/sling/feature/io/artifacts/ArtifactManager.java b/src/main/java/org/apache/sling/feature/io/artifacts/ArtifactManager.java
index 223ca78..d1515ac 100644
--- a/src/main/java/org/apache/sling/feature/io/artifacts/ArtifactManager.java
+++ b/src/main/java/org/apache/sling/feature/io/artifacts/ArtifactManager.java
@@ -25,12 +25,19 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
+import java.lang.ProcessBuilder.Redirect;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
import java.util.Base64;
+import java.util.Comparator;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
@@ -86,6 +93,12 @@ public class ArtifactManager
return new ArtifactManager(config, providers);
}
+ /**
+ * Internal constructor for the manager
+ * @param config The configuration
+ * @param providers The provider map
+ * @throws IOException If the manager can't be initialized
+ */
ArtifactManager(final ArtifactManagerConfig config, final Map<String, ArtifactProvider> providers)
throws IOException {
this.config = config;
@@ -126,6 +139,12 @@ public class ArtifactManager
}
}
+ /**
+ * Return a feature provider based on this artifact manager
+ *
+ * @return A feature provider
+ * @since 1.1.0
+ */
public FeatureProvider toFeatureProvider() {
return (id -> {
try {
@@ -140,6 +159,7 @@ public class ArtifactManager
}
});
}
+
private final URL getArtifactFromProviders(final String url, final String relativeCachePath) throws IOException {
final int pos = url.indexOf(":");
final String scheme = url.substring(0, pos);
@@ -156,7 +176,7 @@ public class ArtifactManager
/**
* Get the full artifact url and file for an artifact.
- *
+ *
* @param url Artifact url or relative path.
* @return Absolute url and file in the form of a handler.
* @throws IOException If something goes wrong or the artifact can't be found.
@@ -166,10 +186,16 @@ public class ArtifactManager
final String path;
+ ArtifactId artifactId = null;
+
if ( url.startsWith("mvn:") ) {
// mvn url
- path = ArtifactId.fromMvnUrl(url).toMvnPath();
-
+ try {
+ artifactId = ArtifactId.fromMvnUrl(url);
+ path = artifactId.toMvnPath();
+ } catch (final IllegalArgumentException iae) {
+ throw new IOException(iae.getMessage(), iae);
+ }
} else if ( url.startsWith(":") ) {
// repository path
path = url.substring(1);
@@ -193,7 +219,7 @@ public class ArtifactManager
if ( !f.exists()) {
throw new IOException("Artifact " + url + " not found.");
}
- return new ArtifactHandler(f.toURI().toString(), f.toURI().toURL());
+ return new ArtifactHandler(f);
}
logger.debug("Querying repositories for {}", path);
@@ -255,6 +281,14 @@ public class ArtifactManager
}
}
+ // if we have an artifact id and using mvn is enabled, we try this as a last
+ // resort
+ if (artifactId != null && this.config.isUseMvn()) {
+ final File file = getArtifactFromMvn(artifactId);
+ if (file != null) {
+ return new ArtifactHandler(file);
+ }
+ }
throw new IOException("Artifact " + url + " not found in any repository.");
}
@@ -293,6 +327,7 @@ public class ArtifactManager
}
return value;
}
+
public static String getLatestSnapshot(final String mavenMetadata) {
final String timestamp = getValue(mavenMetadata, new String[] {"metadata", "versioning", "snapshot", "timestamp"});
final String buildNumber = getValue(mavenMetadata, new String[] {"metadata", "versioning", "snapshot", "buildNumber"});
@@ -412,4 +447,81 @@ public class ArtifactManager
return "DefaultArtifactHandler";
}
}
+
+ private File getArtifactFromMvn(final ArtifactId artifactId) {
+ final String filePath = this.config.getMvnHome()
+ .concat(artifactId.toMvnPath().replace('/', File.separatorChar));
+ logger.debug("Trying to fetch artifact {} from local mvn repository {}", artifactId.toMvnId(), filePath);
+ final File f = new File(filePath);
+ if (!f.exists() || !f.isFile() || !f.canRead()) {
+ logger.debug("Trying to download {}", artifactId.toMvnId());
+ try {
+ this.downloadArtifact(artifactId);
+ } catch (final IOException ioe) {
+ logger.debug("Error downloading file.", ioe);
+ }
+ if (!f.exists() || !f.isFile() || !f.canRead()) {
+ logger.info("Artifact not found {}", artifactId.toMvnId());
+
+ return null;
+ }
+ }
+ return f;
+ }
+
+ /**
+ * Download artifact from maven
+ *
+ * @throws IOException
+ */
+ private void downloadArtifact(final ArtifactId artifactId) throws IOException {
+ // create fake pom
+ final Path dir = Files.createTempDirectory(null);
+ try {
+ final List<String> lines = new ArrayList<String>();
+ lines.add(
+ "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">");
+ lines.add(" <modelVersion>4.0.0</modelVersion>");
+ lines.add(" <groupId>org.apache.sling</groupId>");
+ lines.add(" <artifactId>temp-artifact</artifactId>");
+ lines.add(" <version>1-SNAPSHOT</version>");
+ lines.add(" <dependencies>");
+ lines.add(" <dependency>");
+ lines.add(" <groupId>".concat(artifactId.getGroupId()).concat("</groupId>"));
+ lines.add(" <artifactId>".concat(artifactId.getArtifactId()).concat("</artifactId>"));
+ lines.add(" <version>".concat(artifactId.getVersion()).concat("</version>"));
+ if (artifactId.getClassifier() != null) {
+ lines.add(" <classifier>".concat(artifactId.getClassifier()).concat("</classifier>"));
+ }
+ if (!"bundle".equals(artifactId.getType()) && !"jar".equals(artifactId.getType())) {
+ lines.add(" <type>".concat(artifactId.getType()).concat("</type>"));
+ }
+ lines.add(" <scope>provided</scope>");
+ lines.add(" </dependency>");
+ lines.add(" </dependencies>");
+ lines.add("</project>");
+ logger.debug("Writing pom to {}", dir);
+ Files.write(dir.resolve("pom.xml"), lines, Charset.forName("UTF-8"));
+
+ final File output = dir.resolve("output.txt").toFile();
+ final File error = dir.resolve("error.txt").toFile();
+
+ // invoke maven
+ logger.debug("Invoking mvn...");
+ final ProcessBuilder pb = new ProcessBuilder("mvn", "verify");
+ pb.directory(dir.toFile());
+ pb.redirectOutput(Redirect.to(output));
+ pb.redirectError(Redirect.to(error));
+
+ final Process p = pb.start();
+ try {
+ p.waitFor();
+ } catch (final InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+
+ } finally {
+ Files.walk(dir).sorted(Comparator.reverseOrder()).map(Path::toFile).forEach(File::delete);
+ }
+ }
}
diff --git a/src/main/java/org/apache/sling/feature/io/artifacts/ArtifactManagerConfig.java b/src/main/java/org/apache/sling/feature/io/artifacts/ArtifactManagerConfig.java
index d03c7e3..82e6476 100644
--- a/src/main/java/org/apache/sling/feature/io/artifacts/ArtifactManagerConfig.java
+++ b/src/main/java/org/apache/sling/feature/io/artifacts/ArtifactManagerConfig.java
@@ -19,6 +19,7 @@ package org.apache.sling.feature.io.artifacts;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
+import java.util.concurrent.atomic.AtomicLong;
import org.apache.sling.feature.io.artifacts.spi.ArtifactProviderContext;
@@ -33,15 +34,25 @@ public class ArtifactManagerConfig implements ArtifactProviderContext {
/** The cache directory. */
private volatile File cacheDirectory;
- private volatile long cachedArtifacts;
+ /** Metrics for artifacts used from the cache. */
+ private final AtomicLong cachedArtifacts = new AtomicLong();
- private volatile long downloadedArtifacts;
+ /** Metrics for artifacts needed to be downloaded. */
+ private final AtomicLong downloadedArtifacts = new AtomicLong();
- private volatile long localArtifacts;
+ /** Metrics for artifacts read locally. */
+ private final AtomicLong localArtifacts = new AtomicLong();
+
+ /** Whether locally mvn command can be used to download artifacts. */
+ private volatile boolean useMvn = false;
+
+ /**
+ * The .m2 directory.
+ */
+ private final String repoHome;
/**
- * Create a new configuration object.
- * Set the default values
+ * Create a new configuration object. Set the default values
*/
public ArtifactManagerConfig() {
// set defaults
@@ -55,6 +66,7 @@ public class ArtifactManagerConfig implements ArtifactProviderContext {
} catch (IOException e) {
throw new RuntimeException(e);
}
+ this.repoHome = System.getProperty("user.home") + "/.m2/repository/";
}
/**
@@ -103,17 +115,17 @@ public class ArtifactManagerConfig implements ArtifactProviderContext {
@Override
public void incCachedArtifacts() {
- this.cachedArtifacts++;
+ this.cachedArtifacts.incrementAndGet();
}
@Override
public void incDownloadedArtifacts() {
- this.downloadedArtifacts++;
+ this.downloadedArtifacts.incrementAndGet();
}
@Override
public void incLocalArtifacts() {
- this.localArtifacts++;
+ this.localArtifacts.incrementAndGet();
}
/**
@@ -121,7 +133,7 @@ public class ArtifactManagerConfig implements ArtifactProviderContext {
* @return The number of cached artifacts
*/
public long getCachedArtifacts() {
- return this.cachedArtifacts;
+ return this.cachedArtifacts.get();
}
/**
@@ -129,7 +141,7 @@ public class ArtifactManagerConfig implements ArtifactProviderContext {
* @return The number of downloaded artifacts
*/
public long getDownloadedArtifacts() {
- return this.downloadedArtifacts;
+ return this.downloadedArtifacts.get();
}
/**
@@ -137,6 +149,35 @@ public class ArtifactManagerConfig implements ArtifactProviderContext {
* @return The number of local artifacts
*/
public long getLocalArtifacts() {
- return this.localArtifacts;
+ return this.localArtifacts.get();
+ }
+
+ /**
+ * Should mvn be used if an artifact can't be found in the repositories
+ *
+ * @return Whether mvn command should be used.
+ * @since 1.1.0
+ */
+ public boolean isUseMvn() {
+ return useMvn;
+ }
+
+ /**
+ * Set whether mvn should be used to get artifacts.
+ *
+ * @param useMvn flag for enabling mvn
+ * @since 1.1.0
+ */
+ public void setUseMvn(final boolean useMvn) {
+ this.useMvn = useMvn;
+ }
+
+ /**
+ * Return mvn home
+ *
+ * @since 1.1.0
+ */
+ String getMvnHome() {
+ return this.repoHome;
}
}