package aQute.jpm.platform; import static aQute.lib.io.IO.copy; import java.io.File; import java.io.IOException; import java.io.PrintStream; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Collection; import java.util.Formatter; import java.util.Map; import aQute.jpm.lib.ArtifactData; import aQute.jpm.lib.CommandData; import aQute.jpm.lib.JVM; import aQute.jpm.lib.JustAnotherPackageManager; import aQute.jpm.lib.ServiceData; import aQute.lib.collections.ExtList; import aQute.lib.getopt.CommandLine; import aQute.lib.io.IO; import aQute.libg.reporter.ReporterAdapter; import aQute.libg.sed.Sed; import aQute.service.reporter.Reporter; public abstract class Platform { public enum Type { UNKNOWN, WINDOWS, LINUX, MACOS }; static Platform platform; static Runtime runtime = Runtime.getRuntime(); Reporter reporter; JustAnotherPackageManager jpm; /** * Get the current platform manager. * * @param reporter * @param type */ public static Platform getPlatform(Reporter reporter, Type type) { if (platform == null) { if (type == null) type = getPlatformType(); switch (type) { case LINUX : platform = new Linux(); break; case MACOS : platform = new MacOS(); break; case WINDOWS : platform = new Windows(); break; default : return null; } } platform.reporter = reporter; return platform; } public static Type getPlatformType() { String osName = System.getProperty("os.name").toLowerCase(); if (osName.startsWith("windows")) return Type.WINDOWS; else if (osName.startsWith("mac") || osName.startsWith("darwin")) { return Type.MACOS; } else if (osName.contains("linux")) return Type.LINUX; return null; } /** * Return the place where we place the jpm home directory for global access. * E.g. /var/jpm * */ public abstract File getGlobal(); /** * Return the place where we place the jpm home directory for user/local * access. E.g. ~/.jpm * */ public abstract File getLocal(); abstract public void shell(String initial) throws Exception; @Override public String toString() { StringBuilder sb = new StringBuilder(); try (Formatter formatter = new Formatter(sb)) { formatter.format("Name %s%n", getName()); formatter.format("Local %s%n", getLocal()); formatter.format("Global %s%n", getGlobal()); return formatter.toString(); } } abstract public String getName(); abstract public void uninstall() throws IOException; public int run(String args) throws Exception { return runtime.exec(args).waitFor(); } public abstract String createCommand(CommandData data, Map<String,String> map, boolean force, String... deps) throws Exception; public abstract String createService(ServiceData data, Map<String,String> map, boolean force, String... deps) throws Exception; public abstract String deleteService(ServiceData data) throws Exception; public abstract int launchService(ServiceData data) throws Exception; public abstract void installDaemon(boolean user) throws Exception; public abstract void uninstallDaemon(boolean user) throws Exception; public abstract void chown(String user, boolean recursive, File file) throws Exception; public abstract String user() throws Exception; public abstract void deleteCommand(CommandData cmd) throws Exception; /** * Return the directory on this platform were normally executables are * installed. */ public abstract File getGlobalBinDir(); public File getInitd(ServiceData data) { return null; } public String defaultCacertsPassword() { return "changeme"; } protected void process(String resource, CommandData data, String path, Map<String,String> map, String... extra) throws Exception { File file = new File(path); copy(getClass().getResourceAsStream(resource), file); Sed sed = new Sed(file); sed.setBackup(false); if (data.title == null || data.title.trim().length() == 0) data.title = data.name; // // Allow commands to be done in java or javaw // sed.replace("%java%", data.windows ? "javaw" : "java"); for (Field key : data.getClass().getFields()) { Object value = key.get(data); if (value == null) { value = ""; } // We want to enclose the prolog and epilog so they are // executed as one command and thus logged as one command if ("epilog".equals(key.getName()) || "prolog".equals(key.getName())) { String s = (String) value; if (s != null && s.trim().length() > 0) { value = "(" + s + ")"; } } String v = "" + value; v = v.replace("\\", "\\\\"); sed.replace("%" + key.getName() + "%", v); } ExtList<String> deps = new ExtList<String>(); for (byte[] dependency : data.dependencies) { ArtifactData d = jpm.get(dependency); deps.add(d.file); } for (String x : extra) { deps.add(x); } String classpath = deps.join(File.pathSeparator); sed.replace("%classpath%", classpath.replace("\\", "\\\\")); if (map != null) { StringBuilder sb = new StringBuilder(); String del = "-D"; for (Map.Entry<String,String> e : map.entrySet()) { sed.replace("%" + e.getKey() + "%", e.getValue()); sb.append(del).append(e.getKey()).append("=\"").append(e.getValue()).append("\""); del = " -D"; } sed.replace("%defines%", sb.toString()); } else { sed.replace("%defines%", ""); } sed.doIt(); } protected String[] add(String[] extra, String... more) { if (extra == null || extra.length == 0) return more; if (more == null || more.length == 0) return extra; String[] result = new String[extra.length + more.length]; System.arraycopy(extra, 0, result, 0, extra.length); System.arraycopy(more, 0, result, extra.length, more.length); return result; } public abstract void report(Formatter out) throws IOException, Exception; public String installCompletion(Object target) throws Exception { return "No completion available for this platform"; } public String getConfigFile() throws Exception { return "~/.jpm/settings.json"; } public void parseCompletion(Object target, File f) throws Exception { IO.copy(getClass().getResource("unix/jpm-completion.bash"), f); Sed sed = new Sed(f); sed.setBackup(false); Reporter r = new ReporterAdapter(); CommandLine c = new CommandLine(r); Map<String,Method> commands = c.getCommands(target); StringBuilder sb = new StringBuilder(); for (String commandName : commands.keySet()) { sb.append(" " + commandName); } sb.append(" help"); sed.replace("%listJpmCommands%", sb.toString().substring(1)); sed.doIt(); } public void parseCompletion(Object target, PrintStream out) throws Exception { File tmp = File.createTempFile("jpm-completion", ".tmp"); tmp.deleteOnExit(); try { parseCompletion(target, tmp); IO.copy(tmp, out); } finally { IO.delete(tmp); } } /** * Is called to initialize the platform if necessary. * * @throws IOException * @throws Exception */ public void init() throws Exception { // can be overridden by the subclasses } public void setJpm(JustAnotherPackageManager jpm) { this.jpm = jpm; } public boolean hasPost() { return false; } public void doPostInstall() { // do nothing } abstract public void getVMs(Collection<JVM> vms) throws Exception; public String verifyVM(File f) { if (!f.isDirectory()) return "Not a directory"; File bin = new File(f, "bin"); if (!bin.isDirectory()) return "No bin directory %s for a VM's executables"; File lib = new File(f, "lib"); if (!lib.isDirectory()) return "No lib directory %s for a VM's libraries and certificates"; return null; } abstract public JVM getJVM(File f) throws Exception; }