[Esbox-commits] r945 - in branches/work_Ed: org.maemo.esbox-feature org.maemo.esbox.maemosdk.core/src/org/maemo/esbox/internal/api/maemosdk/core org.maemo.esbox.maemosdk.ui/src/org/maemo/esbox/internal/api/maemosdk/ui/preferences org.maemo.esbox.maemosdk.ui/src/org/maemo/esbox/internal/maemosdk/ui/preferences org.maemo.esbox.vm/META-INF org.maemo.esbox.vm/src/org/maemo/esbox/internal/api/vm/core org.maemo.esbox.vm/src/org/maemo/esbox/vm/core org.maemo.esbox.vm.qemu/META-INF org.maemo.esbox.vm.qemu/src/org/maemo/esbox/internal/vm/qemu org.maemo.esbox.vm.qemu/src/org/maemo/esbox/vm/qemu

eswartz at garage.maemo.org eswartz at garage.maemo.org
Mon Nov 17 23:07:21 EET 2008


Author: eswartz
Date: 2008-11-17 23:07:21 +0200 (Mon, 17 Nov 2008)
New Revision: 945

Added:
   branches/work_Ed/org.maemo.esbox.maemosdk.core/src/org/maemo/esbox/internal/api/maemosdk/core/SharedFilesystemMounter.java
   branches/work_Ed/org.maemo.esbox.vm/src/org/maemo/esbox/internal/api/vm/core/BaseCustomVirtualMachineConfiguration.java
   branches/work_Ed/org.maemo.esbox.vm/src/org/maemo/esbox/internal/api/vm/core/BaseVirtualMachineController.java
Modified:
   branches/work_Ed/org.maemo.esbox-feature/feature.xml
   branches/work_Ed/org.maemo.esbox.maemosdk.ui/src/org/maemo/esbox/internal/api/maemosdk/ui/preferences/SharedFolderTableViewer.java
   branches/work_Ed/org.maemo.esbox.maemosdk.ui/src/org/maemo/esbox/internal/api/maemosdk/ui/preferences/SharedFoldersPreferencePage.java
   branches/work_Ed/org.maemo.esbox.maemosdk.ui/src/org/maemo/esbox/internal/api/maemosdk/ui/preferences/ValidateMachineRunner.java
   branches/work_Ed/org.maemo.esbox.maemosdk.ui/src/org/maemo/esbox/internal/maemosdk/ui/preferences/BuildMachinePreferencePage.java
   branches/work_Ed/org.maemo.esbox.vm.qemu/META-INF/MANIFEST.MF
   branches/work_Ed/org.maemo.esbox.vm.qemu/src/org/maemo/esbox/internal/vm/qemu/CustomQemuConfiguration.java
   branches/work_Ed/org.maemo.esbox.vm.qemu/src/org/maemo/esbox/internal/vm/qemu/QemuBuildMachineFactory.java
   branches/work_Ed/org.maemo.esbox.vm.qemu/src/org/maemo/esbox/internal/vm/qemu/QemuMachine.java
   branches/work_Ed/org.maemo.esbox.vm.qemu/src/org/maemo/esbox/internal/vm/qemu/QemuMachineController.java
   branches/work_Ed/org.maemo.esbox.vm.qemu/src/org/maemo/esbox/vm/qemu/IQemuConfiguration.java
   branches/work_Ed/org.maemo.esbox.vm/META-INF/MANIFEST.MF
   branches/work_Ed/org.maemo.esbox.vm/src/org/maemo/esbox/vm/core/IVirtualMachineConfiguration.java
Log:
Support VMware and QEMU together, factoring out common code and fixing bugs with shared prefs, and trying to be a little more user-friendly in machine validation.

Modified: branches/work_Ed/org.maemo.esbox-feature/feature.xml
===================================================================
--- branches/work_Ed/org.maemo.esbox-feature/feature.xml	2008-11-17 21:07:20 UTC (rev 944)
+++ branches/work_Ed/org.maemo.esbox-feature/feature.xml	2008-11-17 21:07:21 UTC (rev 945)
@@ -1,76 +1,83 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<feature
-      id="org.maemo.esbox"
-      label="ESbox Feature"
-      version="2.0.0.qualifier"
-      provider-name="INdT / NOKIA">
-
-   <description>
-      ESbox feature, containing all the ESbox-specific plugins.
-   </description>
-
-   <copyright>
+<?xml version="1.0" encoding="UTF-8"?>
+<feature
+      id="org.maemo.esbox"
+      label="ESbox Feature"
+      version="2.0.0.qualifier"
+      provider-name="INdT / NOKIA">
+
+   <description>
+      ESbox feature, containing all the ESbox-specific plugins.
+   </description>
+
+   <copyright>
       Copyright (c) 2007-2008 INdT, (c) 2007-2008 Nokia. All rights
-reserved.
-   </copyright>
-
-   <license url="http://www.eclipse.org/legal/epl-v10.html">
-      For legal terms, see the Eclipse Public License.
-   </license>
-
-   <url>
-      <update label="Update site for ESbox project" url="http://esbox.garage.maemo.org/update"/>
-   </url>
-
-   <requires>
-      <import plugin="org.eclipse.core.runtime"/>
-      <import plugin="org.maemo.mica.common.core" version="2.0.0" match="greaterOrEqual"/>
-      <import plugin="org.maemo.mica.maemosdk.core" version="2.0.0" match="greaterOrEqual"/>
-      <import plugin="org.maemo.mica.common.analysis" version="2.0.0" match="greaterOrEqual"/>
-      <import plugin="org.maemo.esbox.scratchbox.core" version="2.0.0" match="greaterOrEqual"/>
-      <import plugin="com.nokia.carbide.templatewizard" version="2.1.0" match="greaterOrEqual"/>
-      <import plugin="org.eclipse.ui"/>
-   </requires>
-
-   <plugin
-         id="org.maemo.esbox.analysis"
-         download-size="0"
-         install-size="0"
-         version="0.0.0"
-         unpack="false"/>
-
-   <plugin
-         id="org.maemo.esbox.help"
-         download-size="0"
-         install-size="0"
-         version="0.0.0"/>
-
-   <plugin
-         id="org.maemo.esbox.maemosdk.core"
-         download-size="0"
-         install-size="0"
-         version="0.0.0"
-         unpack="false"/>
-
-   <plugin
-         id="org.maemo.esbox.maemosdk.ui"
-         download-size="0"
-         install-size="0"
-         version="0.0.0"
-         unpack="false"/>
-
-   <plugin
-         id="org.maemo.esbox.vm.qemu"
-         download-size="0"
-         install-size="0"
-         version="0.0.0"
-         unpack="false"/>
-
-   <plugin
-         id="org.maemo.esbox.vm"
-         download-size="0"
-         install-size="0"
-         version="0.0.0"
-         unpack="false"/>
-
-</feature>
+reserved.
+   </copyright>
+
+   <license url="http://www.eclipse.org/legal/epl-v10.html">
+      For legal terms, see the Eclipse Public License.
+   </license>
+
+   <url>
+      <update label="Update site for ESbox project" url="http://esbox.garage.maemo.org/update"/>
+   </url>
+
+   <requires>
+      <import plugin="org.eclipse.core.runtime"/>
+      <import plugin="org.maemo.mica.common.core" version="2.0.0" match="greaterOrEqual"/>
+      <import plugin="org.maemo.mica.maemosdk.core" version="2.0.0" match="greaterOrEqual"/>
+      <import plugin="org.maemo.mica.common.analysis" version="2.0.0" match="greaterOrEqual"/>
+      <import plugin="org.maemo.esbox.scratchbox.core" version="2.0.0" match="greaterOrEqual"/>
+      <import plugin="com.nokia.carbide.templatewizard" version="2.1.0" match="greaterOrEqual"/>
+      <import plugin="org.eclipse.ui"/>
+   </requires>
+
+   <plugin
+         id="org.maemo.esbox.analysis"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="org.maemo.esbox.help"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"/>
+
+   <plugin
+         id="org.maemo.esbox.maemosdk.core"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="org.maemo.esbox.maemosdk.ui"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="org.maemo.esbox.vm.qemu"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="org.maemo.esbox.vm"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="org.maemo.esbox.vm.vmware"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+</feature>

Added: branches/work_Ed/org.maemo.esbox.maemosdk.core/src/org/maemo/esbox/internal/api/maemosdk/core/SharedFilesystemMounter.java
===================================================================
--- branches/work_Ed/org.maemo.esbox.maemosdk.core/src/org/maemo/esbox/internal/api/maemosdk/core/SharedFilesystemMounter.java	                        (rev 0)
+++ branches/work_Ed/org.maemo.esbox.maemosdk.core/src/org/maemo/esbox/internal/api/maemosdk/core/SharedFilesystemMounter.java	2008-11-17 21:07:21 UTC (rev 945)
@@ -0,0 +1,256 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Nokia Corporation
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Ed Swartz (Nokia) - initial API and implementation
+ *******************************************************************************/
+
+package org.maemo.esbox.internal.api.maemosdk.core;
+
+import org.eclipse.core.filesystem.IFileStore;
+import org.eclipse.core.runtime.*;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.maemo.esbox.internal.maemosdk.core.Activator;
+import org.maemo.mica.common.core.*;
+import org.maemo.mica.common.core.machine.*;
+import org.maemo.mica.common.core.process.*;
+import org.maemo.mica.common.core.process.ProcessLauncherUtils.Results;
+import org.maemo.mica.common.ui.dialogs.DialogUtils;
+import org.maemo.mica.common.ui.dialogs.PasswordInputDialog;
+import org.maemo.mica.internal.api.common.core.machine.IMountVisitor;
+import org.maemo.mica.internal.api.common.core.machine.MountWalker;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.text.MessageFormat;
+import java.util.List;
+
+/**
+ * This class handles mounting shared folders.
+ * <p>
+ * XXX: This is a temporary factoring-out of code to blindly run a script and assume it mounts what we expect. 
+ * @author eswartz
+ *
+ */
+public class SharedFilesystemMounter {
+	
+	/**
+	 * This method is called on the UI thread.  It should validate that
+	 * the shared filesystems are available, prompting the user for a password
+	 * and launching 'mount_share.sh' to mount them otherwise.
+	 * <p>
+	 * XXX: this must be rewritten at some point to handle shares which aren't handled by mount_share.sh!
+	 * @param subProgressMonitor 
+	 * @return Status of mount
+	 */
+	public static IStatus validateSharedMounts(IMachine machine, IProgressMonitor monitor) {
+
+		ISharedFilesystemProvider sharedFilesystemProvider = 
+			machine.getSharedFilesystemProvider();
+		if (sharedFilesystemProvider == null)
+			return Status.OK_STATUS;
+		
+		List<ISharedFolder> sharedFolders = sharedFilesystemProvider.getSharedFolders();
+		
+		monitor.beginTask("Validating shared folders", sharedFolders.size() * 2);
+		
+		boolean neededMount = false;
+		
+		String fsTypePattern = "smbfs|cifs";
+		for (ISharedFolder share : sharedFolders) {
+			if (!isPathMounted(machine, share.getRemotePath(), fsTypePattern, null)) {
+				neededMount = true;
+				PasswordInputDialog dialog = new PasswordInputDialog(
+						DialogUtils.getShell(), 
+						"Password Required",
+						MessageFormat.format(
+								"Enter the password for user ''{0}'' to mount the share ''{1}'':",
+								MachineRegistry.getInstance().getLocalMachine().getUserName(),
+								share.getLocalPath()));
+				if (IDialogConstants.CANCEL_ID == dialog.open())
+					continue;
+				
+				// TODO: this assumes a certain script exists on the VM
+				try {
+					mountSharesWithPassword(machine, dialog.getPassword());
+				} catch (MicaException e) {
+					return Activator.createErrorStatus(
+							MessageFormat.format(
+									"Could not mount ''{0}'' in {1}",
+									share.getLocalPath().toString(),
+									machine.getName()), e);
+				}
+				
+				monitor.worked(1);
+				if (monitor.isCanceled())
+					return Policy.getCancelStatus(Activator.getDefault());
+			}
+		}
+		
+		// verify that the mounting succeeded
+		boolean allSharesMounted = true;
+		if (neededMount) {
+			for (ISharedFolder share : sharedFolders) {
+				if (!isPathMounted(machine, share.getRemotePath(), fsTypePattern, null)) {
+					allSharesMounted = false;
+				}
+				monitor.worked(1);
+				if (monitor.isCanceled())
+					return Policy.getCancelStatus(Activator.getDefault());
+			}
+		}
+		
+		monitor.done();
+		
+		if (!allSharesMounted) {
+			return Activator.createStatus(IStatus.WARNING, 
+					MessageFormat.format(
+							"Not all the known shares were mounted in {0}; builds may fail",
+							machine.getName()));
+		}
+
+		return Status.OK_STATUS;
+	}
+	
+	/**
+	 * Run the 'mount_share.sh' script to mount shares.
+	 * @param password
+	 */
+	protected static void mountSharesWithPassword(IMachine machine, final String password) throws MicaException {
+		IProcessLauncherFactory processLauncherFactory = machine.getProcessLauncherFactory();
+		final IProcessLauncher processLauncher = ProcessLauncherCreator.createProcessLauncher(processLauncherFactory,
+				machine.getUserHome(),
+				CommandLineArguments.createFromVarArgs(
+						"sh",
+						"mount_share.sh"));
+		
+		processLauncher.usePTY(true);
+		//final Process process = processLauncher.createProcess();
+		final MicaException[] exceptions = { null };
+		
+		Thread thread = new Thread("Send password to mount") {
+
+			/* (non-Javadoc)
+			 * @see java.lang.Thread#run()
+			 */
+			@Override
+			public void run() {
+				//try {
+					/* this goes to a weird stream (somehow) so we can't read it,
+					 even though it shows up when we put stuff to the Console!
+					InputStream is = process.getInputStream();
+					int ch;
+					// read "Password:"
+					while ((ch = is.read()) != -1) {
+						if (ch == ':') {
+							break;
+						}
+					}
+					*/
+					
+					try {
+						Results results = ProcessLauncherUtils.launchAndReadStandardStreamsWithInput(processLauncher, 
+								new ByteArrayInputStream((password + "\n").getBytes()),
+								null);
+						String stdout = results.stdout.trim();
+						String stderr = results.stderr.replaceAll("Password:", "").trim();
+						if (results.exitCode != 0 || stdout.length() + stderr.length() > 0) {
+							exceptions[0] = new MicaException("Mounting script did not succeed:\n\n"
+									+ stdout + "\n" + stderr);
+						}
+					} catch (MicaException e) {
+						exceptions[0] = e;
+					}
+					System.out.println(exceptions[0]);
+					
+					/* this process adds noise to the console window without much use
+					// send password
+					OutputStream os = process.getOutputStream();
+					os.write((password + "\n").getBytes());
+					os.close();
+
+					// now let the remaining output go to the Console
+					processLauncher.redirectToConsole(false, null, "Mounting shares");
+					try {
+						int exit = process.waitFor();
+						if (exit != 0) {
+							exceptions[0] = new MicaException("Mounting script did not succeed; check Console for errors");
+							return;
+						}
+					} catch (InterruptedException e) {
+					}
+					
+				} catch (IOException e) {
+					exceptions[0] = new MicaException("Failed to send password", e);
+					return;
+				}
+				*/
+			}
+		};
+		thread.start();
+		
+		boolean timedOut = !JobUtils.waitForThread(thread, 10000, null);
+
+		//process.destroy();
+		
+		MicaException result = exceptions[0];
+		if (thread.isAlive())
+			thread.interrupt();
+		
+		if (result != null) {
+			throw result;
+		}
+		if (timedOut) {
+			throw new MicaException("Timeout sending password");
+		}
+	}
+
+	/**
+	 * Tell whether the given path is mounted on the machine.
+	 * @param value the path to check
+	 * @param fsTypePattern if not null, the regex of fsTypes that should match
+	 * @param devicePattern if not null, the regex of devices that should match 
+	 * @return true: an entry in /proc/mounts matches, else false
+	 */
+	public static boolean isPathMounted(IMachine machine, IPath value, final String fsTypePattern, final String devicePattern) {
+		IFileStore store = machine.getFileSystemAccess().getFileStore(new Path("/proc/mounts"));
+		InputStream is = null;
+		try {
+			MountWalker walker = new MountWalker();
+			final boolean[] found = { false };
+			final String path = value.toPortableString();
+			is = store.openInputStream(0, null);
+			walker.accept(is, new IMountVisitor() {
+	
+				public boolean handleMount(String device, String point,
+						String fsType, String options) {
+					if (point.equals(path)) {
+						// XXX hack until we distinguish WHERE shares are mounted to/from
+						if (point.equals("/scratchbox")) {
+							found[0] = true;
+							return true;
+						}
+						
+						if ((devicePattern == null || device.matches(devicePattern)) &&
+								(fsTypePattern == null || fsType.matches(fsTypePattern))) {
+							found[0] = true;
+							return false;
+						}
+					}
+					return true;
+				}
+				
+			});
+			return found[0];
+		} catch (CoreException e) {
+			Activator.getErrorLogger().logError("Cannot parse mounts", e);
+			return false;
+		} finally {
+			Policy.close(is);
+		}
+	}
+}

Modified: branches/work_Ed/org.maemo.esbox.maemosdk.ui/src/org/maemo/esbox/internal/api/maemosdk/ui/preferences/SharedFolderTableViewer.java
===================================================================
--- branches/work_Ed/org.maemo.esbox.maemosdk.ui/src/org/maemo/esbox/internal/api/maemosdk/ui/preferences/SharedFolderTableViewer.java	2008-11-17 21:07:20 UTC (rev 944)
+++ branches/work_Ed/org.maemo.esbox.maemosdk.ui/src/org/maemo/esbox/internal/api/maemosdk/ui/preferences/SharedFolderTableViewer.java	2008-11-17 21:07:21 UTC (rev 945)
@@ -147,6 +147,7 @@
 
 			@Override
 			protected CellEditor getCellEditor(Object element) {
+				// do NOT automatically proceed to the next cell -- boolean cells CHANGE when you enter them
 				return new TextCellEditor(getTable());
 			}
 

Modified: branches/work_Ed/org.maemo.esbox.maemosdk.ui/src/org/maemo/esbox/internal/api/maemosdk/ui/preferences/SharedFoldersPreferencePage.java
===================================================================
--- branches/work_Ed/org.maemo.esbox.maemosdk.ui/src/org/maemo/esbox/internal/api/maemosdk/ui/preferences/SharedFoldersPreferencePage.java	2008-11-17 21:07:20 UTC (rev 944)
+++ branches/work_Ed/org.maemo.esbox.maemosdk.ui/src/org/maemo/esbox/internal/api/maemosdk/ui/preferences/SharedFoldersPreferencePage.java	2008-11-17 21:07:21 UTC (rev 945)
@@ -80,7 +80,9 @@
 	protected void loadModel(boolean isDefault) {
 		String info = getStoredPreference(isDefault);
 		model = preferenceConverter.convertPreferenceToModel(info);
-		tableViewer.setInput(model);
+		if (tableViewer != null) {
+			tableViewer.setInput(model);
+		}
 	}
 
 	/**

Modified: branches/work_Ed/org.maemo.esbox.maemosdk.ui/src/org/maemo/esbox/internal/api/maemosdk/ui/preferences/ValidateMachineRunner.java
===================================================================
--- branches/work_Ed/org.maemo.esbox.maemosdk.ui/src/org/maemo/esbox/internal/api/maemosdk/ui/preferences/ValidateMachineRunner.java	2008-11-17 21:07:20 UTC (rev 944)
+++ branches/work_Ed/org.maemo.esbox.maemosdk.ui/src/org/maemo/esbox/internal/api/maemosdk/ui/preferences/ValidateMachineRunner.java	2008-11-17 21:07:21 UTC (rev 945)
@@ -121,11 +121,11 @@
 		final IStatus[] statuses = { null };
 		ProgressMonitorDialog dialog = new ProgressMonitorDialog(null);
 		try {
-			dialog.run(true, true, new IRunnableWithProgress() {
+			dialog.run(false, true, new IRunnableWithProgress() {
 
 				public void run(IProgressMonitor monitor)
 						throws InvocationTargetException, InterruptedException {
-					statuses[0] = MachineManager.getInstance().acquireMachine(machine, null);
+					statuses[0] = MachineManager.getInstance().acquireMachine(machine, monitor);
 				}
 				
 			});
@@ -140,6 +140,9 @@
 				fail("Failed to launch or revive the virtual build machine:\n\n{0}", status.getMessage());
 				return false;
 			}
+			if (status.getSeverity() == IStatus.CANCEL) {
+				return false;
+			}
 			fail("The virtual build machine is not well, going to continue anyway...:\n\n{0}", status.getMessage());
 		}
 		return true;
@@ -159,7 +162,7 @@
 		try {
 			process = processLauncher.createProcess();
 		} catch (MicaException e) {
-			fail("Could not run 'ls' on " + machine.getUserHome() + " directory.\nIf SSH connections to machine are failing, ensure the \nrun_linux_wait.bat script (in the plugin) has not been modified\nand that the virtual machine has booted properly:\n{0}", 
+			fail("Could not run 'ls' on " + machine.getUserHome() + " directory.\nIf SSH connections to machine are failing, ensure the \nthat the virtual machine has booted properly and is running an SSH daemon:\n{0}", 
 					e);
 			return false;
 		}
@@ -209,6 +212,10 @@
 		monitor.beginTask("Checking shared folders", sharedFolders.size());
 		
 		boolean succeeded = true;
+		if (sharedFolders.size() == 0) {
+			warn("No shared folders are defined or available\nfor this machine... typically this won't work very well.");
+			succeeded = false;
+		}
 		for (ISharedFolder share : sharedFolders) {
 			succeeded &= testSharedFolder(new SubProgressMonitor(monitor, 1), share);
 		}

Modified: branches/work_Ed/org.maemo.esbox.maemosdk.ui/src/org/maemo/esbox/internal/maemosdk/ui/preferences/BuildMachinePreferencePage.java
===================================================================
--- branches/work_Ed/org.maemo.esbox.maemosdk.ui/src/org/maemo/esbox/internal/maemosdk/ui/preferences/BuildMachinePreferencePage.java	2008-11-17 21:07:20 UTC (rev 944)
+++ branches/work_Ed/org.maemo.esbox.maemosdk.ui/src/org/maemo/esbox/internal/maemosdk/ui/preferences/BuildMachinePreferencePage.java	2008-11-17 21:07:21 UTC (rev 945)
@@ -57,6 +57,7 @@
 	 */
 	public BuildMachinePreferencePage() {
 		setupMachineInfo();
+		originalSelectedMachine = selectedMachine;
 	}
 	
 	/**
@@ -99,7 +100,7 @@
 		// autoselect the in-use machine if possible
 		IBuildMachine[] currentBuildMachines = MachineRegistry.getInstance().getCurrentBuildMachines();
 		for (IBuildMachine machine : currentBuildMachines) {
-			originalSelectedMachine = selectedMachine = (IBuildMachine) machine;
+			selectedMachine = (IBuildMachine) machine;
 			break;
 		}
 		
@@ -271,14 +272,12 @@
 	@Override
 	protected void performApply() {
 		boolean changed = false;
-		for (IComposablePreferencePage page : machineConfigPages.values()) {
-			if (page != null) {
-				changed |= page.anyChanges();
-				page.performApply();
-			}
+		IComposablePreferencePage page = machineConfigPages.get(selectedMachine.getName());
+		if (page != null) {
+			changed |= page.anyChanges();
+			page.performApply();
 		}
 		
-		
 		if (changed) {
 			// reset the build machines, since they were initialized from other prefs
 			MachineRegistry.getInstance().refreshBuildMachines();
@@ -287,8 +286,10 @@
 		// these objects refer to the old values, so we compare them to detect a change,
 		// but a change in prefs also requires a new machine instance
 		if (changed || originalSelectedMachine != selectedMachine) {
+			IBuildMachine newMachine = selectedMachine;
 			setupMachineInfo();
-			MachineRegistry.getInstance().setCurrentBuildMachine(selectedMachine.getName());
+			newMachine = MachineRegistry.getInstance().setCurrentBuildMachine(newMachine.getName());
+			originalSelectedMachine = selectedMachine = newMachine;
 		}
 		
 	}

Modified: branches/work_Ed/org.maemo.esbox.vm/META-INF/MANIFEST.MF
===================================================================
--- branches/work_Ed/org.maemo.esbox.vm/META-INF/MANIFEST.MF	2008-11-17 21:07:20 UTC (rev 944)
+++ branches/work_Ed/org.maemo.esbox.vm/META-INF/MANIFEST.MF	2008-11-17 21:07:21 UTC (rev 945)
@@ -13,7 +13,8 @@
  org.maemo.esbox.scratchbox.core;bundle-version="2.0.0",
  org.maemo.mica.maemosdk.core;bundle-version="2.0.0",
  org.eclipse.ui.ide;bundle-version="3.4.1",
- org.maemo.esbox.maemosdk.ui;bundle-version="2.0.0"
+ org.maemo.esbox.maemosdk.ui;bundle-version="2.0.0",
+ org.maemo.esbox.maemosdk.core;bundle-version="2.0.0"
 Bundle-RequiredExecutionEnvironment: J2SE-1.5
 Bundle-ActivationPolicy: lazy
 Export-Package: org.maemo.esbox.internal.api.vm.core,

Added: branches/work_Ed/org.maemo.esbox.vm/src/org/maemo/esbox/internal/api/vm/core/BaseCustomVirtualMachineConfiguration.java
===================================================================
--- branches/work_Ed/org.maemo.esbox.vm/src/org/maemo/esbox/internal/api/vm/core/BaseCustomVirtualMachineConfiguration.java	                        (rev 0)
+++ branches/work_Ed/org.maemo.esbox.vm/src/org/maemo/esbox/internal/api/vm/core/BaseCustomVirtualMachineConfiguration.java	2008-11-17 21:07:21 UTC (rev 945)
@@ -0,0 +1,138 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Nokia Corporation
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Ed Swartz (Nokia) - initial API and implementation
+ *******************************************************************************/
+package org.maemo.esbox.internal.api.vm.core;
+
+import org.maemo.esbox.internal.vm.Activator;
+import org.maemo.esbox.vm.core.IVirtualMachineConfiguration;
+import org.maemo.mica.common.core.MicaException;
+import org.maemo.mica.common.core.machine.ISharedFilesystemProvider;
+import org.maemo.mica.protocol.ssh.SSHConfiguration;
+
+import java.net.URI;
+
+/**
+ * This configuration sets up the common settings specified at construction time 
+ * through the URI syntax (IMachineFactory)
+ * @author eswartz
+ *
+ */
+public abstract class BaseCustomVirtualMachineConfiguration implements IVirtualMachineConfiguration {
+	
+	private static final String HOST_ADDRESS = "hostAddress";
+	private static final String HOST_PORT = "hostPort";
+	private static final String TIMEOUT = "timeout";
+	private static final String CIFS_PORT = "cifsPort";
+	private static final String COMMAND_LAUNCH_PATTERN = "commandLaunchPattern";
+	private static final String EXECUTABLE = "executable";
+	
+	protected SSHConfiguration sshConfiguration;
+	protected String executable;
+	protected String commandLaunchPattern;
+	protected ISharedFilesystemProvider sharedFilesystemProvider;
+	protected int cifsPort;
+
+	public BaseCustomVirtualMachineConfiguration(URI uri, ISharedFilesystemProvider sharedFilesystemProvider) throws MicaException {
+		this.sshConfiguration = new SSHConfiguration(uri);
+		this.sharedFilesystemProvider = sharedFilesystemProvider;
+
+		setupDefaults();
+		
+		String query = uri.getQuery();
+		String[] queryParts = query.split("&");
+		for (String queryPart : queryParts) {
+			int equIdx = queryPart.indexOf("=");
+			if (equIdx < 0)
+				throw new MicaException("Invalid query component: " + queryPart);
+			
+			String key = queryPart.substring(0, equIdx);
+			String value = queryPart.substring(equIdx + 1);
+
+			try {
+				if (decodeQueryPart(key, value)) {
+					continue;
+				} else {
+					Activator.getErrorLogger().logError("Ignoring unknown query component: " + queryPart, null);
+				}
+			} catch (NumberFormatException e) {
+				throw new MicaException("Invalid integer in query component: " + queryPart);
+			}
+		}
+	}
+	
+	/**
+	 * Decode a portion of the query URI.  
+	 * @param key
+	 * @param value
+	 * @return true if handled, false if not
+	 */
+	protected boolean decodeQueryPart(String key, String value) {
+		if (key.equals(HOST_ADDRESS)) {
+			sshConfiguration.setHostIPAddress(value);
+		} else if (key.equals(HOST_PORT)) {
+			sshConfiguration.setHostPort(Integer.parseInt(value));
+		} else if (key.equals(TIMEOUT)) {
+			sshConfiguration.setConnectionTimeout(Integer.parseInt(value));
+		} else if (key.equals(CIFS_PORT)) {
+			this.cifsPort = Integer.parseInt(value);
+		} else if (key.equals(COMMAND_LAUNCH_PATTERN)) {
+			this.commandLaunchPattern = value;
+		} else if (key.equals(EXECUTABLE)) {
+			this.executable = value;
+		} else {
+			return false;
+		}
+		return true;
+	}
+
+	/**
+	 * 
+	 */
+	protected void setupDefaults() {
+		this.sshConfiguration.setConnectionTimeout(1);
+		this.executable = null;
+		this.commandLaunchPattern = null; 
+		this.cifsPort = 445;
+		
+	}
+
+	/* (non-Javadoc)
+	 * @see org.maemo.esbox.vm.core.IVirtualMachineConfiguration#getSSHConfiguration()
+	 */
+	public SSHConfiguration getSSHConfiguration() {
+		return sshConfiguration;
+	}
+	
+	/* (non-Javadoc)
+	 * @see org.maemo.esbox.vm.core.IVirtualMachineConfiguration#getSharedFilesystemProvider()
+	 */
+	public ISharedFilesystemProvider getSharedFilesystemProvider() {
+		return sharedFilesystemProvider;
+	}
+	
+	/* (non-Javadoc)
+	 * @see org.maemo.esbox.vm.core.IVirtualMachineConfiguration#getCIFSPort()
+	 */
+	public int getCIFSPort() {
+		return cifsPort;
+	}
+	
+	public String getExecutable() {
+		return executable; 
+	}
+	
+	/* (non-Javadoc)
+	 * @see org.maemo.esbox.vm.qemu.IQemuConfiguration#getCommandLaunchPattern()
+	 */
+	public String getCommandLaunchPattern() {
+		return commandLaunchPattern; 
+	}
+
+}

Added: branches/work_Ed/org.maemo.esbox.vm/src/org/maemo/esbox/internal/api/vm/core/BaseVirtualMachineController.java
===================================================================
--- branches/work_Ed/org.maemo.esbox.vm/src/org/maemo/esbox/internal/api/vm/core/BaseVirtualMachineController.java	                        (rev 0)
+++ branches/work_Ed/org.maemo.esbox.vm/src/org/maemo/esbox/internal/api/vm/core/BaseVirtualMachineController.java	2008-11-17 21:07:21 UTC (rev 945)
@@ -0,0 +1,494 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Nokia Corporation
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Ed Swartz (Nokia) - initial API and implementation
+ *******************************************************************************/
+package org.maemo.esbox.internal.api.vm.core;
+
+
+import com.nokia.cpp.internal.api.utils.ui.WorkbenchUtils;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.maemo.esbox.internal.api.maemosdk.core.SharedFilesystemMounter;
+import org.maemo.esbox.internal.vm.Activator;
+import org.maemo.esbox.vm.core.IVirtualMachineConfiguration;
+import org.maemo.mica.common.core.*;
+import org.maemo.mica.common.core.machine.*;
+import org.maemo.mica.common.core.process.*;
+import org.maemo.mica.common.core.process.ProcessLauncherUtils.Results;
+import org.maemo.mica.internal.api.protocol.ssh.SSHMachineControllerBase;
+import org.maemo.mica.protocol.ssh.SSHConfiguration;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.net.Socket;
+import java.text.MessageFormat;
+import java.util.List;
+
+/**
+ * This is the basic implementation of a virtual machine launched via executable
+ * @author eswartz
+ *
+ */
+public abstract class BaseVirtualMachineController extends SSHMachineControllerBase {
+
+	private static final IStatus CANCEL_STATUS = Policy.getCancelStatus(Activator.getDefault());
+	
+	/** thread and process are non-null if we launched Machine ourselves */
+	Process launchedMachineProcess;
+	/** thread and process are non-null if we launched Machine ourselves */
+	MachineWatcherThread launchedMachineThread;
+	
+	protected IVirtualMachineConfiguration machineConfiguration;
+	protected boolean isValidating;
+	
+	class MachineWatcherThread extends Thread {
+		private IProcessLauncher launcher;
+		private ProcessLauncherUtils.Results results;
+		
+		public MachineWatcherThread(IProcessLauncher launcher) {
+			this.launcher = launcher;
+			setDaemon(true);
+		}
+		public void run() {
+			// TODO: make this go to the console
+			
+			// wait for it
+			ByteArrayOutputStream out = new ByteArrayOutputStream();
+			ByteArrayOutputStream err = new ByteArrayOutputStream();
+			
+			int exit = launcher.waitAndRead(out, err, new NullProgressMonitor());
+			
+			results = new Results(exit, out.toString(), err.toString());
+		}
+		
+		/**
+		 * @return the results
+		 */
+		public ProcessLauncherUtils.Results getResults() {
+			return results;
+		}
+	}
+	
+	public BaseVirtualMachineController(String name, IVirtualMachineConfiguration configuration) {
+		super(name);
+		this.machineConfiguration = configuration;
+	}
+	
+	/* (non-Javadoc)
+	 * @see org.maemo.mica.internal.api.protocol.ssh.SSHMachineControllerBase#getConfiguration()
+	 */
+	@Override
+	protected SSHConfiguration getConfiguration() {
+		return machineConfiguration.getSSHConfiguration(); 
+	}
+	
+	/**
+	 * @param processLauncher
+	 * @return
+	 */
+	protected MachineException processOutput(String message, MachineWatcherThread thread) {
+		return new MachineException(
+				MessageFormat.format("{0}\n\nCommand line: {1}\n\nstdout:\n{2}\nstderr:\n{3}",
+					message, 
+					CommandLineArguments.toCommandLine(thread.launcher.getLaunchCommandArguments()),
+					thread.getResults().stdout,
+					thread.getResults().stderr));
+	}
+
+	@Override
+	protected IStatus doStartMachine(IProgressMonitor monitor) throws MachineException {
+		// ensure we check again ASAP
+		scheduleProbe();
+		
+		try {
+			return doStartMachineImpl(monitor);
+		} finally {
+			// and check again whether we think it succeeded or not
+			scheduleProbe();
+		}
+	}
+
+	/**
+	 * @param monitor
+	 * @return
+	 * @throws MachineException
+	 */
+	private IStatus doStartMachineImpl(IProgressMonitor monitor)
+			throws MachineException {
+		final int PROBE_COUNT = 10;
+		
+		monitor.beginTask("Starting " + getName(), IProgressMonitor.UNKNOWN);
+		
+		// we're here due to an error state
+		if (launchedMachineProcess != null) {
+			// kill the running one since there's no way to fix it
+			
+			launchedMachineProcess.destroy();
+			launchedMachineProcess = null;
+			fireMachineStateChanged();
+			monitor.worked(1);
+			if (monitor.isCanceled())
+				return CANCEL_STATUS;
+		}
+		
+		monitor.setTaskName("Launching " + getName() + " and waiting for startup...");
+		
+		ProcessLauncherParameters parameters = constructLaunchParameters();
+		List<String> cmdLine = parameters.getCommandLine();
+		
+		String commandString = CommandLineArguments.toCommandLine(cmdLine);
+		System.out.println(commandString);
+		
+		IProcessLauncherFactory processLauncherFactory = new HostProcessLauncherFactory();
+		final IProcessLauncher processLauncher = ProcessLauncherCreator.createProcessLauncher(
+				processLauncherFactory, parameters);
+		try {
+			launchedMachineProcess = processLauncher.createProcess();
+		} catch (MicaException e) {
+			throw new MachineException("Cannot launch " + getName() + ": " + CommandLineArguments.toCommandLine(cmdLine), e);
+		}
+		
+		launchedMachineThread = new MachineWatcherThread(processLauncher);
+		launchedMachineThread.start();
+		
+		long timeout = System.currentTimeMillis() + 300 * 1000;
+		while (true) {
+			if (!launchedMachineThread.isAlive()) {
+				throw processOutput("Machine launch failed", launchedMachineThread);
+				/*
+				} else {
+					// The process died successfully... this might happen when the VM executable
+					// determines it's already running.  Continue below to check the connection.
+					scheduleProbe();
+					IStatus status = doProbeMachine(new SubProgressMonitor(monitor, 1));
+					return status;
+				}*/
+			} else {
+				try {
+					launchedMachineProcess.exitValue();
+					try {
+						launchedMachineThread.join();
+					} catch (InterruptedException e) {
+					}
+					throw processOutput("Machine died", launchedMachineThread);
+				} catch (IllegalThreadStateException e) {
+					// still running
+				}
+			}
+			
+			for (int cnt = 0; cnt < PROBE_COUNT; cnt++) {
+				monitor.worked(1);
+				if (monitor.isCanceled())
+					return CANCEL_STATUS;
+
+				try {
+					Thread.sleep(100);
+				} catch (InterruptedException e) {
+					doStopMachine(monitor);
+					return CANCEL_STATUS;
+				}
+				
+				Display display = Display.getCurrent();
+				if (display != null) {
+					while (display.readAndDispatch()) ;
+				}
+			}
+			
+			// test the connection
+			scheduleProbe();
+			IStatus status = doProbeMachine(new SubProgressMonitor(monitor, 1));
+			if (status.isOK()) {
+				// XXX: do this more intelligently
+				// sshd starts a few moments before /etc/rc.local is run, 
+				// so kernel parameters like vdso might not be configured yet... 
+				// wait a few seconds more to avoid immediately invoking
+				// scratchbox commands and failing.
+				for (int cnt = 0; cnt < 50; cnt++) {
+					Display display = Display.getCurrent();
+					if (display != null) {
+						while (display.readAndDispatch()) ;
+					}
+					
+					monitor.worked(1);
+					if (monitor.isCanceled())
+						throw cancelled();
+
+					try {
+						Thread.sleep(100);
+					} catch (InterruptedException e) {
+						throw cancelled();
+					}
+				}
+				break;
+			}
+			
+			if (System.currentTimeMillis() >= timeout) {
+				throw processOutput("Timed out waiting for " + getName() + " startup", launchedMachineThread);
+			}
+		}
+		
+		fireMachineStateChanged();
+		
+		return Status.OK_STATUS;
+	}
+	
+	/**
+	 * Create the laumch parameters from the configuration.
+	 * @return new {@link ProcessLauncherParameters}
+	 */
+	abstract protected ProcessLauncherParameters constructLaunchParameters();
+
+	protected MachineException cancelled() {
+		return new MachineException(null, new CoreException(CANCEL_STATUS));
+	}
+
+	@Override
+	protected IStatus doStopMachine(IProgressMonitor monitor) throws MachineException {
+		IStatus status = super.doStopMachine(monitor);
+		if (!status.isOK())
+			return status;
+		
+		// only try halting if we created it
+		if (launchedMachineThread != null && launchedMachineThread.isAlive()) {
+			// make it halt
+			List<String> cmdLine = CommandLineArguments.createFromCommandLine(
+				"sudo -S halt now");
+			
+			IProcessLauncherFactory processLauncherFactory = getProcessLauncherFactory();
+			Process process;
+			try {
+				process = ProcessLauncherCreator.createProcessLauncher(processLauncherFactory,
+						null, cmdLine).createProcess();
+				try {
+					// send the password for sudo
+					process.getOutputStream().write(machineConfiguration.getSSHConfiguration().getUserPassword().getBytes());
+					process.getOutputStream().write('\n');
+					process.getOutputStream().close();
+	
+					// this will return right away, it seems
+					process.waitFor();
+				} catch (InterruptedException e2) {
+					throw new MachineException("Aborted halting Linux host in " + getName(), e2);
+				}
+			} catch (Exception e) {
+				throw new MachineException("Cannot stop processes in Linux host in " + getName(), e);
+			}
+			
+			// probe until it's not responding
+			
+			long timeout = System.currentTimeMillis() + 60 * 1000;
+			while (true) {
+				for (int cnt = 0; cnt < 10; cnt++) {
+					try {
+						monitor.worked(1);
+						if (monitor.isCanceled())
+							return CANCEL_STATUS;
+
+						Thread.sleep(100);
+					} catch (InterruptedException e) {
+						// ignore
+					}
+					
+					while (Display.getCurrent().readAndDispatch()) ;
+				}
+				
+				// test the connection
+				scheduleProbe();
+				status = doProbeMachine(monitor);
+				if (!status.isOK()) {
+					// wait a LITTLE longer -- termination of ssh doesn't mean we have really shut down
+					for (int cnt = 0; cnt < 75; cnt++) {
+						monitor.worked(1);
+						if (monitor.isCanceled())
+							return CANCEL_STATUS;
+
+						try {
+							Thread.sleep(100);
+						} catch (InterruptedException e) {
+							doStopMachine(monitor);
+							return CANCEL_STATUS;
+						}
+						
+						while (Display.getCurrent().readAndDispatch()) ;
+					}
+					break;
+				}
+				
+				if (System.currentTimeMillis() >= timeout) {
+					throw processOutput("Timed out waiting for " + getName() + " shutdown", launchedMachineThread);
+				}
+			}
+			
+			// stop monitoring
+			launchedMachineThread.interrupt();
+			launchedMachineThread = null;
+			
+			// now, kill the process 
+			launchedMachineProcess.destroy();
+			launchedMachineProcess = null;
+			
+			fireMachineStateChanged();
+	
+			return Status.OK_STATUS;
+		} else {
+			return Activator.createStatus(IStatus.WARNING, 
+					"Not terminating " + getName() + " session that this IDE did not create");
+		}
+	}
+
+	/* (non-Javadoc)
+	 * @see org.maemo.mica.internal.common.core.machine.BaseMachineController#doAskUserToRepairMachine(org.eclipse.swt.widgets.Shell, org.eclipse.core.runtime.IStatus)
+	 */
+	@Override
+	protected Result doAskUserToRepairMachine(Shell shell, final IStatus status) {
+		/*
+		// If the machine isn't running at all, it's pretty easy to determine that
+		// re-launching it will repair the problem.
+		if (launchedMachineProcess != null) {
+			try {
+				launchedMachineProcess.exitValue();
+				return Result.IGNORE;
+			} catch (IllegalThreadStateException e) {
+				// still running
+			}
+		}
+		*/
+		// If we didn't launch the machine ourselves, the SSH connection is the only
+		// way to see if it *seems* to be running
+		//if (launchedMachineProcess == null && launchedMachineThread == null) {
+		IStatus probeStatus = testSSHPort();
+		if (!probeStatus.isOK()) {
+			// no one listening to the port, so probably machine not running; ignore the error and keep trying
+			return Result.IGNORE;
+		}
+		//}
+		
+		final boolean[] results = { false };
+		if (!WorkbenchUtils.isJUnitRunning()) {
+			Display.getDefault().syncExec(new Runnable() {
+	
+				public void run() {
+					results[0] = MessageDialog.openQuestion(null, getName() + " Problem",
+							MessageFormat.format(
+									"{0}\n\nCause:\n\n{1}\n\nRetry?",
+									status.getMessage(), status.getException().getMessage())
+									);
+					/*
+							MessageFormat.format(
+									
+									getName() + " may still be running, but it seems to be halted or crashed\n"
+									+"(or something else owns the server socket {0}:{1}).\n\n"
+									+"Please kill it if necessary and select 'Ok' to retry.",
+									MachineConfiguration.getSSHConfiguration().getTargetIPAddress(), 
+									""+MachineConfiguration.getSSHConfiguration().getTargetPort())
+					 */
+				}
+				
+			});
+		}
+		
+		if (!results[0]) {
+			// canceled
+			return Result.ABORT;
+		}
+		return Result.RETRY;
+
+	}
+
+	/* (non-Javadoc)
+	 * @see org.maemo.mica.internal.common.core.machine.BaseMachineController#acquireMachine(org.maemo.mica.common.core.machine.IMachine, org.eclipse.core.runtime.IProgressMonitor)
+	 */
+	@Override
+	public IStatus acquireMachine(IMachine machine, IProgressMonitor monitor) {
+		monitor.beginTask("", 2);
+		
+		// re-check to be sure
+		//scheduleProbe();
+		IStatus status = super.acquireMachine(machine, new SubProgressMonitor(monitor, 1));
+		if (!status.isOK())
+			return status;
+		
+		if (monitor.isCanceled())
+			return CANCEL_STATUS;
+		
+		// now, verify shared folders
+		status = SharedFilesystemMounter.validateSharedMounts(machine, new SubProgressMonitor(monitor, 1));
+
+		return status;
+	}
+	
+	/* (non-Javadoc)
+	 * @see org.maemo.mica.internal.common.core.machine.BaseMachineController#probeMachine(org.maemo.mica.common.core.machine.IMachine, org.eclipse.core.runtime.IProgressMonitor)
+	 */
+	@Override
+	public IStatus probeMachine(final IMachine machine, final IProgressMonitor monitor) {
+		monitor.beginTask("", 2);
+		
+		// re-check if things might be fishy
+		try {
+			if (launchedMachineProcess != null)
+				launchedMachineProcess.exitValue();
+			scheduleProbe();
+		} catch (IllegalThreadStateException e) {
+			
+		}
+		
+		IStatus status = super.probeMachine(machine, new SubProgressMonitor(monitor, 1));
+		if (!status.isOK())
+			return status;
+		
+		if (monitor.isCanceled())
+			return CANCEL_STATUS;
+		
+		try {
+			// try to ensure mounts are shared, but don't sync on this here
+			final IStatus[] subStatus = { null };
+			if (!isValidating) {
+				isValidating = true;
+				Runnable runnable = new Runnable() {
+
+					public void run() {
+						try {
+							IStatus status = SharedFilesystemMounter.validateSharedMounts(
+									machine,
+									new SubProgressMonitor(monitor, 1));
+							if (!status.isOK()) {
+								Activator.getErrorLogger().logError(status.getMessage(), status.getException());
+							}
+							subStatus[0] = status;
+						} finally {
+							isValidating = false;
+						}
+					}
+					
+				};
+				
+				// must do this asynchronously if we don't own the display;
+				// most likely the machine is owned by other thread
+				Display display = Display.getCurrent();
+				if (display == null)
+					Display.getDefault().asyncExec(runnable);
+				else
+					runnable.run();
+			}
+			
+			// in case the runnable was synchronous
+			if (!isValidating && subStatus[0] != null)
+				return subStatus[0];
+			
+			return Status.OK_STATUS;
+		} finally {
+			monitor.worked(1);
+			monitor.done();
+		}
+	}
+}

Modified: branches/work_Ed/org.maemo.esbox.vm/src/org/maemo/esbox/vm/core/IVirtualMachineConfiguration.java
===================================================================
--- branches/work_Ed/org.maemo.esbox.vm/src/org/maemo/esbox/vm/core/IVirtualMachineConfiguration.java	2008-11-17 21:07:20 UTC (rev 944)
+++ branches/work_Ed/org.maemo.esbox.vm/src/org/maemo/esbox/vm/core/IVirtualMachineConfiguration.java	2008-11-17 21:07:21 UTC (rev 945)
@@ -23,6 +23,12 @@
 public interface IVirtualMachineConfiguration {
 	/** Get the name (path + filename) of the program to launch. */
 	String getExecutable();
+	
+	
+	/** Get the command launch pattern.
+	 * @return a pattern suitable for ShellTemplateSubstitutor 
+	 */
+	String getCommandLaunchPattern();
 
 	/** Get the SSH configuration.  This combines most of the other VM settings
 	 * (username, password, target addr/port, host addr).

Modified: branches/work_Ed/org.maemo.esbox.vm.qemu/META-INF/MANIFEST.MF
===================================================================
--- branches/work_Ed/org.maemo.esbox.vm.qemu/META-INF/MANIFEST.MF	2008-11-17 21:07:20 UTC (rev 944)
+++ branches/work_Ed/org.maemo.esbox.vm.qemu/META-INF/MANIFEST.MF	2008-11-17 21:07:21 UTC (rev 945)
@@ -10,7 +10,8 @@
  org.maemo.mica.common.core;bundle-version="2.0.0",
  org.maemo.mica.common.ui;bundle-version="2.0.0",
  org.maemo.mica.protocol.ssh;bundle-version="2.0.0",
- org.maemo.esbox.vm;bundle-version="2.0.0"
+ org.maemo.esbox.vm;bundle-version="2.0.0",
+ org.maemo.esbox.maemosdk.core;bundle-version="2.0.0"
 Bundle-RequiredExecutionEnvironment: J2SE-1.5
 Bundle-ActivationPolicy: lazy
 Export-Package: org.maemo.esbox.internal.vm.qemu;x-friends:="org.maemo.mica.protocol.tests,org.maemo.esbox.scratchbox.tests",

Modified: branches/work_Ed/org.maemo.esbox.vm.qemu/src/org/maemo/esbox/internal/vm/qemu/CustomQemuConfiguration.java
===================================================================
--- branches/work_Ed/org.maemo.esbox.vm.qemu/src/org/maemo/esbox/internal/vm/qemu/CustomQemuConfiguration.java	2008-11-17 21:07:20 UTC (rev 944)
+++ branches/work_Ed/org.maemo.esbox.vm.qemu/src/org/maemo/esbox/internal/vm/qemu/CustomQemuConfiguration.java	2008-11-17 21:07:21 UTC (rev 945)
@@ -10,108 +10,64 @@
  *******************************************************************************/
 package org.maemo.esbox.internal.vm.qemu;
 
+import org.maemo.esbox.internal.api.vm.core.BaseCustomVirtualMachineConfiguration;
 import org.maemo.esbox.vm.qemu.IQemuConfiguration;
 import org.maemo.mica.common.core.MicaException;
 import org.maemo.mica.common.core.machine.ISharedFilesystemProvider;
-import org.maemo.mica.protocol.ssh.SSHConfiguration;
 
 import java.net.URI;
 
 /**
- * This configuration uses settings specified at construction time.
+ * This configuration uses settings specified at construction time 
+ * through the URI syntax (IMachineFactory)
  * @author eswartz
  *
  */
-public class CustomQemuConfiguration implements IQemuConfiguration {
+public class CustomQemuConfiguration extends BaseCustomVirtualMachineConfiguration implements IQemuConfiguration {
 	
-	private static final String HOST_ADDRESS = "hostAddress";
-	private static final String HOST_PORT = "hostPort";
-	private static final String TIMEOUT = "timeout";
 	private static final String INSTALL_PATH = "installPath";
 	private static final String DISK_IMAGE_PATHS = "diskImagePaths";
 	private static final String MEMORY_SIZE = "memorySize";
-	private static final String COMMAND_LAUNCH_PATTERN = "commandLaunchPattern";
-	private static final String CIFS_PORT = "cifsPort";
 	
-	private final SSHConfiguration sshConfiguration;
 	private String installPath;
 	private String diskImagePaths;
-	private String executable;
 	private int memorySize;
-	private String commandLaunchPattern;
-	private ISharedFilesystemProvider sharedFilesystemProvider;
-	private int cifsPort;
 
 	public CustomQemuConfiguration(URI uri, ISharedFilesystemProvider sharedFilesystemProvider) throws MicaException {
-		
-		this.sshConfiguration = new SSHConfiguration(uri);
-		this.sharedFilesystemProvider = sharedFilesystemProvider;
-		
-		this.sshConfiguration.setConnectionTimeout(1);
-		this.installPath = null;
-		this.diskImagePaths = null;
+		super(uri, sharedFilesystemProvider);
+	}	
+	
+	/* (non-Javadoc)
+	 * @see org.maemo.esbox.internal.vm.qemu.BaseCustomVirtualMachineConfiguration#setupDefaults()
+	 */
+	@Override
+	protected void setupDefaults() {
+		super.setupDefaults();
 		this.executable = "qemu.exe";
 		this.memorySize = 512;
 		this.commandLaunchPattern = "\"${QEMU}\" -kernel-kqemu ${DISK_OPTIONS} -usb -L \"${INSTALL_PATH}\" -m ${MEMORY} -redir tcp:${SSH_PORT}::22"; 
 		this.cifsPort = 445;
-		
-		String query = uri.getQuery();
-		String[] queryParts = query.split("&");
-		for (String queryPart : queryParts) {
-			int equIdx = queryPart.indexOf("=");
-			if (equIdx < 0)
-				throw new MicaException("Invalid query component: " + queryPart);
-			
-			String key = queryPart.substring(0, equIdx);
-			String value = queryPart.substring(equIdx + 1);
-
-			try {
-				if (key.equals(HOST_ADDRESS)) {
-					sshConfiguration.setHostIPAddress(value);
-				} else if (key.equals(HOST_PORT)) {
-					sshConfiguration.setHostPort(Integer.parseInt(value));
-				} else if (key.equals(TIMEOUT)) {
-					sshConfiguration.setConnectionTimeout(Integer.parseInt(value));
-				} else if (key.equals(INSTALL_PATH)) {
-					this.installPath = value;
-				} else if (key.equals(DISK_IMAGE_PATHS)) {
-					this.diskImagePaths = value;
-				} else if (key.equals(MEMORY_SIZE)) {
-					this.executable = value;
-				} else if (key.equals(COMMAND_LAUNCH_PATTERN)) {
-					this.commandLaunchPattern = value;
-				} else if (key.equals(CIFS_PORT)) {
-					this.cifsPort = Integer.parseInt(value);
-				} else {
-					Activator.getErrorLogger().logError("Ignoring unknown query component: " + queryPart, null);
-				}
-			} catch (NumberFormatException e) {
-				throw new MicaException("Invalid integer in query component: " + queryPart);
-			}
-		}
 	}
-	
+		
 	/* (non-Javadoc)
-	 * @see org.maemo.esbox.vm.core.IVirtualMachineConfiguration#getSSHConfiguration()
+	 * @see org.maemo.esbox.internal.vm.qemu.BaseCustomVirtualMachineConfiguration#decodeQueryPart(java.lang.String, java.lang.String)
 	 */
-	public SSHConfiguration getSSHConfiguration() {
-		return sshConfiguration;
+	@Override
+	protected boolean decodeQueryPart(String key, String value) {
+		if (super.decodeQueryPart(key, value))
+			return true;
+		if (key.equals(INSTALL_PATH)) {
+			this.installPath = value;
+		} else if (key.equals(DISK_IMAGE_PATHS)) {
+			this.diskImagePaths = value;
+		} else if (key.equals(MEMORY_SIZE)) {
+			this.executable = value;
+		} else {
+			return false;
+		}
+		return true;
 	}
 	
-	/* (non-Javadoc)
-	 * @see org.maemo.esbox.vm.core.IVirtualMachineConfiguration#getSharedFilesystemProvider()
-	 */
-	public ISharedFilesystemProvider getSharedFilesystemProvider() {
-		return sharedFilesystemProvider;
-	}
-	
-	/* (non-Javadoc)
-	 * @see org.maemo.esbox.vm.core.IVirtualMachineConfiguration#getCIFSPort()
-	 */
-	public int getCIFSPort() {
-		return cifsPort;
-	}
-	
 	public String getInstallPath() {
 		return installPath;
 	}
@@ -120,22 +76,10 @@
 		return diskImagePaths.split(","); 
 	}
 
-	public String getExecutable() {
-		return executable; 
-	}
-	
 	/* (non-Javadoc)
 	 * @see org.maemo.esbox.vm.qemu.IQemuConfiguration#getMemorySize()
 	 */
 	public int getMemorySize() {
 		return memorySize;
 	}
-	
-	/* (non-Javadoc)
-	 * @see org.maemo.esbox.vm.qemu.IQemuConfiguration#getCommandLaunchPattern()
-	 */
-	public String getCommandLaunchPattern() {
-		return commandLaunchPattern; 
-	}
-
 }

Modified: branches/work_Ed/org.maemo.esbox.vm.qemu/src/org/maemo/esbox/internal/vm/qemu/QemuBuildMachineFactory.java
===================================================================
--- branches/work_Ed/org.maemo.esbox.vm.qemu/src/org/maemo/esbox/internal/vm/qemu/QemuBuildMachineFactory.java	2008-11-17 21:07:20 UTC (rev 944)
+++ branches/work_Ed/org.maemo.esbox.vm.qemu/src/org/maemo/esbox/internal/vm/qemu/QemuBuildMachineFactory.java	2008-11-17 21:07:21 UTC (rev 945)
@@ -10,22 +10,19 @@
  *******************************************************************************/
 package org.maemo.esbox.internal.vm.qemu;
 
-import org.maemo.esbox.vm.qemu.IQemuConfiguration;
 import org.maemo.mica.common.core.machine.IBuildMachineFactory;
 import org.maemo.mica.internal.api.common.core.machine.IBuildMachineImpl;
 
 /**
  * This factory creates virtual build machines hosted on QEMU.
- * We support only one machine at a time, using preferences to store its settings.
+ * We support only one such machine at a time, using preferences to store its settings.
  * @author eswartz
  *
  */
 public class QemuBuildMachineFactory implements IBuildMachineFactory {
 
-	private IQemuConfiguration configuration;
 	public final static String NAME = "QEMU Linux Build Machine";
 	public QemuBuildMachineFactory() {
-		this.configuration = new PreferenceQemuConfiguration();
 	}
 	
 	
@@ -33,7 +30,7 @@
 	 * @see org.maemo.mica.common.core.machine.IMachineFactory#createMachine(java.lang.String)
 	 */
 	public synchronized IBuildMachineImpl[] getMachines() {
-		IBuildMachineImpl qemuMachine = new QemuMachine(NAME, configuration);
+		IBuildMachineImpl qemuMachine = new QemuMachine(NAME, new PreferenceQemuConfiguration());
 		return new IBuildMachineImpl[] { qemuMachine };
 	}
 

Modified: branches/work_Ed/org.maemo.esbox.vm.qemu/src/org/maemo/esbox/internal/vm/qemu/QemuMachine.java
===================================================================
--- branches/work_Ed/org.maemo.esbox.vm.qemu/src/org/maemo/esbox/internal/vm/qemu/QemuMachine.java	2008-11-17 21:07:20 UTC (rev 944)
+++ branches/work_Ed/org.maemo.esbox.vm.qemu/src/org/maemo/esbox/internal/vm/qemu/QemuMachine.java	2008-11-17 21:07:21 UTC (rev 945)
@@ -10,23 +10,15 @@
  *******************************************************************************/
 package org.maemo.esbox.internal.vm.qemu;
 
-import org.eclipse.core.runtime.*;
-import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.core.runtime.Platform;
 import org.maemo.esbox.vm.core.IVirtualMachine;
 import org.maemo.esbox.vm.core.IVirtualMachineConfiguration;
 import org.maemo.esbox.vm.qemu.IQemuConfiguration;
-import org.maemo.mica.common.core.*;
-import org.maemo.mica.common.core.machine.*;
-import org.maemo.mica.common.core.process.*;
-import org.maemo.mica.common.core.process.ProcessLauncherUtils.Results;
-import org.maemo.mica.common.ui.dialogs.DialogUtils;
-import org.maemo.mica.common.ui.dialogs.PasswordInputDialog;
+import org.maemo.mica.common.core.machine.IComposablePreferencePage;
 import org.maemo.mica.internal.api.common.core.machine.IBuildMachineImpl;
 import org.maemo.mica.internal.api.protocol.ssh.SSHMachineBackend;
 
-import java.io.*;
-import java.text.MessageFormat;
-import java.util.List;
+import java.net.URI;
 
 
 /**
@@ -46,178 +38,7 @@
 				configuration.getSSHConfiguration(), configuration.getSharedFilesystemProvider());
 		this.configuration = configuration; 
 	}
-	
-	/**
-	 * This method is called on the UI thread.  It should validate that
-	 * the shared filesystems are available, prompting the user for a password
-	 * and launching 'mount_share.sh' to mount them otherwise.
-	 * <p>
-	 * XXX: this must be rewritten at some point to handle shares which aren't handled by mount_share.sh!
-	 * @param subProgressMonitor 
-	 * @return Status of mount
-	 */
-	public IStatus validateSharedMounts(IProgressMonitor monitor) {
 
-		ISharedFilesystemProvider sharedFilesystemProvider = 
-			getSharedFilesystemProvider();
-		if (sharedFilesystemProvider == null)
-			return Status.OK_STATUS;
-		
-		List<ISharedFolder> sharedFolders = sharedFilesystemProvider.getSharedFolders();
-		
-		monitor.beginTask("Validating shared folders", sharedFolders.size() * 2);
-		
-		boolean neededMount = false;
-		
-		String fsTypePattern = "smbfs|cifs";
-		for (ISharedFolder share : sharedFolders) {
-			if (!isPathMounted(share.getRemotePath(), fsTypePattern, null)) {
-				neededMount = true;
-				PasswordInputDialog dialog = new PasswordInputDialog(
-						DialogUtils.getShell(), 
-						"Password Required",
-						MessageFormat.format(
-								"Enter the password for user ''{0}'' to mount the share ''{1}'':",
-								MachineRegistry.getInstance().getLocalMachine().getUserName(),
-								share.getLocalPath()));
-				if (IDialogConstants.CANCEL_ID == dialog.open())
-					continue;
-				
-				// TODO: this assumes a certain script exists on the VM
-				try {
-					mountSharesWithPassword(dialog.getPassword());
-				} catch (MicaException e) {
-					return Activator.createErrorStatus(
-							MessageFormat.format(
-									"Could not mount ''{0}'' in {1}",
-									share.getLocalPath().toString(),
-									getName()), e);
-				}
-				
-				monitor.worked(1);
-				if (monitor.isCanceled())
-					return Policy.getCancelStatus(Activator.getDefault());
-			}
-		}
-		
-		// verify that the mounting succeeded
-		boolean allSharesMounted = true;
-		if (neededMount) {
-			for (ISharedFolder share : sharedFolders) {
-				if (!isPathMounted(share.getRemotePath(), fsTypePattern, null)) {
-					allSharesMounted = false;
-				}
-				monitor.worked(1);
-				if (monitor.isCanceled())
-					return Policy.getCancelStatus(Activator.getDefault());
-			}
-		}
-		
-		monitor.done();
-		
-		if (!allSharesMounted) {
-			return Activator.createStatus(IStatus.WARNING, 
-					MessageFormat.format(
-							"Not all the known shares were mounted in {0}; builds may fail",
-							getName()));
-		}
-
-		return Status.OK_STATUS;
-	}
-	
-	/**
-	 * Run the 'mount_share.sh' script to mount shares.
-	 * @param password
-	 */
-	protected void mountSharesWithPassword(final String password) throws MicaException {
-		IProcessLauncherFactory processLauncherFactory = getProcessLauncherFactory();
-		final IProcessLauncher processLauncher = ProcessLauncherCreator.createProcessLauncher(processLauncherFactory,
-				getUserHome(),
-				CommandLineArguments.createFromVarArgs(
-						"sh",
-						"mount_share.sh"));
-		
-		processLauncher.usePTY(true);
-		//final Process process = processLauncher.createProcess();
-		final MicaException[] exceptions = { null };
-		
-		Thread thread = new Thread("Send password to mount") {
-
-			/* (non-Javadoc)
-			 * @see java.lang.Thread#run()
-			 */
-			@Override
-			public void run() {
-				//try {
-					/* this goes to a weird stream (somehow) so we can't read it,
-					 even though it shows up when we put stuff to the Console!
-					InputStream is = process.getInputStream();
-					int ch;
-					// read "Password:"
-					while ((ch = is.read()) != -1) {
-						if (ch == ':') {
-							break;
-						}
-					}
-					*/
-					
-					try {
-						Results results = ProcessLauncherUtils.launchAndReadStandardStreamsWithInput(processLauncher, 
-								new ByteArrayInputStream((password + "\n").getBytes()),
-								null);
-						String stdout = results.stdout.trim();
-						String stderr = results.stderr.replaceAll("Password:", "").trim();
-						if (results.exitCode != 0 || stdout.length() + stderr.length() > 0) {
-							exceptions[0] = new MicaException("Mounting script did not succeed:\n\n"
-									+ stdout + "\n" + stderr);
-						}
-					} catch (MicaException e) {
-						exceptions[0] = e;
-					}
-					System.out.println(exceptions[0]);
-					
-					/* this process adds noise to the console window without much use
-					// send password
-					OutputStream os = process.getOutputStream();
-					os.write((password + "\n").getBytes());
-					os.close();
-
-					// now let the remaining output go to the Console
-					processLauncher.redirectToConsole(false, null, "Mounting shares");
-					try {
-						int exit = process.waitFor();
-						if (exit != 0) {
-							exceptions[0] = new MicaException("Mounting script did not succeed; check Console for errors");
-							return;
-						}
-					} catch (InterruptedException e) {
-					}
-					
-				} catch (IOException e) {
-					exceptions[0] = new MicaException("Failed to send password", e);
-					return;
-				}
-				*/
-			}
-		};
-		thread.start();
-		
-		boolean timedOut = !JobUtils.waitForThread(thread, 10000, null);
-
-		//process.destroy();
-		
-		MicaException result = exceptions[0];
-		if (thread.isAlive())
-			thread.interrupt();
-		
-		if (result != null) {
-			throw result;
-		}
-		if (timedOut) {
-			throw new MicaException("Timeout sending password");
-		}
-	}
-
 	/* (non-Javadoc)
 	 * @see org.maemo.esbox.vm.core.IVirtualMachine#createPreferencePage(org.eclipse.swt.widgets.Composite)
 	 */
@@ -231,4 +52,15 @@
 	public IVirtualMachineConfiguration getConfiguration() {
 		return configuration;
 	}
+	
+	/* (non-Javadoc)
+	 * @see org.maemo.mica.internal.api.protocol.ssh.SSHMachineBackend#getURI()
+	 */
+	@Override
+	public URI getURI() {
+		return URI.create("qemu+ssh://" 
+				+ getSshConfiguration().getTargetIPAddress() 
+				+ ":" 
+				+ getSshConfiguration().getTargetPort());
+	}
 }

Modified: branches/work_Ed/org.maemo.esbox.vm.qemu/src/org/maemo/esbox/internal/vm/qemu/QemuMachineController.java
===================================================================
--- branches/work_Ed/org.maemo.esbox.vm.qemu/src/org/maemo/esbox/internal/vm/qemu/QemuMachineController.java	2008-11-17 21:07:20 UTC (rev 944)
+++ branches/work_Ed/org.maemo.esbox.vm.qemu/src/org/maemo/esbox/internal/vm/qemu/QemuMachineController.java	2008-11-17 21:07:21 UTC (rev 945)
@@ -11,23 +11,12 @@
 package org.maemo.esbox.internal.vm.qemu;
 
 
-import com.nokia.cpp.internal.api.utils.ui.WorkbenchUtils;
-
-import org.eclipse.core.runtime.*;
-import org.eclipse.jface.dialogs.MessageDialog;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Shell;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.maemo.esbox.internal.api.vm.core.BaseVirtualMachineController;
 import org.maemo.esbox.vm.qemu.IQemuConfiguration;
-import org.maemo.mica.common.core.*;
-import org.maemo.mica.common.core.machine.*;
 import org.maemo.mica.common.core.process.*;
-import org.maemo.mica.internal.api.protocol.ssh.SSHMachineControllerBase;
-import org.maemo.mica.protocol.ssh.SSHConfiguration;
 
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.net.Socket;
-import java.text.MessageFormat;
 import java.util.List;
 
 /**
@@ -35,102 +24,23 @@
  * @author eswartz
  *
  */
-public class QemuMachineController extends SSHMachineControllerBase {
+public class QemuMachineController extends BaseVirtualMachineController {
 
-	private static final IStatus CANCEL_STATUS = Policy.getCancelStatus(Activator.getDefault());
-	
-	/** thread and process are non-null if we launched QEMU ourselves */
-	Process launchedQemu;
-	/** thread and process are non-null if we launched QEMU ourselves */
-	QemuWatcherThread launchedQemuThread;
-	
-	private IQemuConfiguration qemuConfiguration;
-	private boolean isValidating;
-	
-	class QemuWatcherThread extends Thread {
-		private IProcessLauncher launcher;
-		private ByteArrayOutputStream err;
-		private ByteArrayOutputStream out;
-		public QemuWatcherThread(IProcessLauncher launcher) {
-			this.launcher = launcher;
-			setDaemon(true);
-		}
-		public void run() {
-			// TODO: make this go to the console
-			
-			// wait for it
-			out = new ByteArrayOutputStream();
-			err = new ByteArrayOutputStream();
-			launcher.waitAndRead(out, err);
-			System.out.println(out);
-			System.out.println(err);
-		}
-	}
-	
+	/**
+	 * @param name
+	 * @param configuration
+	 */
 	public QemuMachineController(IQemuConfiguration configuration) {
-		super("QEMU");
-		this.qemuConfiguration = configuration;
+		super("QEMU", configuration);
 	}
-	
+
 	/* (non-Javadoc)
-	 * @see org.maemo.mica.internal.api.protocol.ssh.SSHMachineControllerBase#getConfiguration()
+	 * @see org.maemo.esbox.internal.api.vm.core.BaseVirtualMachineController#constructLaunchParameters()
 	 */
 	@Override
-	protected SSHConfiguration getConfiguration() {
-		return qemuConfiguration.getSSHConfiguration(); 
-	}
-	
-	/**
-	 * @param processLauncher
-	 * @return
-	 */
-	MachineException processOutput(String message, QemuWatcherThread thread) {
-		return new MachineException(
-				MessageFormat.format("{0}\nCommand line: {1}\nstdout: {2}\nstderr: {3}",
-					message, 
-					CommandLineArguments.toCommandLine(thread.launcher.getLaunchCommandArguments()),
-					thread.out,
-					thread.err));
-	}
-
-	@Override
-	protected IStatus doStartMachine(IProgressMonitor monitor) throws MachineException {
-		// ensure we check again ASAP
-		scheduleProbe();
+	protected ProcessLauncherParameters constructLaunchParameters() {
+		IQemuConfiguration qemuConfiguration = (IQemuConfiguration) machineConfiguration;
 		
-		try {
-			return doStartMachineImpl(monitor);
-		} finally {
-			// and check again whether we think it succeeded or not
-			scheduleProbe();
-		}
-	}
-
-	/**
-	 * @param monitor
-	 * @return
-	 * @throws MachineException
-	 */
-	private IStatus doStartMachineImpl(IProgressMonitor monitor)
-			throws MachineException {
-		final int PROBE_COUNT = 10;
-		
-		monitor.beginTask("Starting " + getName(), IProgressMonitor.UNKNOWN);
-		
-		// we're here due to an error state
-		if (launchedQemu != null) {
-			// kill the running one since there's no way to fix it
-			
-			launchedQemu.destroy();
-			launchedQemu = null;
-			fireMachineStateChanged();
-			monitor.worked(1);
-			if (monitor.isCanceled())
-				return CANCEL_STATUS;
-		}
-		
-		monitor.setTaskName("Launching QEMU and waiting for startup...");
-		
 		String launchPattern = qemuConfiguration.getCommandLaunchPattern();
 		ShellTemplateSubstitutor substitutor = new ShellTemplateSubstitutor();
 		
@@ -155,325 +65,7 @@
 		launchPattern = substitutor.substitute(launchPattern);
 		List<String> cmdLine = CommandLineArguments.createFromHostCommandLine(launchPattern);
 		
-		String commandString = CommandLineArguments.toCommandLine(cmdLine);
-		System.out.println(commandString);
-		
-		IProcessLauncherFactory processLauncherFactory = new HostProcessLauncherFactory();
-		final IProcessLauncher processLauncher = ProcessLauncherCreator.createProcessLauncher(
-				processLauncherFactory, null, cmdLine);
-		try {
-			launchedQemu = processLauncher.createProcess();
-		} catch (MicaException e) {
-			throw new MachineException("Cannot launch qemu: " + CommandLineArguments.toCommandLine(cmdLine), e);
-		}
-		
-		launchedQemuThread = new QemuWatcherThread(processLauncher);
-		launchedQemuThread.start();
-		
-		long timeout = System.currentTimeMillis() + 300 * 1000;
-		while (true) {
-			if (!launchedQemuThread.isAlive()) {
-				throw processOutput("qemu launch failed", launchedQemuThread);
-			}
-			try {
-				launchedQemu.exitValue();
-				try {
-					launchedQemuThread.join();
-				} catch (InterruptedException e) {
-				}
-				throw processOutput("QEMU died", launchedQemuThread);
-			} catch (IllegalThreadStateException e) {
-				// still running
-			}
-			
-			for (int cnt = 0; cnt < PROBE_COUNT; cnt++) {
-				monitor.worked(1);
-				if (monitor.isCanceled())
-					return CANCEL_STATUS;
-
-				try {
-					Thread.sleep(100);
-				} catch (InterruptedException e) {
-					doStopMachine(monitor);
-					return CANCEL_STATUS;
-				}
-				
-				Display display = Display.getCurrent();
-				if (display != null) {
-					while (display.readAndDispatch()) ;
-				}
-			}
-			
-			// test the connection
-			scheduleProbe();
-			IStatus status = doProbeMachine(new SubProgressMonitor(monitor, 1));
-			if (status.isOK()) {
-				// XXX: do this more intelligently
-				// sshd starts a few moments before /etc/rc.local is run, 
-				// so kernel parameters like vdso might not be configured yet... 
-				// wait a few seconds more to avoid immediately invoking
-				// scratchbox commands and failing.
-				for (int cnt = 0; cnt < 50; cnt++) {
-					Display display = Display.getCurrent();
-					if (display != null) {
-						while (display.readAndDispatch()) ;
-					}
-					
-					monitor.worked(1);
-					if (monitor.isCanceled())
-						throw cancelled();
-
-					try {
-						Thread.sleep(100);
-					} catch (InterruptedException e) {
-						throw cancelled();
-					}
-				}
-				break;
-			}
-			
-			if (System.currentTimeMillis() >= timeout) {
-				throw processOutput("Timed out waiting for qemu startup", launchedQemuThread);
-			}
-		}
-		
-		fireMachineStateChanged();
-		
-		return Status.OK_STATUS;
+		return new ProcessLauncherParameters(null, cmdLine, null);
 	}
 	
-	protected MachineException cancelled() {
-		return new MachineException(null, new CoreException(CANCEL_STATUS));
-	}
-
-	@Override
-	protected IStatus doStopMachine(IProgressMonitor monitor) throws MachineException {
-		IStatus status = super.doStopMachine(monitor);
-		if (!status.isOK())
-			return status;
-		
-		// only try halting if we created it
-		if (launchedQemuThread != null && launchedQemuThread.isAlive()) {
-			// make it halt
-			List<String> cmdLine = CommandLineArguments.createFromCommandLine(
-				"sudo -S halt now");
-			
-			IProcessLauncherFactory processLauncherFactory = getProcessLauncherFactory();
-			Process process;
-			try {
-				process = ProcessLauncherCreator.createProcessLauncher(processLauncherFactory,
-						null, cmdLine).createProcess();
-				try {
-					// send the password for sudo
-					process.getOutputStream().write(qemuConfiguration.getSSHConfiguration().getUserPassword().getBytes());
-					process.getOutputStream().write('\n');
-					process.getOutputStream().close();
-	
-					// this will return right away, it seems
-					process.waitFor();
-				} catch (InterruptedException e2) {
-					throw new MachineException("Aborted halting Linux host in QEMU", e2);
-				}
-			} catch (Exception e) {
-				throw new MachineException("Cannot stop processes in Linux host in QEMU", e);
-			}
-			
-			// probe until it's not responding
-			
-			long timeout = System.currentTimeMillis() + 60 * 1000;
-			while (true) {
-				for (int cnt = 0; cnt < 10; cnt++) {
-					try {
-						monitor.worked(1);
-						if (monitor.isCanceled())
-							return CANCEL_STATUS;
-
-						Thread.sleep(100);
-					} catch (InterruptedException e) {
-						// ignore
-					}
-					
-					while (Display.getCurrent().readAndDispatch()) ;
-				}
-				
-				// test the connection
-				scheduleProbe();
-				status = doProbeMachine(monitor);
-				if (!status.isOK()) {
-					// wait a LITTLE longer -- termination of ssh doesn't mean we have really shut down
-					for (int cnt = 0; cnt < 75; cnt++) {
-						monitor.worked(1);
-						if (monitor.isCanceled())
-							return CANCEL_STATUS;
-
-						try {
-							Thread.sleep(100);
-						} catch (InterruptedException e) {
-							doStopMachine(monitor);
-							return CANCEL_STATUS;
-						}
-						
-						while (Display.getCurrent().readAndDispatch()) ;
-					}
-					break;
-				}
-				
-				if (System.currentTimeMillis() >= timeout) {
-					throw processOutput("Timed out waiting for qemu shutdown", launchedQemuThread);
-				}
-			}
-			
-			// stop monitoring
-			launchedQemuThread.interrupt();
-			launchedQemuThread = null;
-			
-			// now, kill the process 
-			launchedQemu.destroy();
-			launchedQemu = null;
-			
-			fireMachineStateChanged();
-	
-			return Status.OK_STATUS;
-		} else {
-			return Activator.createStatus(IStatus.WARNING, 
-					"Not terminating QEMU session that this IDE did not create");
-		}
-	}
-
-	/* (non-Javadoc)
-	 * @see org.maemo.mica.internal.common.core.machine.BaseMachineController#doAskUserToRepairMachine(org.eclipse.swt.widgets.Shell, org.eclipse.core.runtime.IStatus)
-	 */
-	@Override
-	protected Result doAskUserToRepairMachine(Shell shell, final IStatus status) {
-		// see if QEMU *seems* to be running... i.e. something is listening on the SSH port
-		try {
-			Socket socket = new Socket(qemuConfiguration.getSSHConfiguration().getTargetIPAddress(),
-					qemuConfiguration.getSSHConfiguration().getTargetPort());
-			socket.close();
-			
-		} catch (IOException e) {
-			// no one listening to the port, so probably qemu not running; ignore the error and keep trying
-			return Result.IGNORE;
-		}
-		
-		final boolean[] results = { false };
-		if (!WorkbenchUtils.isJUnitRunning()) {
-			Display.getDefault().syncExec(new Runnable() {
-	
-				public void run() {
-					results[0] = MessageDialog.openConfirm(null, "QEMU Problem",
-							MessageFormat.format(
-									"{0}\n\nCause:\n\n{1}\n\nRetry?",
-									status.getMessage(), status.getException().getMessage())
-									);
-					/*
-							MessageFormat.format(
-									
-									"QEMU may still be running, but it seems to be halted or crashed\n"
-									+"(or something else owns the server socket {0}:{1}).\n\n"
-									+"Please kill it if necessary and select 'Ok' to retry.",
-									qemuConfiguration.getSSHConfiguration().getTargetIPAddress(), 
-									""+qemuConfiguration.getSSHConfiguration().getTargetPort())
-					 */
-				}
-				
-			});
-		}
-		
-		if (!results[0]) {
-			// canceled
-			return Result.ABORT;
-		}
-		return Result.RETRY;
-
-	}
-
-	/* (non-Javadoc)
-	 * @see org.maemo.mica.internal.common.core.machine.BaseMachineController#acquireMachine(org.maemo.mica.common.core.machine.IMachine, org.eclipse.core.runtime.IProgressMonitor)
-	 */
-	@Override
-	public IStatus acquireMachine(IMachine machine, IProgressMonitor monitor) {
-		monitor.beginTask("", 2);
-		
-		// re-check to be sure
-		scheduleProbe();
-		IStatus status = super.acquireMachine(machine, new SubProgressMonitor(monitor, 1));
-		if (!status.isOK())
-			return status;
-		
-		if (monitor.isCanceled())
-			return CANCEL_STATUS;
-		
-		// now, verify shared folders
-		QemuMachine qemuMachine = (QemuMachine) machine;
-		
-		status = qemuMachine.validateSharedMounts(new SubProgressMonitor(monitor, 1));
-
-		return status;
-	}
-	
-	/* (non-Javadoc)
-	 * @see org.maemo.mica.internal.common.core.machine.BaseMachineController#probeMachine(org.maemo.mica.common.core.machine.IMachine, org.eclipse.core.runtime.IProgressMonitor)
-	 */
-	@Override
-	public IStatus probeMachine(final IMachine machine, final IProgressMonitor monitor) {
-		monitor.beginTask("", 2);
-		
-		// re-check if things might be fishy
-		try {
-			if (launchedQemu != null)
-				launchedQemu.exitValue();
-			scheduleProbe();
-		} catch (IllegalThreadStateException e) {
-			
-		}
-		
-		IStatus status = super.probeMachine(machine, new SubProgressMonitor(monitor, 1));
-		if (!status.isOK())
-			return status;
-		
-		if (monitor.isCanceled())
-			return CANCEL_STATUS;
-		
-		try {
-			// try to ensure mounts are shared, but don't sync on this here
-			final IStatus[] subStatus = { null };
-			if (!isValidating) {
-				isValidating = true;
-				Runnable runnable = new Runnable() {
-
-					public void run() {
-						try {
-							IStatus status = ((QemuMachine) machine).validateSharedMounts(
-									new SubProgressMonitor(monitor, 1));
-							if (!status.isOK()) {
-								Activator.getErrorLogger().logError(status.getMessage(), status.getException());
-							}
-							subStatus[0] = status;
-						} finally {
-							isValidating = false;
-						}
-					}
-					
-				};
-				
-				// must do this asynchronously if we don't own the display;
-				// most likely the machine is owned by other thread
-				Display display = Display.getCurrent();
-				if (display == null)
-					Display.getDefault().asyncExec(runnable);
-				else
-					runnable.run();
-			}
-			
-			// in case the runnable was synchronous
-			if (!isValidating && subStatus[0] != null)
-				return subStatus[0];
-			
-			return Status.OK_STATUS;
-		} finally {
-			monitor.worked(1);
-			monitor.done();
-		}
-	}
 }

Modified: branches/work_Ed/org.maemo.esbox.vm.qemu/src/org/maemo/esbox/vm/qemu/IQemuConfiguration.java
===================================================================
--- branches/work_Ed/org.maemo.esbox.vm.qemu/src/org/maemo/esbox/vm/qemu/IQemuConfiguration.java	2008-11-17 21:07:20 UTC (rev 944)
+++ branches/work_Ed/org.maemo.esbox.vm.qemu/src/org/maemo/esbox/vm/qemu/IQemuConfiguration.java	2008-11-17 21:07:21 UTC (rev 945)
@@ -33,11 +33,4 @@
 	/** Get the memory size in Mb. */
 	int getMemorySize();
 	
-	/** Get the command launch pattern.
-	 * @return a pattern suitable for ShellTemplateSubstitutor 
-	 */
-	String getCommandLaunchPattern();
-	
-	
-	
 }



More information about the Esbox-commits mailing list