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;
}