Skip to content

Commit

Permalink
Adding DownloadAndUnzip minisite action
Browse files Browse the repository at this point in the history
  • Loading branch information
rmannibucau committed Dec 2, 2022
1 parent e85b86d commit 325e4a4
Show file tree
Hide file tree
Showing 4 changed files with 172 additions and 0 deletions.
11 changes: 11 additions & 0 deletions _documentation/src/main/minisite/content/mojos.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,17 @@ Using `type=simple-configuration` (recommended) or `type=io.yupiik.tools.minisit
. `class`: root configuration fully qualified name.
. `output`: where to generate the `.adoc` to.

==== Download and Unzip

Using `type=download-unzip` (recommended) or `type=io.yupiik.tools.minisite.action.builtin.DownloadAndUnzip` enables to download a zip from a HTTP url then extract it totally or partially to a particular folder.
This can be used to download a git repository using Github/Gitlab/Gitea API for example.

. `url`: the zip URL.
. `subpath`: the subpath to copy in `target`. It filters the zip entries names by prefix.
. `headers`: in properties format, a set of headers to set.
. `target`: where to copy the selected files.
. `workdir`: temporary folder (to download the zip), temporary if not set.

==== Replace string in file

Using `type=replace-in-file` (recommended) or `type=io.yupiik.tools.minisite.action.builtin.ReplaceInFile` will rewrite a text file replacing a string by another one.
Expand Down
17 changes: 17 additions & 0 deletions minisite-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,28 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<executions>
<execution>
<id>compile-11</id>
<phase>process-resources</phase>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<source>11</source>
<target>11</target>
<includes>
<include>**/DownloadAndUnzip.java</include>
</includes>
</configuration>
</execution>
<execution>
<id>default-compile</id>
<configuration>
<source>8</source>
<target>8</target>
<excludes>
<exclude>**/DownloadAndUnzip.java</exclude>
</excludes>
</configuration>
</execution>
</executions>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import io.yupiik.maven.service.action.builtin.CopyFile;
import io.yupiik.maven.service.action.builtin.JsonSchemaGenerator;
import io.yupiik.maven.service.action.builtin.MojoDocumentationGeneration;
import io.yupiik.tools.minisite.action.builtin.DownloadAndUnzip;
import io.yupiik.tools.minisite.action.builtin.OpenMetricsToAsciidoc;
import io.yupiik.tools.minisite.action.builtin.ReplaceInFile;
import io.yupiik.tools.minisite.action.builtin.SimpleConfigurationGenerator;
Expand Down Expand Up @@ -59,6 +60,8 @@ private Class<? extends Runnable> findActionClass(final String name) throws Clas
return SimpleConfigurationGenerator.class;
case "replace-in-file":
return ReplaceInFile.class;
case "download-unzip":
return DownloadAndUnzip.class;
default:
return Thread.currentThread().getContextClassLoader()
.loadClass(name)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/*
* Copyright (c) 2020 - Yupiik SAS - https://www.yupiik.com
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package io.yupiik.tools.minisite.action.builtin;

import java.io.IOException;
import java.io.StringReader;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.StandardCopyOption;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Map;
import java.util.Properties;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import static java.util.Objects.requireNonNull;
import static java.util.Optional.ofNullable;

public class DownloadAndUnzip implements Runnable {
private final String url;
private final String subpath;
private final String target;
private final String workdir;
private final Properties headers;

public DownloadAndUnzip(final Map<String, String> configuration) {
this.url = requireNonNull(configuration.get("url"), "No 'url'.");
this.subpath = configuration.getOrDefault("subpath", "");
this.target = requireNonNull(configuration.get("target"), "No 'target'");
this.workdir = configuration.get("workdir");
this.headers = ofNullable(configuration.get("headers"))
.map(h -> {
final Properties props = new Properties();
try (final StringReader reader = new StringReader(h)) {
props.load(reader);
} catch (final IOException e) {
throw new IllegalStateException(e);
}
return props;
})
.orElseGet(Properties::new);
}

@Override
public void run() {
final HttpClient http = HttpClient.newBuilder().followRedirects(HttpClient.Redirect.ALWAYS).build();
final HttpRequest.Builder builder = HttpRequest.newBuilder()
.GET()
.uri(URI.create(url));
headers.stringPropertyNames().forEach(key -> builder.header(key, headers.getProperty(key)));

final boolean deleteWorkDir = workdir == null || !Files.exists(Paths.get(workdir));
final Path work = ofNullable(workdir)
.map(Paths::get)
.orElseGet(() -> {
try {
return Files.createTempDirectory("ypkmst");
} catch (final IOException e) {
throw new IllegalStateException(e);
}
});
try {
final Path zip = Files.createDirectories(work).resolve("download-" + url.hashCode() + ".zip");
Files.deleteIfExists(zip);
try {
final HttpResponse<Path> response = http.send(
builder.build(),
HttpResponse.BodyHandlers.ofFile(zip));
if (response.statusCode() < 200 || response.statusCode() > 399) {
throw new IllegalStateException(response.toString());
}

final Path baseOutput = Paths.get(target);
try (final ZipInputStream jar = new ZipInputStream(Files.newInputStream(zip))) {
ZipEntry entry;
while ((entry = jar.getNextEntry()) != null) {
if (!entry.getName().startsWith(subpath) && !entry.isDirectory()) {
continue;
}
final Path out = baseOutput.resolve(entry.getName().substring(subpath.length()));
if (out.getParent() != null) {
Files.createDirectories(out.getParent());
}
Files.copy(jar, out, StandardCopyOption.REPLACE_EXISTING);
}
}
} finally {
Files.deleteIfExists(zip);
}
} catch (final IOException e) {
throw new IllegalStateException(e);
} catch (final InterruptedException e) {
Thread.currentThread().interrupt();
throw new IllegalStateException(e);
} finally {
if (deleteWorkDir) {
delete(work);
}
}
}

private void delete(final Path work) {
try {
Files.walkFileTree(work, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException {
Files.delete(file);
return super.visitFile(file, attrs);
}

@Override
public FileVisitResult postVisitDirectory(final Path dir, final IOException exc) throws IOException {
Files.delete(dir);
return super.postVisitDirectory(dir, exc);
}
});
} catch (final IOException e) {
// no-op
}
}
}

0 comments on commit 325e4a4

Please sign in to comment.