blob: 89a40d81f8774a855cff9d5cf3dc21368e7cae79 [file] [log] [blame]
/**
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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 org.apache.winegrower.extension.build.common;
import static java.util.Arrays.asList;
import static java.util.Locale.ENGLISH;
import static java.util.stream.Collectors.joining;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.StandardCopyOption;
import java.nio.file.StandardOpenOption;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Collection;
import java.util.HashMap;
import java.util.stream.Stream;
import java.util.zip.GZIPOutputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
import org.apache.commons.text.StringSubstitutor;
public class Build implements Runnable {
private final Configuration configuration;
public Build(final Configuration configuration) {
this.configuration = configuration;
}
@Override
public void run() {
final File distroFolder = new File(configuration.workDir, configuration.artifactId + "-winegrower-distribution");
if (distroFolder.exists()) {
delete(distroFolder);
}
Stream.of("bin", "conf", "logs", "lib").forEach(i -> new File(distroFolder, i).mkdirs());
for (final String ext : asList("sh", "bat")) {
try (final BufferedReader reader = new BufferedReader(new InputStreamReader(
Thread.currentThread().getContextClassLoader().getResourceAsStream("bin/winegrower." + ext)))) {
write(new File(distroFolder, "bin/winegrower." + ext), StringSubstitutor.replace(reader.lines().collect(joining("\n")),
new HashMap<String, String>() {{
put("main", configuration.main);
}}));
} catch (final IOException e) {
throw new IllegalStateException(e.getMessage(), e);
}
}
copyProvidedFiles(configuration.basedir, distroFolder);
Stream.of("conf", "logs").forEach(folder ->
write(new File(distroFolder, folder + "/you_can_safely_delete.txt"), "Just there to not loose the folder cause it is empty, you can safely delete."));
configuration.jars.forEach(it -> addLib(distroFolder, it));
final Path prefix = configuration.skipArchiveRootFolder ? distroFolder.toPath() : distroFolder.getParentFile().toPath();
for (final String format : configuration.formats) {
final File output = new File(configuration.workDir, configuration.artifactId + "-winegrower-distribution." + format);
switch (format.toLowerCase(ENGLISH)) {
case "tar.gz":
try (final TarArchiveOutputStream tarGz =
new TarArchiveOutputStream(new GZIPOutputStream(new FileOutputStream(output)))) {
tarGz.setLongFileMode(TarArchiveOutputStream.LONGFILE_GNU);
for (final String entry : distroFolder.list()) {
tarGz(tarGz, new File(distroFolder, entry), prefix);
}
} catch (final IOException e) {
throw new IllegalStateException(e.getMessage(), e);
}
break;
case "zip":
try (final ZipArchiveOutputStream zos =
new ZipArchiveOutputStream(new FileOutputStream(output))) {
for (final String entry : distroFolder.list()) {
zip(zos, new File(distroFolder, entry), prefix);
}
} catch (final IOException e) {
throw new IllegalStateException(e.getMessage(), e);
}
break;
default:
throw new IllegalArgumentException(format + " is not supported");
}
}
if (!configuration.keepExplodedFolder) {
delete(distroFolder);
}
}
private void copyProvidedFiles(final File basedir, final File base) {
final File srcConf = new File(basedir, configuration.conf);
if (srcConf.exists() && srcConf.isDirectory()) {
final File targetConf = new File(base, "conf");
targetConf.mkdirs();
for (final File file : srcConf.listFiles()) {
final String fileName = file.getName();
if (fileName.startsWith(".")) {
// hidden file -> ignore
continue;
}
try {
Files.copy(file.toPath(), new File(targetConf, fileName).toPath());
} catch (final IOException e) {
throw new IllegalStateException("Could not copy file " + file.getAbsolutePath(), e);
}
}
}
final File srcBin = new File(basedir, configuration.bin);
if (srcBin.exists() && srcBin.isDirectory()) {
final File targetRoot = new File(base, "bin");
targetRoot.mkdirs();
Stream.of(srcBin.listFiles())
.filter(f -> !f.isDirectory()) // not nested for now
.forEach(f -> {
try {
final File target = new File(targetRoot, f.getName());
Files.copy(f.toPath(), target.toPath());
if (target.getName().endsWith(".sh")) {
target.setExecutable(true);
}
} catch (final IOException e) {
throw new IllegalArgumentException("Could not copy file " + f.getAbsolutePath(), e);
}
});
}
}
private void write(final File file, final String content) {
try {
Files.write(file.toPath(), content.getBytes(StandardCharsets.UTF_8), StandardOpenOption.WRITE, StandardOpenOption.CREATE);
} catch (final IOException e) {
throw new IllegalStateException(e);
}
}
private void delete(final File file) { // not critical
final Path rootPath = file.toPath();
try {
Files.walkFileTree(rootPath, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException {
Files.delete(file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(final Path dir, final IOException exc) throws IOException {
Files.delete(dir);
return FileVisitResult.CONTINUE;
}
});
} catch (final IOException e) {
// no-op
}
}
private void addLib(final File base, final File cc) {
try {
Files.copy(cc.toPath(), new File(base, "lib/" + cc.getName()).toPath(), StandardCopyOption.REPLACE_EXISTING);
} catch (final IOException e) {
throw new IllegalStateException(e.getMessage(), e);
}
}
private void zip(final ZipArchiveOutputStream zip, final File f, final Path prefix) throws IOException {
final String path = prefix.relativize(f.toPath()).toString().replace(File.separator, "/");
final ZipArchiveEntry archiveEntry = new ZipArchiveEntry(f, path);
if (isSh(path)) {
archiveEntry.setUnixMode(0755);
}
zip.putArchiveEntry(archiveEntry);
if (f.isDirectory()) {
zip.closeArchiveEntry();
final File[] files = f.listFiles();
if (files != null) {
for (final File child : files) {
zip(zip, child, prefix);
}
}
} else {
Files.copy(f.toPath(), zip);
zip.closeArchiveEntry();
}
}
private void tarGz(final TarArchiveOutputStream tarGz, final File f, final Path prefix) throws IOException {
final String path = prefix.relativize(f.toPath()).toString().replace(File.separator, "/");
final TarArchiveEntry archiveEntry = new TarArchiveEntry(f, path);
if (isSh(path)) {
archiveEntry.setMode(0755);
}
tarGz.putArchiveEntry(archiveEntry);
if (f.isDirectory()) {
tarGz.closeArchiveEntry();
final File[] files = f.listFiles();
if (files != null) {
for (final File child : files) {
tarGz(tarGz, child, prefix);
}
}
} else {
Files.copy(f.toPath(), tarGz);
tarGz.closeArchiveEntry();
}
}
private boolean isSh(final String path) {
return path.endsWith(".sh");
}
public static class Configuration {
private final File workDir;
private final File basedir;
private final String artifactId;
private final Collection<File> jars;
private final Collection<String> formats;
private final String main;
private final String bin;
private final String conf;
private final boolean skipArchiveRootFolder;
private final boolean keepExplodedFolder;
public Configuration(final File workDir, final File basedir,
final String artifactId, final Collection<File> jars,
final Collection<String> formats,
final String main, final String bin, final String conf,
final boolean skipArchiveRootFolder, final boolean keepExplodedFolder) {
this.workDir = workDir;
this.basedir = basedir;
this.artifactId = artifactId;
this.jars = jars;
this.formats = formats;
this.main = main;
this.bin = bin;
this.conf = conf;
this.skipArchiveRootFolder = skipArchiveRootFolder;
this.keepExplodedFolder = keepExplodedFolder;
}
}
}