Maemo: Introduce explicit states to deploy step.

Probably fixed some subtle error handling bugs along the way.

Task-number: QTCREATORBUG-2705
This commit is contained in:
Christian Kandeler
2010-11-03 17:11:56 +01:00
parent 706a04c686
commit 1914d05db3
2 changed files with 356 additions and 195 deletions

View File

@@ -55,6 +55,8 @@
#include <QtCore/QFileInfo> #include <QtCore/QFileInfo>
#include <QtCore/QTimer> #include <QtCore/QTimer>
#define ASSERT_STATE(state) ASSERT_STATE_GENERIC(State, state, m_state)
using namespace Core; using namespace Core;
using namespace ProjectExplorer; using namespace ProjectExplorer;
@@ -97,11 +99,9 @@ void MaemoDeployStep::ctor()
m_deployables = other->deployables(); m_deployables = other->deployables();
} }
m_connecting = false; m_state = Inactive;
m_needsInstall = false; m_needsInstall = false;
m_stopped = false;
m_deviceConfigModel = new MaemoDeviceConfigListModel(this); m_deviceConfigModel = new MaemoDeviceConfigListModel(this);
m_canStart = true;
m_sysrootInstaller = new QProcess(this); m_sysrootInstaller = new QProcess(this);
connect(m_sysrootInstaller, SIGNAL(finished(int,QProcess::ExitStatus)), connect(m_sysrootInstaller, SIGNAL(finished(int,QProcess::ExitStatus)),
this, SLOT(handleSysrootInstallerFinished())); this, SLOT(handleSysrootInstallerFinished()));
@@ -109,9 +109,6 @@ void MaemoDeployStep::ctor()
SLOT(handleSysrootInstallerOutput())); SLOT(handleSysrootInstallerOutput()));
connect(m_sysrootInstaller, SIGNAL(readyReadStandardError()), this, connect(m_sysrootInstaller, SIGNAL(readyReadStandardError()), this,
SLOT(handleSysrootInstallerErrorOutput())); SLOT(handleSysrootInstallerErrorOutput()));
m_cleanupTimer = new QTimer(this);
connect(m_cleanupTimer, SIGNAL(timeout()), this,
SLOT(handleCleanupTimeout()));
m_mounter = new MaemoRemoteMounter(this); m_mounter = new MaemoRemoteMounter(this);
connect(m_mounter, SIGNAL(mounted()), this, SLOT(handleMounted())); connect(m_mounter, SIGNAL(mounted()), this, SLOT(handleMounted()));
connect(m_mounter, SIGNAL(unmounted()), this, SLOT(handleUnmounted())); connect(m_mounter, SIGNAL(unmounted()), this, SLOT(handleUnmounted()));
@@ -139,7 +136,6 @@ void MaemoDeployStep::run(QFutureInterface<bool> &fi)
QTimer::singleShot(0, this, SLOT(start())); QTimer::singleShot(0, this, SLOT(start()));
MaemoDeployEventHandler eventHandler(this, fi); MaemoDeployEventHandler eventHandler(this, fi);
connect (&eventHandler, SIGNAL(destroyed()), this, SLOT(stop()));
} }
BuildStepConfigWidget *MaemoDeployStep::createConfigWidget() BuildStepConfigWidget *MaemoDeployStep::createConfigWidget()
@@ -214,7 +210,6 @@ const MaemoPackageCreationStep *MaemoDeployStep::packagingStep() const
void MaemoDeployStep::raiseError(const QString &errorString) void MaemoDeployStep::raiseError(const QString &errorString)
{ {
disconnect(m_connection.data(), 0, this, 0);
emit addTask(Task(Task::Error, errorString, QString(), -1, emit addTask(Task(Task::Error, errorString, QString(), -1,
Constants::TASK_CATEGORY_BUILDSYSTEM)); Constants::TASK_CATEGORY_BUILDSYSTEM));
emit error(); emit error();
@@ -227,40 +222,46 @@ void MaemoDeployStep::writeOutput(const QString &text, OutputFormat format)
void MaemoDeployStep::stop() void MaemoDeployStep::stop()
{ {
if (m_stopped) if (m_state == StopRequested || m_state == Inactive)
return; return;
const bool remoteProcessRunning const State oldState = m_state;
= (m_deviceInstaller && m_deviceInstaller->isRunning()) setState(StopRequested);
|| m_currentDeviceDeployAction; switch (oldState) {
const bool isActive = remoteProcessRunning || m_connecting case InstallingToSysroot:
|| m_needsInstall || !m_filesToCopy.isEmpty(); if (m_needsInstall)
if (!isActive) { m_sysrootInstaller->terminate();
if (m_connection) break;
disconnect(m_connection.data(), 0, this, 0); case Connecting:
return; m_connection->disconnectFromHost();
} setState(Inactive);
break;
if (remoteProcessRunning) { case InstallingToDevice:
const QByteArray programToKill case CopyingFile: {
= m_currentDeviceDeployAction ? "/bin/cp" : "/usr/bin/dpkg"; const QByteArray programToKill = oldState == CopyingFile
const QByteArray cmdLine = "pkill " + programToKill ? " cp " : "dpkg";
+ "; sleep 1; pkill -9 " + programToKill; const QByteArray killCommand
= MaemoGlobal::remoteSudo().toUtf8() + " pkill -f ";
const QByteArray cmdLine = killCommand + programToKill + "; sleep 1; "
+ killCommand + "-9 " + programToKill;
SshRemoteProcess::Ptr killProc SshRemoteProcess::Ptr killProc
= m_connection->createRemoteProcess(cmdLine); = m_connection->createRemoteProcess(cmdLine);
killProc->start(); killProc->start();
break;
}
case Uploading:
m_uploader->closeChannel();
break;
case UnmountingOldDirs:
case UnmountingCurrentDirs:
case UnmountingCurrentMounts:
case GatheringPorts:
case Mounting:
case InitializingSftp:
break; // Nothing to do here.
default:
Q_ASSERT_X(false, Q_FUNC_INFO, "Missing switch case.");
} }
m_stopped = true;
m_unmountState = CurrentMountsUnmount;
m_canStart = false;
m_needsInstall = false;
m_filesToCopy.clear();
m_connecting = false;
m_sysrootInstaller->terminate();
m_sysrootInstaller->waitForFinished(500);
m_sysrootInstaller->kill();
m_cleanupTimer->start(5000);
m_mounter->stop();
} }
QString MaemoDeployStep::uploadDir() const QString MaemoDeployStep::uploadDir() const
@@ -291,15 +292,15 @@ MaemoDeviceConfig MaemoDeployStep::deviceConfig() const
void MaemoDeployStep::start() void MaemoDeployStep::start()
{ {
if (!m_canStart) { if (m_state != Inactive) {
raiseError(tr("Cannot start deployment, as the clean-up from the last time has not finished yet.")); raiseError(tr("Cannot deploy: Still cleaning up from last time."));
emit done();
return; return;
} }
m_cleanupTimer->stop();
m_stopped = false;
if (!deviceConfig().isValid()) { if (!deviceConfig().isValid()) {
raiseError(tr("Deployment failed: No valid device set.")); raiseError(tr("Deployment failed: No valid device set."));
emit done();
return; return;
} }
@@ -334,125 +335,181 @@ void MaemoDeployStep::start()
void MaemoDeployStep::handleConnectionFailure() void MaemoDeployStep::handleConnectionFailure()
{ {
m_connecting = false; if (m_state != Inactive) {
if (m_stopped) { raiseError(tr("Could not connect to host: %1")
m_canStart = true; .arg(m_connection->errorString()));
return; setState(Inactive);
} }
raiseError(tr("Could not connect to host: %1")
.arg(m_connection->errorString()));
} }
void MaemoDeployStep::handleSftpChannelInitialized() void MaemoDeployStep::handleSftpChannelInitialized()
{ {
if (m_stopped) { ASSERT_STATE(QList<State>() << InitializingSftp << StopRequested);
m_canStart = true;
return;
}
const QString filePath = packagingStep()->packageFilePath(); switch (m_state) {
const QString filePathNative = QDir::toNativeSeparators(filePath); case InitializingSftp: {
const QString fileName = QFileInfo(filePath).fileName(); const QString filePath = packagingStep()->packageFilePath();
const QString remoteFilePath = uploadDir() + QLatin1Char('/') + fileName; const QString filePathNative = QDir::toNativeSeparators(filePath);
const SftpJobId job = m_uploader->uploadFile(filePath, const QString fileName = QFileInfo(filePath).fileName();
remoteFilePath, SftpOverwriteExisting); const QString remoteFilePath = uploadDir() + QLatin1Char('/') + fileName;
if (job == SftpInvalidJob) { const SftpJobId job = m_uploader->uploadFile(filePath,
raiseError(tr("Upload failed: Could not open file '%1'") remoteFilePath, SftpOverwriteExisting);
.arg(filePathNative)); if (job == SftpInvalidJob) {
} else { raiseError(tr("Upload failed: Could not open file '%1'")
writeOutput(tr("Started uploading file '%1'.").arg(filePathNative)); .arg(filePathNative));
setState(Inactive);
} else {
setState(Uploading);
writeOutput(tr("Started uploading file '%1'.").arg(filePathNative));
}
break;
}
case StopRequested:
setState(Inactive);
break;
default:
break;
} }
} }
void MaemoDeployStep::handleSftpChannelInitializationFailed(const QString &error) void MaemoDeployStep::handleSftpChannelInitializationFailed(const QString &error)
{ {
if (m_stopped) { ASSERT_STATE(QList<State>() << InitializingSftp << StopRequested);
m_canStart = true;
return; switch (m_state) {
case InitializingSftp:
case StopRequested:
raiseError(tr("Could not set up SFTP connection: %1").arg(error));
setState(Inactive);
break;
default:
break;
} }
raiseError(tr("Could not set up SFTP connection: %1").arg(error));
} }
void MaemoDeployStep::handleSftpJobFinished(Core::SftpJobId, void MaemoDeployStep::handleSftpJobFinished(Core::SftpJobId,
const QString &error) const QString &error)
{ {
if (m_stopped) { ASSERT_STATE(QList<State>() << Uploading << StopRequested);
m_canStart = true;
return;
}
const QString filePathNative const QString filePathNative
= QDir::toNativeSeparators(packagingStep()->packageFilePath()); = QDir::toNativeSeparators(packagingStep()->packageFilePath());
if (!error.isEmpty()) { if (!error.isEmpty()) {
raiseError(tr("Failed to upload file %1: %2") raiseError(tr("Failed to upload file %1: %2")
.arg(filePathNative, error)); .arg(filePathNative, error));
return; if (m_state == Uploading)
setState(Inactive);
} else if (m_state == Uploading) {
writeOutput(tr("Successfully uploaded file '%1'.")
.arg(filePathNative));
const QString remoteFilePath
= uploadDir() + QLatin1Char('/') + QFileInfo(filePathNative).fileName();
runDpkg(remoteFilePath);
} }
}
writeOutput(tr("Successfully uploaded file '%1'.") void MaemoDeployStep::handleSftpChannelClosed()
.arg(filePathNative)); {
const QString remoteFilePath ASSERT_STATE(StopRequested);
= uploadDir() + QLatin1Char('/') + QFileInfo(filePathNative).fileName(); setState(Inactive);
runDpkg(remoteFilePath, true);
} }
void MaemoDeployStep::handleMounted() void MaemoDeployStep::handleMounted()
{ {
if (m_stopped) { ASSERT_STATE(QList<State>() << Mounting << StopRequested << Inactive);
m_mounter->unmount();
return;
}
if (m_needsInstall) { switch (m_state) {
const QString remoteFilePath = deployMountPoint() + QLatin1Char('/') case Mounting:
+ QFileInfo(packagingStep()->packageFilePath()).fileName(); if (m_needsInstall) {
runDpkg(remoteFilePath, false); const QString remoteFilePath = deployMountPoint() + QLatin1Char('/')
} else { + QFileInfo(packagingStep()->packageFilePath()).fileName();
copyNextFileToDevice(); runDpkg(remoteFilePath);
} else {
setState(CopyingFile);
copyNextFileToDevice();
}
break;
case StopRequested:
unmount();
break;
case Inactive:
default:
break;
} }
} }
void MaemoDeployStep::handleUnmounted() void MaemoDeployStep::handleUnmounted()
{ {
if (m_stopped) { ASSERT_STATE(QList<State>() << UnmountingOldDirs << UnmountingCurrentDirs
m_mounter->resetMountSpecifications(); << UnmountingCurrentMounts << StopRequested << Inactive);
m_canStart = true;
return;
}
switch (m_unmountState) { switch (m_state) {
case OldDirsUnmount: case StopRequested:
m_mounter->resetMountSpecifications();
setState(Inactive);
break;
case UnmountingOldDirs:
if (toolChain()->allowsRemoteMounts()) if (toolChain()->allowsRemoteMounts())
setupMount(); setupMount();
else else
prepareSftpConnection(); prepareSftpConnection();
break; break;
case CurrentDirsUnmount: case UnmountingCurrentDirs:
setState(GatheringPorts);
m_portsGatherer->start(m_connection, deviceConfig().freePorts()); m_portsGatherer->start(m_connection, deviceConfig().freePorts());
break; break;
case CurrentMountsUnmount: case UnmountingCurrentMounts:
writeOutput(tr("Deployment finished.")); writeOutput(tr("Deployment finished."));
emit done(); setState(Inactive);
break;
case Inactive:
default:
break; break;
} }
} }
void MaemoDeployStep::handleMountError(const QString &errorMsg) void MaemoDeployStep::handleMountError(const QString &errorMsg)
{ {
if (m_stopped) ASSERT_STATE(QList<State>() << UnmountingOldDirs << UnmountingCurrentDirs
m_canStart = true; << UnmountingCurrentMounts << Mounting << StopRequested << Inactive);
else
switch (m_state) {
case UnmountingOldDirs:
case UnmountingCurrentDirs:
case UnmountingCurrentMounts:
case StopRequested:
raiseError(errorMsg); raiseError(errorMsg);
setState(Inactive);
break;
case Inactive:
default:
break;
}
} }
void MaemoDeployStep::handleMountDebugOutput(const QString &output) void MaemoDeployStep::handleMountDebugOutput(const QString &output)
{ {
if (!m_stopped) ASSERT_STATE(QList<State>() << UnmountingOldDirs << UnmountingCurrentDirs
<< UnmountingCurrentMounts << Mounting << StopRequested << Inactive);
switch (m_state) {
case UnmountingOldDirs:
case UnmountingCurrentDirs:
case UnmountingCurrentMounts:
case StopRequested:
writeOutput(output, ErrorOutput); writeOutput(output, ErrorOutput);
break;
case Inactive:
default:
break;
}
} }
void MaemoDeployStep::setupMount() void MaemoDeployStep::setupMount()
{ {
ASSERT_STATE(UnmountingOldDirs);
setState(UnmountingCurrentDirs);
Q_ASSERT(m_needsInstall || !m_filesToCopy.isEmpty()); Q_ASSERT(m_needsInstall || !m_filesToCopy.isEmpty());
m_mounter->resetMountSpecifications(); m_mounter->resetMountSpecifications();
m_mounter->setToolchain(toolChain()); m_mounter->setToolchain(toolChain());
@@ -490,17 +547,12 @@ void MaemoDeployStep::setupMount()
deployMountPoint()), true); deployMountPoint()), true);
#endif #endif
} }
m_unmountState = CurrentDirsUnmount; unmount();
m_mounter->unmount();
} }
void MaemoDeployStep::prepareSftpConnection() void MaemoDeployStep::prepareSftpConnection()
{ {
// TODO: Close channel when upload has finished/failed/etc. setState(InitializingSftp);
if (m_uploader) {
disconnect(m_uploader.data(), 0, this, 0);
m_uploader->closeChannel();
}
m_uploader = m_connection->createSftpChannel(); m_uploader = m_connection->createSftpChannel();
connect(m_uploader.data(), SIGNAL(initialized()), this, connect(m_uploader.data(), SIGNAL(initialized()), this,
SLOT(handleSftpChannelInitialized())); SLOT(handleSftpChannelInitialized()));
@@ -508,11 +560,16 @@ void MaemoDeployStep::prepareSftpConnection()
SLOT(handleSftpChannelInitializationFailed(QString))); SLOT(handleSftpChannelInitializationFailed(QString)));
connect(m_uploader.data(), SIGNAL(finished(Core::SftpJobId, QString)), connect(m_uploader.data(), SIGNAL(finished(Core::SftpJobId, QString)),
this, SLOT(handleSftpJobFinished(Core::SftpJobId, QString))); this, SLOT(handleSftpJobFinished(Core::SftpJobId, QString)));
connect(m_uploader.data(), SIGNAL(closed()), this,
SLOT(handleSftpChannelClosed()));
m_uploader->initialize(); m_uploader->initialize();
} }
void MaemoDeployStep::installToSysroot() void MaemoDeployStep::installToSysroot()
{ {
ASSERT_STATE(Inactive);
setState(InstallingToSysroot);
if (m_needsInstall) { if (m_needsInstall) {
writeOutput(tr("Installing package to sysroot ...")); writeOutput(tr("Installing package to sysroot ..."));
const MaemoToolChain * const tc = toolChain(); const MaemoToolChain * const tc = toolChain();
@@ -543,8 +600,8 @@ void MaemoDeployStep::installToSysroot()
ErrorMessageOutput); ErrorMessageOutput);
} }
QCoreApplication::processEvents(); QCoreApplication::processEvents();
if (m_stopped) { if (m_state == StopRequested) {
m_canStart = true; setState(Inactive);
return; return;
} }
} }
@@ -554,8 +611,10 @@ void MaemoDeployStep::installToSysroot()
void MaemoDeployStep::handleSysrootInstallerFinished() void MaemoDeployStep::handleSysrootInstallerFinished()
{ {
if (m_stopped) { ASSERT_STATE(QList<State>() << InstallingToSysroot << StopRequested);
m_canStart = true;
if (m_state == StopRequested) {
setState(Inactive);
return; return;
} }
@@ -569,7 +628,9 @@ void MaemoDeployStep::handleSysrootInstallerFinished()
void MaemoDeployStep::connectToDevice() void MaemoDeployStep::connectToDevice()
{ {
m_connecting = false; ASSERT_STATE(QList<State>() << Inactive << InstallingToSysroot);
setState(Connecting);
const bool canReUse = m_connection const bool canReUse = m_connection
&& m_connection->state() == SshConnection::Connected && m_connection->state() == SshConnection::Connected
&& m_connection->connectionParameters() == deviceConfig().server; && m_connection->connectionParameters() == deviceConfig().server;
@@ -580,34 +641,34 @@ void MaemoDeployStep::connectToDevice()
connect(m_connection.data(), SIGNAL(error(Core::SshError)), this, connect(m_connection.data(), SIGNAL(error(Core::SshError)), this,
SLOT(handleConnectionFailure())); SLOT(handleConnectionFailure()));
if (canReUse) { if (canReUse) {
unmountOldDirs(); handleConnected();
} else { } else {
writeOutput(tr("Connecting to device...")); writeOutput(tr("Connecting to device..."));
m_connecting = true;
m_connection->connectToHost(deviceConfig().server); m_connection->connectToHost(deviceConfig().server);
} }
} }
void MaemoDeployStep::handleConnected() void MaemoDeployStep::handleConnected()
{ {
if (m_stopped) { ASSERT_STATE(QList<State>() << Connecting << StopRequested);
m_canStart = true;
return;
}
unmountOldDirs(); if (m_state == Connecting)
unmountOldDirs();
} }
void MaemoDeployStep::unmountOldDirs() void MaemoDeployStep::unmountOldDirs()
{ {
m_unmountState = OldDirsUnmount; setState(UnmountingOldDirs);
m_mounter->setConnection(m_connection); m_mounter->setConnection(m_connection);
m_mounter->unmount(); unmount();
} }
void MaemoDeployStep::runDpkg(const QString &packageFilePath, void MaemoDeployStep::runDpkg(const QString &packageFilePath)
bool removeAfterInstall)
{ {
ASSERT_STATE(QList<State>() << Mounting << Uploading);
const bool removeAfterInstall = m_state == Uploading;
setState(InstallingToDevice);
writeOutput(tr("Installing package to device...")); writeOutput(tr("Installing package to device..."));
QByteArray cmd = MaemoGlobal::remoteSudo().toUtf8() + " dpkg -i " QByteArray cmd = MaemoGlobal::remoteSudo().toUtf8() + " dpkg -i "
+ packageFilePath.toUtf8(); + packageFilePath.toUtf8();
@@ -626,11 +687,25 @@ void MaemoDeployStep::runDpkg(const QString &packageFilePath,
void MaemoDeployStep::handleProgressReport(const QString &progressMsg) void MaemoDeployStep::handleProgressReport(const QString &progressMsg)
{ {
writeOutput(progressMsg); ASSERT_STATE(QList<State>() << UnmountingOldDirs << UnmountingCurrentDirs
<< UnmountingCurrentMounts << Mounting << StopRequested << Inactive);
switch (m_state) {
case UnmountingOldDirs:
case UnmountingCurrentDirs:
case UnmountingCurrentMounts:
case StopRequested:
writeOutput(progressMsg);
break;
case Inactive:
default:
break;
}
} }
void MaemoDeployStep::copyNextFileToDevice() void MaemoDeployStep::copyNextFileToDevice()
{ {
ASSERT_STATE(CopyingFile);
Q_ASSERT(!m_filesToCopy.isEmpty()); Q_ASSERT(!m_filesToCopy.isEmpty());
Q_ASSERT(!m_currentDeviceDeployAction); Q_ASSERT(!m_currentDeviceDeployAction);
const MaemoDeployable d = m_filesToCopy.takeFirst(); const MaemoDeployable d = m_filesToCopy.takeFirst();
@@ -660,45 +735,40 @@ void MaemoDeployStep::copyNextFileToDevice()
void MaemoDeployStep::handleCopyProcessFinished(int exitStatus) void MaemoDeployStep::handleCopyProcessFinished(int exitStatus)
{ {
if (m_stopped) { ASSERT_STATE(QList<State>() << CopyingFile << StopRequested << Inactive);
m_mounter->unmount();
return;
}
Q_ASSERT(m_currentDeviceDeployAction); switch (m_state) {
const QString localFilePath = m_currentDeviceDeployAction->first.localFilePath; case CopyingFile: {
if (exitStatus != SshRemoteProcess::ExitedNormally Q_ASSERT(m_currentDeviceDeployAction);
|| m_currentDeviceDeployAction->second->exitCode() != 0) { const QString localFilePath
raiseError(tr("Copying file '%1' failed.").arg(localFilePath)); = m_currentDeviceDeployAction->first.localFilePath;
m_mounter->unmount(); if (exitStatus != SshRemoteProcess::ExitedNormally
m_currentDeviceDeployAction.reset(0); || m_currentDeviceDeployAction->second->exitCode() != 0) {
} else { raiseError(tr("Copying file '%1' failed.").arg(localFilePath));
writeOutput(tr("Successfully copied file '%1'.").arg(localFilePath));
setDeployed(m_connection->connectionParameters().host,
m_currentDeviceDeployAction->first);
m_currentDeviceDeployAction.reset(0);
if (m_filesToCopy.isEmpty()) {
writeOutput(tr("All files copied."));
m_unmountState = CurrentMountsUnmount;
m_mounter->unmount();
} else {
copyNextFileToDevice();
}
}
}
void MaemoDeployStep::handleCleanupTimeout()
{
m_cleanupTimer->stop();
if (!m_canStart) {
m_canStart = true;
disconnect(m_connection.data(), 0, this, 0);
if (m_deviceInstaller)
disconnect(m_deviceInstaller.data(), 0, this, 0);
if (m_currentDeviceDeployAction) {
disconnect(m_currentDeviceDeployAction->second.data(), 0, this, 0);
m_currentDeviceDeployAction.reset(0); m_currentDeviceDeployAction.reset(0);
setState(UnmountingCurrentMounts);
unmount();
} else {
writeOutput(tr("Successfully copied file '%1'.").arg(localFilePath));
setDeployed(m_connection->connectionParameters().host,
m_currentDeviceDeployAction->first);
m_currentDeviceDeployAction.reset(0);
if (m_filesToCopy.isEmpty()) {
writeOutput(tr("All files copied."));
setState(UnmountingCurrentMounts);
unmount();
} else {
copyNextFileToDevice();
}
} }
break;
}
case StopRequested:
unmount();
break;
case Inactive:
default:
break;
} }
} }
@@ -717,64 +787,146 @@ const MaemoToolChain *MaemoDeployStep::toolChain() const
void MaemoDeployStep::handleSysrootInstallerOutput() void MaemoDeployStep::handleSysrootInstallerOutput()
{ {
if (!m_stopped) { ASSERT_STATE(QList<State>() << InstallingToSysroot << StopRequested);
switch (m_state) {
case InstallingToSysroot:
case StopRequested:
writeOutput(QString::fromLocal8Bit(m_sysrootInstaller->readAllStandardOutput()), writeOutput(QString::fromLocal8Bit(m_sysrootInstaller->readAllStandardOutput()),
NormalOutput); NormalOutput);
break;
default:
break;
} }
} }
void MaemoDeployStep::handleSysrootInstallerErrorOutput() void MaemoDeployStep::handleSysrootInstallerErrorOutput()
{ {
if (!m_stopped) { ASSERT_STATE(QList<State>() << InstallingToSysroot << StopRequested);
switch (m_state) {
case InstallingToSysroot:
case StopRequested:
writeOutput(QString::fromLocal8Bit(m_sysrootInstaller->readAllStandardError()), writeOutput(QString::fromLocal8Bit(m_sysrootInstaller->readAllStandardError()),
BuildStep::ErrorOutput); BuildStep::ErrorOutput);
break;
default:
break;
} }
} }
void MaemoDeployStep::handleInstallationFinished(int exitStatus) void MaemoDeployStep::handleInstallationFinished(int exitStatus)
{ {
if (m_stopped) { ASSERT_STATE(QList<State>() << InstallingToDevice << StopRequested
m_mounter->unmount(); << Inactive);
return;
}
if (exitStatus != SshRemoteProcess::ExitedNormally switch (m_state) {
|| m_deviceInstaller->exitCode() != 0) { case InstallingToDevice:
raiseError(tr("Installing package failed.")); if (exitStatus != SshRemoteProcess::ExitedNormally
} else { || m_deviceInstaller->exitCode() != 0) {
m_needsInstall = false; raiseError(tr("Installing package failed."));
setDeployed(m_connection->connectionParameters().host, } else {
MaemoDeployable(packagingStep()->packageFilePath(), QString())); m_needsInstall = false;
writeOutput(tr("Package installed.")); setDeployed(m_connection->connectionParameters().host,
MaemoDeployable(packagingStep()->packageFilePath(), QString()));
writeOutput(tr("Package installed."));
}
setState(UnmountingCurrentMounts);
unmount();
break;
case StopRequested:
unmount();
break;
case Inactive:
default:
break;
} }
m_unmountState = CurrentMountsUnmount;
m_mounter->unmount();
} }
void MaemoDeployStep::handlePortsGathererError(const QString &errorMsg) void MaemoDeployStep::handlePortsGathererError(const QString &errorMsg)
{ {
raiseError(errorMsg); ASSERT_STATE(QList<State>() << GatheringPorts << StopRequested << Inactive);
if (m_state != Inactive) {
raiseError(errorMsg);
setState(Inactive);
}
} }
void MaemoDeployStep::handlePortListReady() void MaemoDeployStep::handlePortListReady()
{ {
m_freePorts = deviceConfig().freePorts(); ASSERT_STATE(QList<State>() << GatheringPorts << StopRequested);
m_mounter->mount(&m_freePorts, m_portsGatherer);
if (m_state == GatheringPorts) {
setState(Mounting);
m_freePorts = deviceConfig().freePorts();
m_mounter->mount(&m_freePorts, m_portsGatherer);
} else {
setState(Inactive);
}
}
void MaemoDeployStep::setState(State newState)
{
if (newState == m_state)
return;
m_state = newState;
if (m_state == Inactive) {
m_needsInstall = false;
m_filesToCopy.clear();
m_currentDeviceDeployAction.reset(0);
if (m_connection)
disconnect(m_connection.data(), 0, this, 0);
if (m_uploader) {
disconnect(m_uploader.data(), 0, this, 0);
m_uploader->closeChannel();
}
if (m_deviceInstaller)
disconnect(m_deviceInstaller.data(), 0, this, 0);
emit done();
}
}
void MaemoDeployStep::unmount()
{
if (m_mounter->hasValidMountSpecifications())
m_mounter->unmount();
else
handleUnmounted();
} }
void MaemoDeployStep::handleDeviceInstallerOutput(const QByteArray &output) void MaemoDeployStep::handleDeviceInstallerOutput(const QByteArray &output)
{ {
writeOutput(QString::fromUtf8(output), NormalOutput); ASSERT_STATE(QList<State>() << InstallingToDevice << StopRequested);
switch (m_state) {
case InstallingToDevice:
case StopRequested:
writeOutput(QString::fromUtf8(output), NormalOutput);
break;
default:
break;
}
} }
void MaemoDeployStep::handleDeviceInstallerErrorOutput(const QByteArray &output) void MaemoDeployStep::handleDeviceInstallerErrorOutput(const QByteArray &output)
{ {
writeOutput(QString::fromUtf8(output), ErrorOutput); ASSERT_STATE(QList<State>() << InstallingToDevice << StopRequested);
switch (m_state) {
case InstallingToDevice:
case StopRequested:
writeOutput(QString::fromUtf8(output), ErrorOutput);
break;
default:
break;
}
} }
MaemoDeployEventHandler::MaemoDeployEventHandler(MaemoDeployStep *deployStep, MaemoDeployEventHandler::MaemoDeployEventHandler(MaemoDeployStep *deployStep,
QFutureInterface<bool> &future) QFutureInterface<bool> &future)
: m_deployStep(deployStep), m_future(future), m_eventLoop(new QEventLoop) : m_deployStep(deployStep), m_future(future), m_eventLoop(new QEventLoop),
m_error(false)
{ {
connect(m_deployStep, SIGNAL(done()), this, SLOT(handleDeployingDone())); connect(m_deployStep, SIGNAL(done()), this, SLOT(handleDeployingDone()));
connect(m_deployStep, SIGNAL(error()), this, SLOT(handleDeployingFailed())); connect(m_deployStep, SIGNAL(error()), this, SLOT(handleDeployingFailed()));
@@ -786,18 +938,21 @@ MaemoDeployEventHandler::MaemoDeployEventHandler(MaemoDeployStep *deployStep,
void MaemoDeployEventHandler::handleDeployingDone() void MaemoDeployEventHandler::handleDeployingDone()
{ {
m_eventLoop->exit(0); m_eventLoop->exit(m_error ? 1 : 0);
} }
void MaemoDeployEventHandler::handleDeployingFailed() void MaemoDeployEventHandler::handleDeployingFailed()
{ {
m_eventLoop->exit(1); m_error = true;
} }
void MaemoDeployEventHandler::checkForCanceled() void MaemoDeployEventHandler::checkForCanceled()
{ {
if (m_future.isCanceled()) if (!m_error && m_future.isCanceled()) {
handleDeployingFailed(); QMetaObject::invokeMethod(m_deployStep, "stop");
m_error = true;
handleDeployingDone();
}
} }
} // namespace Internal } // namespace Internal

View File

@@ -83,13 +83,14 @@ public:
bool isDeployToSysrootEnabled() const { return m_deployToSysroot; } bool isDeployToSysrootEnabled() const { return m_deployToSysroot; }
void setDeployToSysrootEnabled(bool deploy) { m_deployToSysroot = deploy; } void setDeployToSysrootEnabled(bool deploy) { m_deployToSysroot = deploy; }
Q_INVOKABLE void stop();
signals: signals:
void done(); void done();
void error(); void error();
private slots: private slots:
void start(); void start();
void stop();
void handleConnected(); void handleConnected();
void handleConnectionFailure(); void handleConnectionFailure();
void handleMounted(); void handleMounted();
@@ -98,13 +99,13 @@ private slots:
void handleMountDebugOutput(const QString &output); void handleMountDebugOutput(const QString &output);
void handleProgressReport(const QString &progressMsg); void handleProgressReport(const QString &progressMsg);
void handleCopyProcessFinished(int exitStatus); void handleCopyProcessFinished(int exitStatus);
void handleCleanupTimeout();
void handleSysrootInstallerFinished(); void handleSysrootInstallerFinished();
void handleSysrootInstallerOutput(); void handleSysrootInstallerOutput();
void handleSysrootInstallerErrorOutput(); void handleSysrootInstallerErrorOutput();
void handleSftpChannelInitialized(); void handleSftpChannelInitialized();
void handleSftpChannelInitializationFailed(const QString &error); void handleSftpChannelInitializationFailed(const QString &error);
void handleSftpJobFinished(Core::SftpJobId job, const QString &error); void handleSftpJobFinished(Core::SftpJobId job, const QString &error);
void handleSftpChannelClosed();
void handleInstallationFinished(int exitStatus); void handleInstallationFinished(int exitStatus);
void handleDeviceInstallerOutput(const QByteArray &output); void handleDeviceInstallerOutput(const QByteArray &output);
void handleDeviceInstallerErrorOutput(const QByteArray &output); void handleDeviceInstallerErrorOutput(const QByteArray &output);
@@ -112,6 +113,13 @@ private slots:
void handlePortListReady(); void handlePortListReady();
private: private:
enum State {
Inactive, StopRequested, InstallingToSysroot, Connecting,
UnmountingOldDirs, UnmountingCurrentDirs, GatheringPorts, Mounting,
InstallingToDevice, UnmountingCurrentMounts, CopyingFile,
InitializingSftp, Uploading
};
MaemoDeployStep(ProjectExplorer::BuildStepList *bc, MaemoDeployStep(ProjectExplorer::BuildStepList *bc,
MaemoDeployStep *other); MaemoDeployStep *other);
virtual bool init(); virtual bool init();
@@ -136,7 +144,9 @@ private:
void unmountOldDirs(); void unmountOldDirs();
void setupMount(); void setupMount();
void prepareSftpConnection(); void prepareSftpConnection();
void runDpkg(const QString &packageFilePath, bool removeAfterInstall); void runDpkg(const QString &packageFilePath);
void setState(State newState);
void unmount();
static const QLatin1String Id; static const QLatin1String Id;
@@ -147,22 +157,17 @@ private:
QScopedPointer<DeviceDeployAction> m_currentDeviceDeployAction; QScopedPointer<DeviceDeployAction> m_currentDeviceDeployAction;
QList<MaemoDeployable> m_filesToCopy; QList<MaemoDeployable> m_filesToCopy;
MaemoRemoteMounter *m_mounter; MaemoRemoteMounter *m_mounter;
QTimer *m_cleanupTimer;
bool m_canStart;
bool m_deployToSysroot; bool m_deployToSysroot;
enum UnmountState { OldDirsUnmount, CurrentDirsUnmount, CurrentMountsUnmount };
UnmountState m_unmountState;
QSharedPointer<Core::SftpChannel> m_uploader; QSharedPointer<Core::SftpChannel> m_uploader;
QSharedPointer<Core::SshRemoteProcess> m_deviceInstaller; QSharedPointer<Core::SshRemoteProcess> m_deviceInstaller;
bool m_stopped;
bool m_needsInstall; bool m_needsInstall;
bool m_connecting;
typedef QPair<MaemoDeployable, QString> DeployablePerHost; typedef QPair<MaemoDeployable, QString> DeployablePerHost;
QHash<DeployablePerHost, QDateTime> m_lastDeployed; QHash<DeployablePerHost, QDateTime> m_lastDeployed;
MaemoDeviceConfigListModel *m_deviceConfigModel; MaemoDeviceConfigListModel *m_deviceConfigModel;
MaemoUsedPortsGatherer *m_portsGatherer; MaemoUsedPortsGatherer *m_portsGatherer;
MaemoPortList m_freePorts; MaemoPortList m_freePorts;
State m_state;
}; };
class MaemoDeployEventHandler : public QObject class MaemoDeployEventHandler : public QObject
@@ -178,9 +183,10 @@ private slots:
void checkForCanceled(); void checkForCanceled();
private: private:
const MaemoDeployStep * const m_deployStep; MaemoDeployStep * const m_deployStep;
const QFutureInterface<bool> m_future; const QFutureInterface<bool> m_future;
QEventLoop * const m_eventLoop; QEventLoop * const m_eventLoop;
bool m_error;
}; };
} // namespace Internal } // namespace Internal