diff --git a/src/plugins/coreplugin/ssh/sftpchannel.h b/src/plugins/coreplugin/ssh/sftpchannel.h index cbdc072283e91e106ab6bcdf1de4757dbf24ef1f..06ad52de5eca7aabb025eff210a6273607bba2d2 100644 --- a/src/plugins/coreplugin/ssh/sftpchannel.h +++ b/src/plugins/coreplugin/ssh/sftpchannel.h @@ -108,6 +108,7 @@ signals: /* * This signal is only emitted by the "List Directory" operation, * one file at a time. + // TODO: Also emit for each file copied by uploadDir(). */ void dataAvailable(SftpJobId job, const QString &data); diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemorunconfiguration.cpp b/src/plugins/qt4projectmanager/qt-maemo/maemorunconfiguration.cpp index 6ab65f99a6a2f8a7f725e2c6634bef93de4949c1..4998112f300fc54787f9f9a2ec443d01c255035e 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemorunconfiguration.cpp +++ b/src/plugins/qt4projectmanager/qt-maemo/maemorunconfiguration.cpp @@ -190,6 +190,12 @@ MaemoDeployStep *MaemoRunConfiguration::deployStep() const return step; } +QString MaemoRunConfiguration::localHostAddressFromDevice() const +{ + // TODO: From user + return QLatin1String("192.168.2.14"); +} + QString MaemoRunConfiguration::maddeRoot() const { if (const MaemoToolChain *tc = toolchain()) diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemorunconfiguration.h b/src/plugins/qt4projectmanager/qt-maemo/maemorunconfiguration.h index 9f2f9b2536d208a8348bcfd8519b32923d3014de..e7fa2c53e8d55c1370a7f0441df647548671e2db 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemorunconfiguration.h +++ b/src/plugins/qt4projectmanager/qt-maemo/maemorunconfiguration.h @@ -75,7 +75,10 @@ public: Qt4BuildConfiguration *activeQt4BuildConfiguration() const; MaemoDeployStep *deployStep() const; + MaemoRemoteMountsModel *remoteMounts() const { return m_remoteMounts; } + QString localHostAddressFromDevice() const; + const MaemoToolChain *toolchain() const; QString maddeRoot() const; QString localExecutableFilePath() const; QString remoteExecutableFilePath() const; @@ -106,7 +109,6 @@ private slots: private: void init(); - const MaemoToolChain *toolchain() const; QString m_proFilePath; mutable QString m_gdbPath; diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemosshrunner.cpp b/src/plugins/qt4projectmanager/qt-maemo/maemosshrunner.cpp index 81b7ded2466aacc8a3879835fac9a3cd5a930a2d..b79898b9896642545995a3737375ec04909498f1 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemosshrunner.cpp +++ b/src/plugins/qt4projectmanager/qt-maemo/maemosshrunner.cpp @@ -35,12 +35,17 @@ #include "maemosshrunner.h" #include "maemodeviceconfigurations.h" +#include "maemoglobal.h" +#include "maemoremotemountsmodel.h" #include "maemorunconfiguration.h" +#include "maemotoolchain.h" +#include <coreplugin/ssh/sftpchannel.h> #include <coreplugin/ssh/sshconnection.h> #include <coreplugin/ssh/sshremoteprocess.h> #include <QtCore/QFileInfo> +#include <QtCore/QProcess> using namespace Core; @@ -50,9 +55,12 @@ namespace Internal { MaemoSshRunner::MaemoSshRunner(QObject *parent, MaemoRunConfiguration *runConfig) : QObject(parent), m_runConfig(runConfig), - m_devConfig(runConfig->deviceConfig()) + m_devConfig(runConfig->deviceConfig()), + m_uploadJobId(SftpInvalidJob) { - m_procsToKill << QFileInfo(m_runConfig->localExecutableFilePath()).fileName(); + m_procsToKill + << QFileInfo(m_runConfig->localExecutableFilePath()).fileName() + << QLatin1String("utfs-client"); } MaemoSshRunner::~MaemoSshRunner() {} @@ -93,10 +101,18 @@ void MaemoSshRunner::stop() disconnect(m_connection.data(), 0, this, 0); if (m_initialCleaner) disconnect(m_initialCleaner.data(), 0, this, 0); + if (m_utfsClientUploader) { + disconnect(m_utfsClientUploader.data(), 0, this, 0); + m_utfsClientUploader->closeChannel(); + } + if (m_mountProcess) { + disconnect(m_mountProcess.data(), 0, this, 0); + m_mountProcess->closeChannel(); + } if (m_runner) { disconnect(m_runner.data(), 0, this, 0); m_runner->closeChannel(); - killRemoteProcs(false); + cleanup(false); } } @@ -105,7 +121,7 @@ void MaemoSshRunner::handleConnected() if (m_stop) return; - killRemoteProcs(true); + cleanup(true); } void MaemoSshRunner::handleConnectionFailure() @@ -114,7 +130,7 @@ void MaemoSshRunner::handleConnectionFailure() .arg(m_connection->errorString())); } -void MaemoSshRunner::killRemoteProcs(bool initialCleanup) +void MaemoSshRunner::cleanup(bool initialCleanup) { QString niceKill; QString brutalKill; @@ -123,6 +139,15 @@ void MaemoSshRunner::killRemoteProcs(bool initialCleanup) brutalKill += QString::fromLocal8Bit("pkill -x -9 %1;").arg(proc); } QString remoteCall = niceKill + QLatin1String("sleep 1; ") + brutalKill; + + const MaemoRemoteMountsModel * const remoteMounts + = m_runConfig->remoteMounts(); + for (int i = 0; i < remoteMounts->mountSpecificationCount(); ++i) { + remoteCall += QString::fromLocal8Bit("%1 umount %2;") + .arg(MaemoGlobal::remoteSudo(), + remoteMounts->mountSpecificationAt(i).remoteMountPoint); + } + remoteCall.remove(remoteCall.count() - 1, 1); // Get rid of trailing semicolon. SshRemoteProcess::Ptr proc = m_connection->createRemoteProcess(remoteCall.toUtf8()); @@ -143,14 +168,142 @@ void MaemoSshRunner::handleInitialCleanupFinished(int exitStatus) if (m_stop) return; + foreach (QProcess *utfsServer, m_utfsServers) { + utfsServer->terminate(); + utfsServer->waitForFinished(1000); + utfsServer->kill(); + } + qDeleteAll(m_utfsServers); if (exitStatus != SshRemoteProcess::ExitedNormally) { emit error(tr("Initial cleanup failed: %1") .arg(m_initialCleaner->errorString())); + } else if (m_runConfig->remoteMounts()->mountSpecificationCount() != 0) { + deployUtfsClient(); } else { emit readyForExecution(); } } +void MaemoSshRunner::deployUtfsClient() +{ + m_utfsClientUploader = m_connection->createSftpChannel(); + connect(m_utfsClientUploader.data(), SIGNAL(initialized()), this, + SLOT(handleUploaderInitialized())); + connect(m_utfsClientUploader.data(), SIGNAL(initializationFailed(QString)), + this, SLOT(handleUploaderInitializationFailed(QString))); + m_utfsClientUploader->initialize(); +} + +void MaemoSshRunner::handleUploaderInitializationFailed(const QString &reason) +{ + if (m_stop) + return; + + emit error(tr("Failed to establish SFTP connection: %1").arg(reason)); +} + +void MaemoSshRunner::handleUploaderInitialized() +{ + if (m_stop) + return; + + connect(m_utfsClientUploader.data(), + SIGNAL(finished(Core::SftpJobId, QString)), this, + SLOT(handleUploadFinished(Core::SftpJobId,QString))); + const MaemoToolChain * const toolChain + = dynamic_cast<const MaemoToolChain *>(m_runConfig->toolchain()); + Q_ASSERT_X(toolChain, Q_FUNC_INFO, + "Impossible: Maemo run configuration has no Maemo Toolchain."); + const QString localFile + = toolChain->maddeRoot() + QLatin1String("/madlib/utfs-client"); + m_uploadJobId + = m_utfsClientUploader->uploadFile(localFile, utfsClientOnDevice(), + SftpOverwriteExisting); + if (m_uploadJobId == SftpInvalidJob) + emit error(tr("Could not upload UTFS client (%1).").arg(localFile)); +} + +void MaemoSshRunner::handleUploadFinished(Core::SftpJobId jobId, + const QString &errorMsg) +{ + if (m_stop) + return; + + if (jobId != m_uploadJobId) { + qWarning("Warning: unknown upload job %d finished.", jobId); + return; + } + + m_uploadJobId = SftpInvalidJob; + if (!errorMsg.isEmpty()) { + emit error(tr("Could not upload UTFS client: %1").arg(errorMsg)); + return; + } + + mount(); +} + +void MaemoSshRunner::mount() +{ + const MaemoRemoteMountsModel * const remoteMounts + = m_runConfig->remoteMounts(); + QString remoteCall(QLatin1String(":")); + for (int i = 0; i < remoteMounts->mountSpecificationCount(); ++i) { + const MaemoRemoteMountsModel::MountSpecification &mountSpec + = remoteMounts->mountSpecificationAt(i); + + QProcess * const utfsServerProc = new QProcess(this); + const QString port = QString::number(mountSpec.port); + const QString localSecretOpt = QLatin1String("-l"); + const QString remoteSecretOpt = QLatin1String("-r"); + const QStringList utfsServerArgs = QStringList() << localSecretOpt + << port << remoteSecretOpt << port << QLatin1String("-b") << port; + utfsServerProc->start(utfsServer(), utfsServerArgs); + if (!utfsServerProc->waitForStarted()) { + emit error(tr("Could not start UTFS server: %1") + .arg(utfsServerProc->errorString())); + return; + } + m_utfsServers << utfsServerProc; + const QString mkdir = QString::fromLocal8Bit("%1 mkdir -p %2") + .arg(MaemoGlobal::remoteSudo(), mountSpec.remoteMountPoint); + const QString utfsClient + = QString::fromLocal8Bit("%1 -l %2 -r %2 -c %3:%2 %4") + .arg(utfsClientOnDevice()).arg(port) + .arg(m_runConfig->localHostAddressFromDevice()) + .arg(mountSpec.remoteMountPoint); + const QLatin1String andOp(" && "); + remoteCall += andOp + mkdir + andOp + utfsClient; + } + + m_mountProcess = m_connection->createRemoteProcess(remoteCall.toUtf8()); + connect(m_mountProcess.data(), SIGNAL(started()), this, + SLOT(handleMountProcessStarted())); + connect(m_mountProcess.data(), SIGNAL(closed(int)), this, + SLOT(handleRemoteProcessFinished(int))); + m_mountProcess->start(); +} + +void MaemoSshRunner::handleMountProcessStarted() +{ + // TODO: Do we get "finished" from utfs-client when it goes into background? + // If so, remnove this slot; readyForExecution() should be emitted from + // handleRemoteProcessFinished() in that case. + if (!m_stop) + emit readyForExecution(); +} + +void MaemoSshRunner::handleMountProcessFinished(int exitStatus) +{ + if (m_stop) + return; + + if (exitStatus != SshRemoteProcess::ExitedNormally) { + emit error(tr("Failure running UTFS client: %1") + .arg(m_mountProcess->errorString())); + } +} + void MaemoSshRunner::startExecution(const QByteArray &remoteCall) { if (m_runConfig->remoteExecutableFilePath().isEmpty()) { @@ -187,6 +340,20 @@ void MaemoSshRunner::handleRemoteProcessFinished(int exitStatus) } } +QString MaemoSshRunner::utfsClientOnDevice() const +{ + return MaemoGlobal::homeDirOnDevice(QLatin1String("developer")) + + QLatin1String("/utfs-client"); +} + +QString MaemoSshRunner::utfsServer() const +{ + const MaemoToolChain * const toolChain + = dynamic_cast<const MaemoToolChain *>(m_runConfig->toolchain()); + Q_ASSERT_X(toolChain, Q_FUNC_INFO, + "Impossible: Maemo run configuration has no Maemo Toolchain."); + return toolChain->maddeRoot() + QLatin1String("/madlib/utfs-server"); +} } // namespace Internal } // namespace Qt4ProjectManager diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemosshrunner.h b/src/plugins/qt4projectmanager/qt-maemo/maemosshrunner.h index 02f80f36ec21227f37bd1de5e13d715fb5d4ea2b..cbfcb36c164dbe33c94e6c1418bf7bf2acdcaa49 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemosshrunner.h +++ b/src/plugins/qt4projectmanager/qt-maemo/maemosshrunner.h @@ -44,6 +44,8 @@ #include <QtCore/QStringList> +QT_FORWARD_DECLARE_CLASS(QProcess) + namespace Core { class SftpChannel; class SshConnection; @@ -84,9 +86,18 @@ private slots: void handleConnectionFailure(); void handleInitialCleanupFinished(int exitStatus); void handleRemoteProcessFinished(int exitStatus); + void handleUploaderInitialized(); + void handleUploaderInitializationFailed(const QString &reason); + void handleUploadFinished(Core::SftpJobId jobId, const QString &error); + void handleMountProcessStarted(); + void handleMountProcessFinished(int exitStatus); private: - void killRemoteProcs(bool initialCleanup); + void cleanup(bool initialCleanup); + void deployUtfsClient(); + void mount(); + QString utfsClientOnDevice() const; + QString utfsServer() const; MaemoRunConfiguration * const m_runConfig; // TODO this pointer can be invalid const MaemoDeviceConfig m_devConfig; @@ -94,7 +105,12 @@ private: QSharedPointer<Core::SshConnection> m_connection; QSharedPointer<Core::SshRemoteProcess> m_runner; QSharedPointer<Core::SshRemoteProcess> m_initialCleaner; + QSharedPointer<Core::SshRemoteProcess> m_mountProcess; + QSharedPointer<Core::SftpChannel> m_utfsClientUploader; QStringList m_procsToKill; + QList<QProcess *> m_utfsServers; + + Core::SftpJobId m_uploadJobId; bool m_stop; };