diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemodeploystepfactory.cpp b/src/plugins/qt4projectmanager/qt-maemo/maemodeploystepfactory.cpp index 699eb47159bd70f554355f2403cd16d158cf1e23..12c837f3f185d685af1aa043b7bfc6f4fcf32e53 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemodeploystepfactory.cpp +++ b/src/plugins/qt4projectmanager/qt-maemo/maemodeploystepfactory.cpp @@ -34,6 +34,7 @@ #include "maemodeploystepfactory.h" #include "maemodeploybymountstep.h" +#include "maemodirectdeviceuploadstep.h" #include "maemoglobal.h" #include "maemoinstalltosysrootstep.h" #include "maemouploadandinstalldeploystep.h" @@ -104,6 +105,8 @@ QString MaemoDeployStepFactory::displayNameForId(const QString &id) const return MaemoInstallRpmPackageToSysrootStep::DisplayName; else if (id == MaemoCopyToSysrootStep::Id) return MaemoCopyToSysrootStep::DisplayName; + else if (id == MaemoDirectDeviceUploadStep::Id) + return MaemoDirectDeviceUploadStep::DisplayName; return QString(); } @@ -135,6 +138,8 @@ BuildStep *MaemoDeployStepFactory::create(BuildStepList *parent, const QString & return new MaemoUploadAndInstallRpmPackageStep(parent); } else if (id == MaemoUploadAndInstallTarPackageStep::Id) { return new MaemoUploadAndInstallTarPackageStep(parent); + } else if (id == MaemoDirectDeviceUploadStep::Id) { + return new MaemoDirectDeviceUploadStep(parent); } return 0; @@ -189,6 +194,9 @@ BuildStep *MaemoDeployStepFactory::clone(BuildStepList *parent, BuildStep *produ } else if (product->id() == MaemoCopyToSysrootStep::Id) { return new MaemoCopyToSysrootStep(parent, qobject_cast<MaemoCopyToSysrootStep *>(product)); + } else if (product->id() == MaemoDirectDeviceUploadStep::Id) { + return new MaemoDirectDeviceUploadStep(parent, + qobject_cast<MaemoDirectDeviceUploadStep *>(product)); } return 0; } diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemodirectdeviceuploadstep.cpp b/src/plugins/qt4projectmanager/qt-maemo/maemodirectdeviceuploadstep.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b7a1b1c3053885375a02c64ad5fc27001a80ff8f --- /dev/null +++ b/src/plugins/qt4projectmanager/qt-maemo/maemodirectdeviceuploadstep.cpp @@ -0,0 +1,217 @@ +#include "maemodirectdeviceuploadstep.h" + +#include "maemodeployable.h" +#include "maemoglobal.h" +#include "qt4maemodeployconfiguration.h" + +#include <utils/ssh/sftpchannel.h> +#include <utils/ssh/sshremoteprocess.h> + +#include <QtCore/QDir> +#include <QtCore/QFileInfo> + +#define ASSERT_BASE_STATE(state) ASSERT_STATE_GENERIC(BaseState, state, baseState()) +#define ASSERT_STATE(state) ASSERT_STATE_GENERIC(ExtendedState, state, m_extendedState) + +using namespace ProjectExplorer; +using namespace Utils; + +namespace Qt4ProjectManager { +namespace Internal { + +MaemoDirectDeviceUploadStep::MaemoDirectDeviceUploadStep(BuildStepList *parent) + : AbstractMaemoDeployStep(parent, Id) +{ + ctor(); +} + +MaemoDirectDeviceUploadStep::MaemoDirectDeviceUploadStep(BuildStepList *parent, + MaemoDirectDeviceUploadStep *other) + : AbstractMaemoDeployStep(parent, other) +{ + ctor(); +} + +MaemoDirectDeviceUploadStep::~MaemoDirectDeviceUploadStep() {} + + +void MaemoDirectDeviceUploadStep::ctor() +{ + setDefaultDisplayName(DisplayName); + m_extendedState = Inactive; +} + +bool MaemoDirectDeviceUploadStep::isDeploymentPossibleInternal(QString &whyNot) const +{ + Q_UNUSED(whyNot); + return true; +} + +bool MaemoDirectDeviceUploadStep::isDeploymentNeeded(const QString &hostName) const +{ + m_filesToUpload.clear(); + const QSharedPointer<MaemoDeployables> deployables + = maemoDeployConfig()->deployables(); + const int deployableCount = deployables->deployableCount(); + for (int i = 0; i < deployableCount; ++i) + checkDeploymentNeeded(hostName, deployables->deployableAt(i)); + return !m_filesToUpload.isEmpty(); +} + +void MaemoDirectDeviceUploadStep::checkDeploymentNeeded(const QString &hostName, + const MaemoDeployable &deployable) const +{ + QFileInfo fileInfo(deployable.localFilePath); + if (fileInfo.isDir()) { + const QStringList files = QDir(deployable.localFilePath) + .entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot); + if (files.isEmpty() && currentlyNeedsDeployment(hostName, deployable)) + m_filesToUpload << deployable; + foreach (const QString &fileName, files) { + const QString localFilePath = deployable.localFilePath + + QLatin1Char('/') + fileName; + const QString remoteDir = deployable.remoteDir + QLatin1Char('/') + + fileInfo.fileName(); + checkDeploymentNeeded(hostName, + MaemoDeployable(localFilePath, remoteDir)); + } + } else if (currentlyNeedsDeployment(hostName, deployable)) { + m_filesToUpload << deployable; + } +} + + +void MaemoDirectDeviceUploadStep::startInternal() +{ + Q_ASSERT(m_extendedState == Inactive); + + m_uploader = connection()->createSftpChannel(); + connect(m_uploader.data(), SIGNAL(initialized()), + SLOT(handleSftpInitialized())); + connect(m_uploader.data(), SIGNAL(initializationFailed(QString)), + SLOT(handleSftpInitializationFailed(QString))); + m_uploader->initialize(); + m_extendedState = InitializingSftp; +} + +void MaemoDirectDeviceUploadStep::handleSftpInitializationFailed(const QString &errorMessage) +{ + ASSERT_STATE(QList<ExtendedState>() << Inactive << InitializingSftp); + + if (m_extendedState == InitializingSftp) { + raiseError(tr("SFTP initialization failed: %1").arg(errorMessage)); + setFinished(); + } +} + +void MaemoDirectDeviceUploadStep::handleSftpInitialized() +{ + ASSERT_STATE(QList<ExtendedState>() << Inactive << InitializingSftp); + if (m_extendedState == InitializingSftp) { + Q_ASSERT(!m_filesToUpload.isEmpty()); + connect(m_uploader.data(), SIGNAL(finished(Utils::SftpJobId, QString)), + SLOT(handleUploadFinished(Utils::SftpJobId,QString))); + uploadNextFile(); + } +} + +void MaemoDirectDeviceUploadStep::uploadNextFile() +{ + if (m_filesToUpload.isEmpty()) { + writeOutput(tr("All files successfully deployed.")); + setFinished(); + return; + } + + const MaemoDeployable &d = m_filesToUpload.first(); + QString dirToCreate = d.remoteDir; + QFileInfo fi(d.localFilePath); + if (fi.isDir()) + dirToCreate += QLatin1Char('/') + fi.fileName(); + const QByteArray command = "mkdir -p " + dirToCreate.toUtf8(); + m_mkdirProc = connection()->createRemoteProcess(command); + connect(m_mkdirProc.data(), SIGNAL(closed(int)), + SLOT(handleMkdirFinished(int))); + // TODO: Connect stderr. + writeOutput(tr("Uploading file '%1'...") + .arg(QDir::toNativeSeparators(d.localFilePath))); + m_mkdirProc->start(); + m_extendedState = Uploading; +} + +void MaemoDirectDeviceUploadStep::handleMkdirFinished(int exitStatus) +{ + ASSERT_STATE(QList<ExtendedState>() << Inactive << Uploading); + if (m_extendedState == Inactive) + return; + + const MaemoDeployable &d = m_filesToUpload.first(); + QFileInfo fi(d.localFilePath); + const QString nativePath = QDir::toNativeSeparators(d.localFilePath); + if (exitStatus != SshRemoteProcess::ExitedNormally + || m_mkdirProc->exitCode() != 0) { + raiseError(tr("Failed to upload file '%1'.").arg(nativePath)); + setFinished(); + } else if (fi.isDir()) { + setDeployed(deviceConfig()->sshParameters().host, d); + m_filesToUpload.removeFirst(); + uploadNextFile(); + } else { + const SftpJobId job = m_uploader->uploadFile(d.localFilePath, + d.remoteDir + QLatin1Char('/') + fi.fileName(), + SftpOverwriteExisting); + if (job == SftpInvalidJob) { + raiseError(tr("Failed to upload file '%1': " + "Could not open for reading.").arg(nativePath)); + setFinished(); + } + } +} + +void MaemoDirectDeviceUploadStep::handleUploadFinished(Utils::SftpJobId jobId, + const QString &errorMsg) +{ + Q_UNUSED(jobId); + + ASSERT_STATE(QList<ExtendedState>() << Inactive << Uploading); + if (m_extendedState == Inactive) + return; + + const MaemoDeployable d = m_filesToUpload.takeFirst(); + if (!errorMsg.isEmpty()) { + raiseError(tr("Upload of file '%1' failed: %2") + .arg(QDir::toNativeSeparators(d.localFilePath), errorMsg)); + setFinished(); + } else { + setDeployed(connection()->connectionParameters().host, d); + uploadNextFile(); + } +} + +void MaemoDirectDeviceUploadStep::stopInternal() +{ + ASSERT_BASE_STATE(StopRequested); + ASSERT_STATE(QList<ExtendedState>() << InitializingSftp << Uploading); + + setFinished(); +} + +void MaemoDirectDeviceUploadStep::setFinished() +{ + m_extendedState = Inactive; + if (m_mkdirProc) { + disconnect(m_mkdirProc.data(), 0, this, 0); + } + if (m_uploader) { + disconnect(m_uploader.data(), 0, this, 0); + m_uploader->closeChannel(); + } + setDeploymentFinished(); +} + +const QString MaemoDirectDeviceUploadStep::Id("MaemoDirectDeviceUploadStep"); +const QString MaemoDirectDeviceUploadStep::DisplayName + = tr("Upload files via SFTP"); + +} // namespace Internal +} // namespace Qt4ProjectManager diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemodirectdeviceuploadstep.h b/src/plugins/qt4projectmanager/qt-maemo/maemodirectdeviceuploadstep.h new file mode 100644 index 0000000000000000000000000000000000000000..57704580c5f2b38dad4b623b3cd3384dabd5981e --- /dev/null +++ b/src/plugins/qt4projectmanager/qt-maemo/maemodirectdeviceuploadstep.h @@ -0,0 +1,62 @@ +#ifndef MAEMODIRECTDEVICEUPLOADSTEP_H +#define MAEMODIRECTDEVICEUPLOADSTEP_H + +#include "abstractmaemodeploystep.h" + +#include <utils/ssh/sftpdefs.h> + +#include <QtCore/QList> +#include <QtCore/QSharedPointer> + +namespace Utils { +class SshRemoteProcess; +class SftpChannel; +} + +namespace Qt4ProjectManager { +namespace Internal { +class MaemoDeployable; + +class MaemoDirectDeviceUploadStep : public AbstractMaemoDeployStep +{ + Q_OBJECT +public: + MaemoDirectDeviceUploadStep(ProjectExplorer::BuildStepList *bc); + MaemoDirectDeviceUploadStep(ProjectExplorer::BuildStepList *bc, + MaemoDirectDeviceUploadStep *other); + ~MaemoDirectDeviceUploadStep(); + + static const QString Id; + static const QString DisplayName; + +private slots: + void handleSftpInitialized(); + void handleSftpInitializationFailed(const QString &errorMessage); + void handleUploadFinished(Utils::SftpJobId jobId, const QString &errorMsg); + void handleMkdirFinished(int exitStatus); + +private: + enum ExtendedState { Inactive, InitializingSftp, Uploading }; + + virtual bool isDeploymentPossibleInternal(QString &whynot) const; + virtual bool isDeploymentNeeded(const QString &hostName) const; + virtual void startInternal(); + virtual void stopInternal(); + virtual const AbstractMaemoPackageCreationStep *packagingStep() const { return 0; } + + void ctor(); + void setFinished(); + void checkDeploymentNeeded(const QString &hostName, + const MaemoDeployable &deployable) const; + void uploadNextFile(); + + QSharedPointer<Utils::SftpChannel> m_uploader; + QSharedPointer<Utils::SshRemoteProcess> m_mkdirProc; + mutable QList<MaemoDeployable> m_filesToUpload; + ExtendedState m_extendedState; +}; + +} // namespace Internal +} // namespace Qt4ProjectManager + +#endif // MAEMODIRECTDEVICEUPLOADSTEP_H diff --git a/src/plugins/qt4projectmanager/qt-maemo/qt-maemo.pri b/src/plugins/qt4projectmanager/qt-maemo/qt-maemo.pri index 0c43ec8ec0bc93643022471eff17558744170a8e..d42d24ad40e9ceab5bab4a70aba32a09d9aa80a7 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/qt-maemo.pri +++ b/src/plugins/qt4projectmanager/qt-maemo/qt-maemo.pri @@ -58,7 +58,8 @@ HEADERS += \ $$PWD/maemoremotecopyfacility.h \ $$PWD/abstractmaemodeploystep.h \ $$PWD/maemodeploybymountstep.h \ - $$PWD/maemouploadandinstalldeploystep.h + $$PWD/maemouploadandinstalldeploystep.h \ + $$PWD/maemodirectdeviceuploadstep.h SOURCES += \ $$PWD/maemoconfigtestdialog.cpp \ @@ -117,7 +118,8 @@ SOURCES += \ $$PWD/maemoremotecopyfacility.cpp \ $$PWD/abstractmaemodeploystep.cpp \ $$PWD/maemodeploybymountstep.cpp \ - $$PWD/maemouploadandinstalldeploystep.cpp + $$PWD/maemouploadandinstalldeploystep.cpp \ + $$PWD/maemodirectdeviceuploadstep.cpp FORMS += \ $$PWD/maemoconfigtestdialog.ui \