package aQute.jpm.platform; /** * http://support.microsoft.com/kb/814596 */ import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Formatter; import java.util.List; import java.util.Map; import org.boris.winrun4j.RegistryKey; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import aQute.bnd.osgi.Instructions; import aQute.jpm.lib.ArtifactData; import aQute.jpm.lib.CommandData; import aQute.jpm.lib.JVM; import aQute.jpm.lib.ServiceData; import aQute.lib.getopt.Arguments; import aQute.lib.getopt.Description; import aQute.lib.getopt.Options; import aQute.lib.io.IO; import aQute.lib.strings.Strings; /** * The Windows platform uses an open source library * <a href="http://winrun4j.sourceforge.net/">WinRun4j</a>. An executable is * copied to the path of the desired command. When this command is executed, it * looks up the same path, but then with the .exe replaced with .ini. This ini * file then describes what Java code to start. For JPM, we copy the base exe * (either console and/or 64 bit arch) and then create the ini file from the jpm * command data. * <p> * TODO services (fortunately, winrun4j has extensive support) */ public class Windows extends Platform { private final static Logger logger = LoggerFactory.getLogger(Windows.class); static boolean IS64 = System.getProperty("os.arch").contains("64"); static File javahome; private File misc; /** * The default global directory. */ @Override public File getGlobal() { String sysdrive = System.getenv("SYSTEMDRIVE"); if (sysdrive == null) sysdrive = "c:"; return IO.getFile(sysdrive + "\\JPM4J"); } /** * The default local directory. */ @Override public File getLocal() { return IO.getFile("~/.jpm/windows"); } /** * The default global binary dir. Though this role is played by the * c:\Windows\system directory, this is seen as a bit too ambitious. We * therefore create it a subdirectory of the global directory. */ @Override public File getGlobalBinDir() { return new File(getGlobal() + "\\bin"); } @Override public void shell(String initial) throws Exception { throw new UnsupportedOperationException(); } @Override public String getName() { return "Windows"; } /** * The uninstaller should be used */ @Override public void uninstall() throws IOException {} /** * Create a new command. Firgure out if we need the console or the window * version and the 64 or 32 bit version of the exe. Copy it, and create the * ini file. */ @Override public String createCommand(CommandData data, Map<String,String> map, boolean force, String... extra) throws Exception { // // The path to the executable // data.bin = getExecutable(data); File f = new File(data.bin); if (!force && f.exists()) return "Command already exists " + data.bin + ", try to use --force"; // // Pick console or windows (java/javaw) // if (data.windows) IO.copy(new File(getMisc(), "winrun4j.exe"), f); else IO.copy(new File(getMisc(), "winrun4jc.exe"), f); // // Make the ini file // File ini = new File(f.getAbsolutePath().replaceAll("\\.exe$", ".ini")); try (PrintWriter pw = new PrintWriter(ini)) { pw.printf("main.class=%s%n", data.main); pw.printf("log.level=error%n"); String del = "classpath.1="; // // Add all the calculated dependencies // for (byte[] dependency : data.dependencies) { ArtifactData d = jpm.get(dependency); pw.printf("%s%s", del, d.file); del = ","; } pw.printf("%n"); // // And the vm arguments. // if (data.jvmArgs != null && data.jvmArgs.length() != 0) { String parts[] = data.jvmArgs.split("\\s+"); for (int i = 0; i < parts.length; i++) pw.printf("vmarg.%d=%s%n", i + 1, parts[i]); } } logger.debug("Ini content {}", IO.collect(ini)); return null; } @Override public void deleteCommand(CommandData cmd) throws Exception { String executable = getExecutable(cmd); File f = new File(executable); File fj = new File(executable + ".ini"); if (cmd.name.equals("jpm")) { logger.debug("leaving jpm behind"); return; } else { IO.deleteWithException(f); IO.deleteWithException(fj); } } /** * Where we store our miscellaneous stuff. * */ private File getMisc() { if (misc == null) { misc = new File(jpm.getHomeDir(), "misc"); } return misc; } /** * Return the File to the exe file. * * @param data */ protected String getExecutable(CommandData data) { return new File(jpm.getBinDir(), data.name + ".exe").getAbsolutePath(); } /** * Create a new service */ @Override public String createService(ServiceData data, Map<String,String> map, boolean force, String... extra) throws Exception { // TODO Auto-generated method stub return null; } @Override public String deleteService(ServiceData data) throws Exception { // TODO Auto-generated method stub return null; } @Override public int launchService(ServiceData data) throws Exception { // TODO Auto-generated method stub return 0; } @Override public void installDaemon(boolean user) throws Exception { // TODO Auto-generated method stub } @Override public void uninstallDaemon(boolean user) throws Exception { // TODO Auto-generated method stub } @Override public void chown(String user, boolean recursive, File file) throws Exception { // TODO Auto-generated method stub } @Override public String user() throws Exception { // TODO Auto-generated method stub return null; } @Override public String toString() { try { return "Windows"; } catch (Exception e) { throw new RuntimeException(e); } } /** * Provide as much detail about the jpm environment as possible. * * @throws Exception */ public void report(Formatter f) throws Exception {} /** * Initialize the directories for windows. * * @throws Exception */ public void init() throws Exception { IO.mkdirs(getMisc()); if (IS64) { IO.copy(getClass().getResourceAsStream("windows/winrun4jc64.exe"), new File(getMisc(), "winrun4jc.exe")); IO.copy(getClass().getResourceAsStream("windows/winrun4j64.exe"), new File(getMisc(), "winrun4j.exe")); // IO.copy(getClass().getResourceAsStream("windows/sjpm64.exe"), new // File(getMisc(), "sjpm.exe")); } else { IO.copy(getClass().getResourceAsStream("windows/winrun4j.exe"), new File(getMisc(), "winrun4j.exe")); IO.copy(getClass().getResourceAsStream("windows/winrun4jc.exe"), new File(getMisc(), "winrun4jc.exe")); // IO.copy(getClass().getResourceAsStream("windows/winrun4j.exe"), // new File(getMisc(), "sjpm.exe")); } } @Override public boolean hasPost() { return true; } @Override public void doPostInstall() { System.out.println("In post install"); } /** * Add the current bindir to the environment */ @Arguments(arg = {}) @Description("Add the bin directory for this jpm to your PATH in the user's environment variables") interface PathOptions extends Options { @Description("Remove the bindir from the user's environment variables.") boolean remove(); @Description("Delete a path from the PATH environment variable") List<String> delete(); @Description("Add the current binary dir to the PATH environment variable") boolean add(); @Description("Add additional paths to the PATH environment variable") List<String> extra(); } @Description("Add the bin directory for this jpm to your PATH in the user's environment variables") public void _path(PathOptions options) { RegistryKey env = RegistryKey.HKEY_CURRENT_USER.getSubKey("Environment"); if (env == null) { reporter.error("Cannot find key for environment HKEY_CURRENT_USER/Environment"); return; } String path = env.getString("Path"); String parts[] = path == null ? new String[0] : path.split(File.pathSeparator); List<String> paths = new ArrayList<String>(Arrays.asList(parts)); boolean save = false; if (options.extra() != null) { paths.addAll(options.extra()); save = true; } for (int i = 0; i < parts.length; i++) { System.out.printf("%2d:%s %s %s%n", i, parts[i].toLowerCase().contains("jpm") ? "*" : " ", new File(parts[i]).isDirectory() ? " " : "!", parts[i]); } if (options.remove()) { if (!paths.remove(jpm.getBinDir().getAbsolutePath())) { reporter.error("Could not find %s", jpm.getBinDir()); } save = true; } if (options.delete() != null) { Instructions instr = new Instructions(options.delete()); paths = new ArrayList<String>(instr.select(paths, true)); } if (options.add()) { paths.remove(jpm.getBinDir().getAbsolutePath()); paths.add(jpm.getBinDir().getAbsolutePath()); save = true; } if (save) { String p = Strings.join(File.pathSeparator, paths); env.setString("Path", p); } } @Override public void getVMs(Collection<JVM> vms) throws Exception { // TODO Auto-generated method stub } @Override public JVM getJVM(File f) throws Exception { // TODO Auto-generated method stub return null; } }