package restx.common;
import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableList;
import com.google.common.io.ByteSink;
import com.google.common.io.ByteSource;
import com.google.common.io.CharSource;
import com.google.common.io.Resources;
import com.samskivert.mustache.Mustache;
import com.samskivert.mustache.Template;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Map;
import java.util.regex.Pattern;
import static com.google.common.io.Files.asByteSink;
import static com.google.common.io.Files.asByteSource;
import static com.google.common.io.Files.asCharSource;
/**
* Date: 6/1/14
* Time: 23:27
*/
public class Archetype {
public static Archetype buildArchetype(String packageName) {
Map<String,URL> resources = MoreResources.findResources(packageName, Pattern.compile(".*"), true);
ImmutableList.Builder<ArchetypeEntry> builder = ImmutableList.builder();
for (String r : resources.keySet()) {
if (r.substring(r.lastIndexOf('/') + 1).startsWith("_")) {
builder.add(buildTemplate(packageName.replace('.', '/') + '/', r.substring(packageName.length() + 1)));
} else {
builder.add(new StaticArchetypeEntry(r.substring(packageName.length() + 1),
Resources.asByteSource(Resources.getResource(r))));
}
}
return new Archetype(builder.build());
}
public static Archetype buildArchetype(final Path basePath) {
try {
final ImmutableList.Builder<ArchetypeEntry> builder = ImmutableList.builder();
Files.walkFileTree(basePath, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
String name = basePath.relativize(file).toString();
if (file.getFileName().toString().startsWith("_")) {
builder.add(buildTemplate(name, asCharSource(file.toFile(), Charsets.UTF_8)));
} else {
builder.add(new StaticArchetypeEntry(name, asByteSource(file.toFile())));
}
return FileVisitResult.CONTINUE;
}
});
return new Archetype(builder.build());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private static TemplateArchetypeEntry buildTemplate(String basePath, String tpl) {
return new TemplateArchetypeEntry(Mustaches.compile(basePath + tpl),
tpl
.replaceAll("^_([^/]+$)", "$1")
.replaceAll("/_([^/]+$)", "/$1")
.replaceAll("\\$([^_]+)\\$", "\\{\\{$1\\}\\}"));
}
private static TemplateArchetypeEntry buildTemplate(String tplPath,
CharSource charSource) {
return new TemplateArchetypeEntry(Mustaches.compile(tplPath, charSource),
tplPath
.replaceAll("^_([^/]+$)", "$1")
.replaceAll("/_([^/]+$)", "/$1")
.replaceAll("\\$([^_]+)\\$", "\\{\\{$1\\}\\}"));
}
public abstract static class ArchetypeEntry {
public abstract void generate(Path path, Object scope) throws IOException;
protected Path resolvePath(Path path, String relative, Object scope) {
return path.resolve(Mustaches.execute(
Mustache.compiler().escapeHTML(false).compile(relative), scope));
}
}
public static class StaticArchetypeEntry extends ArchetypeEntry {
private final String path;
private final ByteSource byteSource;
public StaticArchetypeEntry(String path, ByteSource byteSource) {
this.path = path;
this.byteSource = byteSource;
}
@Override
public void generate(Path path, Object scope) throws IOException {
File dest = resolvePath(path, this.path, scope).toFile();
if (dest.getParentFile() != null && !dest.getParentFile().exists()) {
dest.getParentFile().mkdirs();
}
byteSource.copyTo(asByteSink(dest));
}
}
public static class TemplateArchetypeEntry extends ArchetypeEntry {
private final Template template;
private final String path;
public TemplateArchetypeEntry(Template template, String path) {
this.template = template;
this.path = path;
}
@Override
public void generate(Path path, Object scope) throws IOException {
Mustaches.execute(template, scope, resolvePath(path, this.path, scope));
}
}
private final ImmutableList<ArchetypeEntry> entries;
private Archetype(ImmutableList<ArchetypeEntry> entries) {
this.entries = entries;
}
public void generate(Path path, Object scope) throws IOException {
for (ArchetypeEntry entry : entries) {
entry.generate(path, scope);
}
}
}