[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