package dev.jbang; import java.io.File; import java.io.IOException; import java.io.Reader; import java.io.Writer; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.*; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import io.quarkus.qute.Template; public class Settings { static AliasInfo aliasInfo = null; public static final String JBANG_REPO = "JBANG_REPO"; public static final String JBANG_DIR = "JBANG_DIR"; public static final String JBANG_CACHE_DIR = "JBANG_CACHE_DIR"; public static final String ALIASES_JSON = "aliases.json"; public static final String TRUSTED_SOURCES_JSON = "trusted-sources.json"; public static final String DEPENDENCY_CACHE_TXT = "dependency_cache.txt"; final public static String CP_SEPARATOR = System.getProperty("os.name").toLowerCase().contains("windows") ? ";" : ":"; private static TrustedSources trustedSources; public static File getLocalMavenRepo() { return new File(System.getenv().getOrDefault(JBANG_REPO, System.getProperty("user.home") + "/.m2/repository")) .getAbsoluteFile(); } public static Path getCacheDependencyFile() { return getCacheDir(true).resolve(DEPENDENCY_CACHE_TXT); } public static Path getConfigDir(boolean init) { Path dir; String jd = System.getenv(JBANG_DIR); if (jd != null) { dir = Paths.get(jd); } else { dir = Paths.get(System.getProperty("user.home")).resolve(".jbang"); } if (init) setupJbangDir(dir); return dir; } public static Path getConfigDir() { return getConfigDir(true); } public static void setupJbangDir(Path dir) { // create JBang configuration dir if it does not yet exist dir.toFile().mkdirs(); } public static Path getCacheDir(boolean init) { Path dir; String v = System.getenv(JBANG_CACHE_DIR); if (v != null) { dir = Paths.get(v); } else { dir = getConfigDir().resolve("cache"); } if (init) setupCache(dir); return dir; } public static Path getCacheDir() { return getCacheDir(true); } private static void setupCache(Path dir) { // create cache dir if it does not yet exist dir.toFile().mkdirs(); } public static Path getTrustedSourcesFile() { return getConfigDir().resolve(TRUSTED_SOURCES_JSON); } void createTrustedSources() { Path trustedSourcesFile = getTrustedSourcesFile(); if (Files.notExists(trustedSourcesFile)) { String templateName = "trusted-sources.qute"; Template template = Settings.getTemplateEngine().getTemplate(templateName); if (template == null) throw new ExitException(1, "Could not locate template named: '" + templateName + "'"); String result = template.render(); try { Util.writeString(trustedSourcesFile, result); } catch (IOException e) { Util.errorMsg("Could not create initial trusted-sources file at " + trustedSourcesFile, e); } } } public static TrustedSources getTrustedSources() { if (trustedSources == null) { Path trustedSourcesFile = getTrustedSourcesFile(); if (Files.isRegularFile(trustedSourcesFile)) { try { trustedSources = TrustedSources.load(trustedSourcesFile); } catch (IOException e) { Util.warnMsg("Could not read " + trustedSourcesFile); trustedSources = new TrustedSources(new String[0]); } } else { trustedSources = new TrustedSources(new String[0]); } } return trustedSources; } public static void clearCache() { try { Files .walk(Settings.getCacheDir()) .sorted(Comparator.reverseOrder()) .map(Path::toFile) .forEach(File::delete); } catch (IOException e) { throw new ExitException(-1, "Could not delete cache.", e); } } static TemplateEngine te; public static TemplateEngine getTemplateEngine() { if (te == null) { te = new TemplateEngine(); } return te; } public static class Alias { public final String scriptRef; public final String description; public final List<String> arguments; public final Map<String, String> properties; Alias(String scriptRef, String description, List<String> arguments, Map<String, String> properties) { this.scriptRef = scriptRef; this.description = description; this.arguments = arguments; this.properties = properties; } } static class AliasInfo { Map<String, Alias> aliases = new HashMap<>(); } public static Path getAliasesFile() { return getConfigDir().resolve(ALIASES_JSON); } private static AliasInfo getAliasInfo() { if (aliasInfo == null) { Path aliasesFile = getAliasesFile(); if (Files.isRegularFile(aliasesFile)) { try (Reader in = Files.newBufferedReader(aliasesFile)) { Gson parser = new Gson(); aliasInfo = parser.fromJson(in, AliasInfo.class); } catch (IOException e) { // Ignore errors } } else { aliasInfo = new AliasInfo(); } } return aliasInfo; } public static Map<String, Alias> getAliases() { return getAliasInfo().aliases; } public static Alias getAlias(String ref, List<String> arguments, Map<String, String> properties) { HashSet<String> names = new HashSet<>(); Alias alias = new Alias(null, null, arguments, properties); return mergeAliases(alias, ref, names); } private static Alias mergeAliases(Alias a1, String ref2, HashSet<String> names) { if (names.contains(ref2)) { throw new RuntimeException("Encountered alias loop on '" + ref2 + "'"); } Alias a2 = getAliases().get(ref2); if (a2 != null) { names.add(ref2); a2 = mergeAliases(a2, a2.scriptRef, names); List<String> args = a1.arguments != null ? a1.arguments : a2.arguments; Map<String, String> props = a1.properties != null ? a1.properties : a2.properties; return new Alias(a2.scriptRef, null, args, props); } else { return a1; } } public static void addAlias(String name, String scriptRef, String description, List<String> arguments, Map<String, String> properties) { getAliases().put(name, new Alias(scriptRef, description, arguments, properties)); try (Writer out = Files.newBufferedWriter(getAliasesFile())) { Gson parser = new GsonBuilder().setPrettyPrinting().create(); parser.toJson(getAliasInfo(), out); } catch (IOException ex) { Util.warnMsg("Unable to add alias: " + ex.getMessage()); } } public static void removeAlias(String name) { if (getAliasInfo().aliases.containsKey(name)) { try (Writer out = Files.newBufferedWriter(getAliasesFile())) { getAliases().remove(name); Gson parser = new GsonBuilder().setPrettyPrinting().create(); parser.toJson(getAliasInfo(), out); } catch (IOException ex) { Util.warnMsg("Unable to remove alias: " + ex.getMessage()); } } } }