Issue #5264 - Supporting extract of maven archive to destination
Signed-off-by: Joakim Erdfelt <joakim.erdfelt@gmail.com>
This commit is contained in:
parent
e338310c0a
commit
ba78355bd6
|
@ -21,11 +21,15 @@ package org.eclipse.jetty.start;
|
|||
import java.io.Closeable;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.attribute.FileTime;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Locale;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
public class FS
|
||||
{
|
||||
|
@ -168,4 +172,52 @@ public class FS
|
|||
{
|
||||
return path.toRealPath();
|
||||
}
|
||||
|
||||
public static void extract(Path archive, Path destination) throws IOException
|
||||
{
|
||||
String filename = archive.getFileName().toString().toLowerCase(Locale.US);
|
||||
|
||||
if (filename.endsWith(".jar") || filename.endsWith(".zip"))
|
||||
{
|
||||
extractZip(archive, destination);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IOException("Unable to extract unsupported archive format: " + archive);
|
||||
}
|
||||
}
|
||||
|
||||
public static void extractZip(Path archive, Path destination) throws IOException
|
||||
{
|
||||
try (ZipFile zip = new ZipFile(archive.toFile()))
|
||||
{
|
||||
StartLog.info("extract %s to %s", archive, destination);
|
||||
Enumeration<? extends ZipEntry> entries = zip.entries();
|
||||
while (entries.hasMoreElements())
|
||||
{
|
||||
ZipEntry entry = entries.nextElement();
|
||||
|
||||
if (entry.isDirectory() || entry.getName().startsWith("/META-INF"))
|
||||
{
|
||||
// skip
|
||||
continue;
|
||||
}
|
||||
|
||||
Path destFile = destination.resolve(entry.getName());
|
||||
if (!Files.exists(destFile))
|
||||
{
|
||||
FS.ensureDirectoryExists(destFile.getParent());
|
||||
try (InputStream input = zip.getInputStream(entry))
|
||||
{
|
||||
StartLog.debug("extracting %s", destFile);
|
||||
Files.copy(input, destFile);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
StartLog.debug("skipping extract (file exists) %s", destFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,13 +20,12 @@ package org.eclipse.jetty.start;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URI;
|
||||
import java.nio.file.DirectoryStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
|
@ -143,23 +142,9 @@ public abstract class FileInitializer
|
|||
throw new IOException("URL GET Failure [" + status + "/" + http.getResponseMessage() + "] on " + uri);
|
||||
}
|
||||
|
||||
byte[] buf = new byte[8192];
|
||||
try (InputStream in = http.getInputStream();
|
||||
OutputStream out = Files.newOutputStream(destination, StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE))
|
||||
try (InputStream in = http.getInputStream())
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
int len = in.read(buf);
|
||||
|
||||
if (len > 0)
|
||||
{
|
||||
out.write(buf, 0, len);
|
||||
}
|
||||
if (len < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
Files.copy(in, destination, StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ import java.io.IOException;
|
|||
import java.net.URI;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import org.eclipse.jetty.start.BaseHome;
|
||||
|
@ -105,7 +106,7 @@ public class MavenLocalRepoFileInitializer extends FileInitializer
|
|||
}
|
||||
}
|
||||
|
||||
private Path localRepositoryDir;
|
||||
private final Path localRepositoryDir;
|
||||
private final boolean readonly;
|
||||
private String mavenRepoUri;
|
||||
|
||||
|
@ -116,19 +117,24 @@ public class MavenLocalRepoFileInitializer extends FileInitializer
|
|||
|
||||
public MavenLocalRepoFileInitializer(BaseHome baseHome, Path localRepoDir, boolean readonly)
|
||||
{
|
||||
super(baseHome, "maven");
|
||||
this.localRepositoryDir = localRepoDir;
|
||||
this.readonly = readonly;
|
||||
this(baseHome, localRepoDir, readonly, null);
|
||||
}
|
||||
|
||||
public MavenLocalRepoFileInitializer(BaseHome baseHome, Path localRepoDir, boolean readonly, String mavenRepoUri)
|
||||
{
|
||||
super(baseHome, "maven");
|
||||
this.localRepositoryDir = localRepoDir;
|
||||
this.localRepositoryDir = localRepoDir != null ? localRepoDir : newTempRepo();
|
||||
this.readonly = readonly;
|
||||
this.mavenRepoUri = mavenRepoUri;
|
||||
}
|
||||
|
||||
private static Path newTempRepo()
|
||||
{
|
||||
Path javaTempDir = Paths.get(System.getProperty("java.io.tmpdir"));
|
||||
// Simple return here, don't create the directory, unless it's being used.
|
||||
return javaTempDir.resolve("jetty-start-downloads");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean create(URI uri, String location) throws IOException
|
||||
{
|
||||
|
@ -139,16 +145,55 @@ public class MavenLocalRepoFileInitializer extends FileInitializer
|
|||
return false;
|
||||
}
|
||||
|
||||
Path destination = getDestination(uri, location);
|
||||
|
||||
if (isFilePresent(destination))
|
||||
return false;
|
||||
|
||||
// If using local repository
|
||||
if (this.localRepositoryDir != null)
|
||||
URI destURI = URI.create(location);
|
||||
if (destURI.isAbsolute() && destURI.getScheme().equals("extract"))
|
||||
{
|
||||
// Grab copy from local repository (download if needed to local
|
||||
// repository)
|
||||
// Extract Flow
|
||||
|
||||
// Download to local repo.
|
||||
Path localFile = localRepositoryDir.resolve(coords.toPath());
|
||||
if (!FS.canReadFile(localFile))
|
||||
{
|
||||
if (FS.ensureDirectoryExists(localFile.getParent()))
|
||||
StartLog.info("mkdir " + _basehome.toShortForm(localFile.getParent()));
|
||||
download(coords, localFile);
|
||||
if (!FS.canReadFile(localFile))
|
||||
{
|
||||
throw new IOException("Unable to establish temp copy of file to extract: " + localFile);
|
||||
}
|
||||
}
|
||||
|
||||
// Destination Directory
|
||||
Path destination;
|
||||
String extractLocation = destURI.getSchemeSpecificPart();
|
||||
if (extractLocation.equals("/"))
|
||||
{
|
||||
destination = _basehome.getBasePath();
|
||||
}
|
||||
else
|
||||
{
|
||||
extractLocation = extractLocation.replaceFirst("^[/\\\\]*", "");
|
||||
if (!extractLocation.endsWith("/"))
|
||||
throw new IOException("Extract mode can only unpack to a directory, end your URL with a slash: " + location);
|
||||
destination = _basehome.getBasePath().resolve(extractLocation);
|
||||
|
||||
if (Files.exists(destination) && !Files.isDirectory(destination))
|
||||
throw new IOException("Destination already exists, and is not a directory: " + destination);
|
||||
|
||||
if (!destination.startsWith(_basehome.getBasePath()))
|
||||
throw new IOException("For security reasons, Jetty start is unable to extract outside of the ${jetty.base} - " + location);
|
||||
}
|
||||
|
||||
FS.extract(localFile, destination);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Copy Flow
|
||||
Path destination = getDestination(uri, location);
|
||||
if (isFilePresent(destination))
|
||||
return false;
|
||||
|
||||
// Grab copy from local repository (download if needed to local repository)
|
||||
Path localRepoFile = getLocalRepoFile(coords);
|
||||
|
||||
if (localRepoFile != null)
|
||||
|
@ -159,10 +204,11 @@ public class MavenLocalRepoFileInitializer extends FileInitializer
|
|||
Files.copy(localRepoFile, destination);
|
||||
return true;
|
||||
}
|
||||
|
||||
// normal non-local repo version
|
||||
download(coords, destination);
|
||||
}
|
||||
|
||||
// normal non-local repo version
|
||||
download(coords, destination);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,6 @@ import java.io.IOException;
|
|||
import java.net.URI;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import org.eclipse.jetty.start.BaseHome;
|
||||
import org.eclipse.jetty.start.config.ConfigSources;
|
||||
|
@ -30,7 +29,6 @@ import org.eclipse.jetty.start.config.JettyBaseConfigSource;
|
|||
import org.eclipse.jetty.start.config.JettyHomeConfigSource;
|
||||
import org.eclipse.jetty.start.fileinits.MavenLocalRepoFileInitializer.Coordinates;
|
||||
import org.eclipse.jetty.toolchain.test.FS;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDir;
|
||||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
|
@ -55,11 +53,15 @@ public class MavenLocalRepoFileInitializerTest
|
|||
@BeforeEach
|
||||
public void setupBaseHome() throws IOException
|
||||
{
|
||||
Path homeDir = testdir.getEmptyPathDir();
|
||||
Path homeDir = testdir.getEmptyPathDir().resolve("home");
|
||||
Path baseDir = testdir.getEmptyPathDir().resolve("base");
|
||||
|
||||
FS.ensureDirExists(homeDir);
|
||||
FS.ensureDirExists(baseDir);
|
||||
|
||||
ConfigSources config = new ConfigSources();
|
||||
config.add(new JettyHomeConfigSource(homeDir));
|
||||
config.add(new JettyBaseConfigSource(homeDir));
|
||||
config.add(new JettyBaseConfigSource(baseDir));
|
||||
|
||||
this.baseHome = new BaseHome(config);
|
||||
}
|
||||
|
@ -193,7 +195,7 @@ public class MavenLocalRepoFileInitializerTest
|
|||
assertThat("coords.toCentralURI", coords.toCentralURI().toASCIIString(),
|
||||
is("https://repo1.maven.org/maven2/org/eclipse/jetty/jetty-http/9.4.31.v20200723/jetty-http-9.4.31.v20200723-tests.jar"));
|
||||
|
||||
Path destination = Paths.get(System.getProperty("java.io.tmpdir"), "jetty-http-9.4.31.v20200723-tests.jar");
|
||||
Path destination = testdir.getEmptyPathDir().resolve("jetty-http-9.4.31.v20200723-tests.jar");
|
||||
Files.deleteIfExists(destination);
|
||||
repo.download(coords.toCentralURI(), destination);
|
||||
assertThat(Files.exists(destination), is(true));
|
||||
|
@ -204,7 +206,7 @@ public class MavenLocalRepoFileInitializerTest
|
|||
public void testDownloadSnapshotRepo()
|
||||
throws Exception
|
||||
{
|
||||
Path snapshotLocalRepoDir = MavenTestingUtils.getTargetTestingPath("snapshot-repo");
|
||||
Path snapshotLocalRepoDir = testdir.getPath().resolve("snapshot-repo");
|
||||
FS.ensureEmpty(snapshotLocalRepoDir);
|
||||
|
||||
MavenLocalRepoFileInitializer repo =
|
||||
|
@ -222,10 +224,43 @@ public class MavenLocalRepoFileInitializerTest
|
|||
assertThat("coords.toCentralURI", coords.toCentralURI().toASCIIString(),
|
||||
is("https://oss.sonatype.org/content/repositories/jetty-snapshots/org/eclipse/jetty/jetty-rewrite/10.0.0-SNAPSHOT/jetty-rewrite-10.0.0-SNAPSHOT.jar"));
|
||||
|
||||
Path destination = Paths.get(System.getProperty("java.io.tmpdir"), "jetty-rewrite-10.0.0-SNAPSHOT.jar");
|
||||
Files.deleteIfExists(destination);
|
||||
Path destination = baseHome.getBasePath().resolve("jetty-rewrite-10.0.0-SNAPSHOT.jar");
|
||||
repo.download(coords, destination);
|
||||
assertThat(Files.exists(destination), is(true));
|
||||
assertThat("Snapshot File size", destination.toFile().length(), greaterThan(10_000L));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDownloadSnapshotRepoWithExtractDeep()
|
||||
throws Exception
|
||||
{
|
||||
Path snapshotLocalRepoDir = testdir.getPath().resolve("snapshot-repo");
|
||||
FS.ensureEmpty(snapshotLocalRepoDir);
|
||||
|
||||
MavenLocalRepoFileInitializer repo =
|
||||
new MavenLocalRepoFileInitializer(baseHome, snapshotLocalRepoDir, false,
|
||||
"https://oss.sonatype.org/content/repositories/jetty-snapshots/");
|
||||
String ref = "maven://org.eclipse.jetty/test-jetty-webapp/10.0.0-SNAPSHOT/jar/config";
|
||||
Path baseDir = baseHome.getBasePath();
|
||||
repo.create(URI.create(ref), "extract:company/");
|
||||
|
||||
assertThat(Files.exists(baseDir.resolve("company/webapps/test.d/override-web.xml")), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDownloadSnapshotRepoWithExtractDefault()
|
||||
throws Exception
|
||||
{
|
||||
Path snapshotLocalRepoDir = testdir.getPath().resolve("snapshot-repo");
|
||||
FS.ensureEmpty(snapshotLocalRepoDir);
|
||||
|
||||
MavenLocalRepoFileInitializer repo =
|
||||
new MavenLocalRepoFileInitializer(baseHome, snapshotLocalRepoDir, false,
|
||||
"https://oss.sonatype.org/content/repositories/jetty-snapshots/");
|
||||
String ref = "maven://org.eclipse.jetty/test-jetty-webapp/10.0.0-SNAPSHOT/jar/config";
|
||||
Path baseDir = baseHome.getBasePath();
|
||||
repo.create(URI.create(ref), "extract:/");
|
||||
|
||||
assertThat(Files.exists(baseDir.resolve("webapps/test.d/override-web.xml")), is(true));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue