1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt Creator.
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and The Qt Company. For licensing terms
13 ** and conditions see https://www.qt.io/terms-conditions. For further
14 ** information use the contact form at https://www.qt.io/contact-us.
15 **
16 ** GNU General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU
18 ** General Public License version 3 as published by the Free Software
19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 ** included in the packaging of this file. Please review the following
21 ** information to ensure the GNU General Public License requirements will
22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 **
24 ****************************************************************************/
25 
26 #include "remotelinuxpackageinstaller.h"
27 
28 #include <utils/qtcassert.h>
29 #include <utils/fileutils.h>
30 #include <ssh/sshremoteprocessrunner.h>
31 
32 using namespace ProjectExplorer;
33 using namespace QSsh;
34 
35 namespace RemoteLinux {
36 namespace Internal {
37 
38 class AbstractRemoteLinuxPackageInstallerPrivate
39 {
40 public:
41     bool isRunning = false;
42     IDevice::ConstPtr deviceConfig;
43     SshRemoteProcessRunner *installer = nullptr;
44     SshRemoteProcessRunner *killProcess = nullptr;
45 };
46 
47 } // namespace Internal
48 
AbstractRemoteLinuxPackageInstaller(QObject * parent)49 AbstractRemoteLinuxPackageInstaller::AbstractRemoteLinuxPackageInstaller(QObject *parent)
50     : QObject(parent), d(new Internal::AbstractRemoteLinuxPackageInstallerPrivate)
51 {
52 }
53 
~AbstractRemoteLinuxPackageInstaller()54 AbstractRemoteLinuxPackageInstaller::~AbstractRemoteLinuxPackageInstaller()
55 {
56     delete d;
57 }
58 
installPackage(const IDevice::ConstPtr & deviceConfig,const QString & packageFilePath,bool removePackageFile)59 void AbstractRemoteLinuxPackageInstaller::installPackage(const IDevice::ConstPtr &deviceConfig,
60     const QString &packageFilePath, bool removePackageFile)
61 {
62     QTC_ASSERT(!d->isRunning, return);
63 
64     d->deviceConfig = deviceConfig;
65     prepareInstallation();
66     if (!d->installer)
67         d->installer = new SshRemoteProcessRunner(this);
68     connect(d->installer, &SshRemoteProcessRunner::connectionError,
69             this, &AbstractRemoteLinuxPackageInstaller::handleConnectionError);
70     connect(d->installer, &SshRemoteProcessRunner::readyReadStandardOutput,
71             this, &AbstractRemoteLinuxPackageInstaller::handleInstallerOutput);
72     connect(d->installer, &SshRemoteProcessRunner::readyReadStandardError,
73             this, &AbstractRemoteLinuxPackageInstaller::handleInstallerErrorOutput);
74     connect(d->installer, &SshRemoteProcessRunner::processClosed,
75             this, &AbstractRemoteLinuxPackageInstaller::handleInstallationFinished);
76 
77     QString cmdLine = installCommandLine(packageFilePath);
78     if (removePackageFile)
79         cmdLine += QLatin1String(" && (rm ") + packageFilePath + QLatin1String(" || :)");
80     d->installer->run(cmdLine, deviceConfig->sshParameters());
81     d->isRunning = true;
82 }
83 
cancelInstallation()84 void AbstractRemoteLinuxPackageInstaller::cancelInstallation()
85 {
86     QTC_ASSERT(d->installer && d->isRunning, return);
87 
88     if (!d->killProcess)
89         d->killProcess = new SshRemoteProcessRunner(this);
90     d->killProcess->run(cancelInstallationCommandLine(), d->deviceConfig->sshParameters());
91     setFinished();
92 }
93 
handleConnectionError()94 void AbstractRemoteLinuxPackageInstaller::handleConnectionError()
95 {
96     if (!d->isRunning)
97         return;
98     emit finished(tr("Connection failure: %1").arg(d->installer->lastConnectionErrorString()));
99     setFinished();
100 }
101 
handleInstallationFinished(const QString & error)102 void AbstractRemoteLinuxPackageInstaller::handleInstallationFinished(const QString &error)
103 {
104     if (!d->isRunning)
105         return;
106 
107     if (!error.isEmpty() || d->installer->processExitCode() != 0)
108         emit finished(tr("Installing package failed."));
109     else if (!errorString().isEmpty())
110         emit finished(errorString());
111     else
112         emit finished();
113 
114     setFinished();
115 }
116 
handleInstallerOutput()117 void AbstractRemoteLinuxPackageInstaller::handleInstallerOutput()
118 {
119     emit stdoutData(QString::fromUtf8(d->installer->readAllStandardOutput()));
120 }
121 
handleInstallerErrorOutput()122 void AbstractRemoteLinuxPackageInstaller::handleInstallerErrorOutput()
123 {
124     emit stderrData(QString::fromUtf8(d->installer->readAllStandardError()));
125 }
126 
setFinished()127 void AbstractRemoteLinuxPackageInstaller::setFinished()
128 {
129     disconnect(d->installer, nullptr, this, nullptr);
130     d->isRunning = false;
131 }
132 
133 
RemoteLinuxTarPackageInstaller(QObject * parent)134 RemoteLinuxTarPackageInstaller::RemoteLinuxTarPackageInstaller(QObject *parent)
135     : AbstractRemoteLinuxPackageInstaller(parent)
136 {
137 }
138 
installCommandLine(const QString & packageFilePath) const139 QString RemoteLinuxTarPackageInstaller::installCommandLine(const QString &packageFilePath) const
140 {
141     return QLatin1String("cd / && tar xvf ") + packageFilePath;
142 }
143 
cancelInstallationCommandLine() const144 QString RemoteLinuxTarPackageInstaller::cancelInstallationCommandLine() const
145 {
146     return QLatin1String("pkill tar");
147 }
148 
149 } // namespace RemoteLinux
150