OSDN Git Service

a3644355963116172e6aa31f5ce6f91b4565dd4c
[qt-creator-jp/qt-creator-jp.git] / src / libs / utils / ssh / sshremoteprocessrunner.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
8 **
9 ** No Commercial Usage
10 **
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 **
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights.  These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
31 **
32 **************************************************************************/
33
34 #include "sshremoteprocessrunner.h"
35
36 #define ASSERT_STATE(states) assertState(states, Q_FUNC_INFO)
37
38 /*!
39     \class Utils::SshRemoteProcessRunner
40
41     \brief Convenience class for running a remote process over an SSH connection.
42 */
43
44 namespace Utils {
45
46 class SshRemoteProcessRunnerPrivate : public QObject
47 {
48     Q_OBJECT
49 public:
50     SshRemoteProcessRunnerPrivate(const SshConnectionParameters &params,
51         QObject *parent);
52     SshRemoteProcessRunnerPrivate(const SshConnection::Ptr &connection,
53         QObject *parent);
54     void run(const QByteArray &command);
55     QByteArray command() const { return m_command; }
56
57     const SshConnection::Ptr m_connection;
58     SshRemoteProcess::Ptr m_process;
59
60 signals:
61     void connectionError(Utils::SshError);
62     void processStarted();
63     void processOutputAvailable(const QByteArray &output);
64     void processErrorOutputAvailable(const QByteArray &output);
65     void processClosed(int exitStatus);
66
67 private slots:
68     void handleConnected();
69     void handleConnectionError(Utils::SshError error);
70     void handleDisconnected();
71     void handleProcessStarted();
72     void handleProcessFinished(int exitStatus);
73
74 private:
75     enum State { Inactive, Connecting, Connected, ProcessRunning };
76
77     void setState(State state);
78     void assertState(const QList<State> &allowedStates, const char *func);
79     void assertState(State allowedState, const char *func);
80
81     State m_state;
82     QByteArray m_command;
83     const SshConnectionParameters m_params;
84 };
85
86
87 SshRemoteProcessRunnerPrivate::SshRemoteProcessRunnerPrivate(const SshConnectionParameters &params,
88     QObject *parent)
89     : QObject(parent),
90       m_connection(SshConnection::create()),
91       m_state(Inactive),
92       m_params(params)
93 {
94 }
95
96 SshRemoteProcessRunnerPrivate::SshRemoteProcessRunnerPrivate(const SshConnection::Ptr &connection,
97     QObject *parent)
98     : QObject(parent),
99       m_connection(connection),
100       m_state(Inactive),
101       m_params(connection->connectionParameters())
102 {
103 }
104
105 void SshRemoteProcessRunnerPrivate::run(const QByteArray &command)
106 {
107     ASSERT_STATE(Inactive);
108     setState(Connecting);
109
110     m_command = command;
111     connect(m_connection.data(), SIGNAL(error(Utils::SshError)),
112         SLOT(handleConnectionError(Utils::SshError)));
113     connect(m_connection.data(), SIGNAL(disconnected()),
114         SLOT(handleDisconnected()));
115     if (m_connection->state() == SshConnection::Connected) {
116         handleConnected();
117     } else {
118         connect(m_connection.data(), SIGNAL(connected()),
119             SLOT(handleConnected()));
120         m_connection->connectToHost(m_params);
121     }
122 }
123
124 void SshRemoteProcessRunnerPrivate::handleConnected()
125 {
126     ASSERT_STATE(Connecting);
127     setState(Connected);
128
129     m_process = m_connection->createRemoteProcess(m_command);
130     connect(m_process.data(), SIGNAL(started()), SLOT(handleProcessStarted()));
131     connect(m_process.data(), SIGNAL(closed(int)),
132         SLOT(handleProcessFinished(int)));
133     connect(m_process.data(), SIGNAL(outputAvailable(QByteArray)),
134         SIGNAL(processOutputAvailable(QByteArray)));
135     connect(m_process.data(), SIGNAL(errorOutputAvailable(QByteArray)),
136         SIGNAL(processErrorOutputAvailable(QByteArray)));
137     m_process->start();
138 }
139
140 void SshRemoteProcessRunnerPrivate::handleConnectionError(Utils::SshError error)
141 {
142     handleDisconnected();
143     emit connectionError(error);
144 }
145
146 void SshRemoteProcessRunnerPrivate::handleDisconnected()
147 {
148     ASSERT_STATE(QList<State>() << Connecting << Connected << ProcessRunning);
149     setState(Inactive);
150 }
151
152 void SshRemoteProcessRunnerPrivate::handleProcessStarted()
153 {
154     ASSERT_STATE(Connected);
155     setState(ProcessRunning);
156
157     emit processStarted();
158 }
159
160 void SshRemoteProcessRunnerPrivate::handleProcessFinished(int exitStatus)
161 {
162     switch (exitStatus) {
163     case SshRemoteProcess::FailedToStart:
164         ASSERT_STATE(Connected);
165         break;
166     case SshRemoteProcess::KilledBySignal:
167     case SshRemoteProcess::ExitedNormally:
168         ASSERT_STATE(ProcessRunning);
169         break;
170     default:
171         Q_ASSERT_X(false, Q_FUNC_INFO, "Impossible exit status.");
172     }
173     setState(Inactive);
174     emit processClosed(exitStatus);
175 }
176
177 void SshRemoteProcessRunnerPrivate::setState(State state)
178 {
179     if (m_state != state) {
180         m_state = state;
181         if (m_state == Inactive) {
182             if (m_process)
183                 disconnect(m_process.data(), 0, this, 0);
184             disconnect(m_connection.data(), 0, this, 0);
185         }
186     }
187 }
188
189 void SshRemoteProcessRunnerPrivate::assertState(const QList<State> &allowedStates,
190     const char *func)
191 {
192     if (!allowedStates.contains(m_state))
193         qWarning("Unexpected state %d in function %s", m_state, func);
194 }
195
196 void SshRemoteProcessRunnerPrivate::assertState(State allowedState,
197     const char *func)
198 {
199     assertState(QList<State>() << allowedState, func);
200 }
201
202
203 SshRemoteProcessRunner::Ptr SshRemoteProcessRunner::create(const SshConnectionParameters &params)
204 {
205     return SshRemoteProcessRunner::Ptr(new SshRemoteProcessRunner(params));
206 }
207
208 SshRemoteProcessRunner::Ptr SshRemoteProcessRunner::create(const SshConnection::Ptr &connection)
209 {
210     return SshRemoteProcessRunner::Ptr(new SshRemoteProcessRunner(connection));
211 }
212
213 SshRemoteProcessRunner::SshRemoteProcessRunner(const SshConnectionParameters &params)
214     : d(new SshRemoteProcessRunnerPrivate(params, this))
215 {
216     init();
217 }
218
219 SshRemoteProcessRunner::SshRemoteProcessRunner(const SshConnection::Ptr &connection)
220     : d(new SshRemoteProcessRunnerPrivate(connection, this))
221 {
222     init();
223 }
224
225 void SshRemoteProcessRunner::init()
226 {
227     connect(d, SIGNAL(connectionError(Utils::SshError)),
228         SIGNAL(connectionError(Utils::SshError)));
229     connect(d, SIGNAL(processStarted()), SIGNAL(processStarted()));
230     connect(d, SIGNAL(processClosed(int)), SIGNAL(processClosed(int)));
231     connect(d, SIGNAL(processOutputAvailable(QByteArray)),
232         SIGNAL(processOutputAvailable(QByteArray)));
233     connect(d, SIGNAL(processErrorOutputAvailable(QByteArray)),
234         SIGNAL(processErrorOutputAvailable(QByteArray)));
235 }
236
237 void SshRemoteProcessRunner::run(const QByteArray &command)
238 {
239     d->run(command);
240 }
241
242 QByteArray SshRemoteProcessRunner::command() const { return d->command(); }
243 SshConnection::Ptr SshRemoteProcessRunner::connection() const { return d->m_connection; }
244 SshRemoteProcess::Ptr SshRemoteProcessRunner::process() const { return d->m_process; }
245
246 } // namespace Utils
247
248
249 #include "sshremoteprocessrunner.moc"