OSDN Git Service

4719e32f2f711d37663175c6374e9820c2ce3ed7
[qt-creator-jp/qt-creator-jp.git] / src / plugins / perforce / perforcechecker.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 "perforcechecker.h"
35
36 #include <utils/qtcassert.h>
37 #include <utils/synchronousprocess.h>
38
39 #include <QtCore/QRegExp>
40 #include <QtCore/QTimer>
41 #include <QtCore/QFileInfo>
42 #include <QtCore/QDir>
43
44 #include <QtGui/QApplication>
45 #include <QtGui/QCursor>
46
47 namespace Perforce {
48 namespace Internal {
49
50 PerforceChecker::PerforceChecker(QObject *parent) :
51     QObject(parent),
52     m_timeOutMS(-1),
53     m_timedOut(false),
54     m_useOverideCursor(false),
55     m_isOverrideCursor(false)
56 {
57     connect(&m_process, SIGNAL(error(QProcess::ProcessError)),
58             this, SLOT(slotError(QProcess::ProcessError)));
59     connect(&m_process, SIGNAL(finished(int,QProcess::ExitStatus)),
60                 this, SLOT(slotFinished(int,QProcess::ExitStatus)));
61 }
62
63 PerforceChecker::~PerforceChecker()
64 {
65     resetOverrideCursor();
66 }
67
68 bool PerforceChecker::isRunning() const
69 {
70     return m_process.state() == QProcess::Running;
71 }
72
73 void PerforceChecker::resetOverrideCursor()
74 {
75     if (m_isOverrideCursor) {
76         QApplication::restoreOverrideCursor();
77         m_isOverrideCursor = false;
78     }
79 }
80
81 void PerforceChecker::start(const QString &binary,
82                             const QStringList &basicArgs,
83                             int timeoutMS)
84 {
85     if (isRunning()) {
86         emitFailed(QLatin1String("Internal error: process still running"));
87         return;
88     }
89     if (binary.isEmpty()) {
90         emitFailed(tr("No executable specified"));
91         return;
92     }
93     m_binary = binary;
94     QStringList args = basicArgs;
95     args << QLatin1String("client") << QLatin1String("-o");
96     m_process.start(m_binary, args);
97     m_process.closeWriteChannel();
98     // Timeout handling
99     m_timeOutMS = timeoutMS;
100     m_timedOut = false;
101     if (timeoutMS > 0)
102         QTimer::singleShot(m_timeOutMS, this, SLOT(slotTimeOut()));
103     // Cursor
104     if (m_useOverideCursor) {
105         m_isOverrideCursor = true;
106         QApplication::setOverrideCursor(QCursor(Qt::BusyCursor));
107     }
108 }
109
110 void PerforceChecker::slotTimeOut()
111 {
112     if (!isRunning())
113         return;
114     m_timedOut = true;
115     Utils::SynchronousProcess::stopProcess(m_process);
116     emitFailed(tr("\"%1\" timed out after %2ms.").
117                arg(m_binary).arg(m_timeOutMS));
118 }
119
120 void PerforceChecker::slotError(QProcess::ProcessError error)
121 {
122     if (m_timedOut)
123         return;
124     switch (error) {
125     case QProcess::FailedToStart:
126         emitFailed(tr("Unable to launch \"%1\": %2").
127                    arg(QDir::toNativeSeparators(m_binary), m_process.errorString()));
128         break;
129     case QProcess::Crashed: // Handled elsewhere
130     case QProcess::Timedout:
131         break;
132     case QProcess::ReadError:
133     case QProcess::WriteError:
134     case QProcess::UnknownError:
135         Utils::SynchronousProcess::stopProcess(m_process);
136         break;
137     }
138 }
139
140 void PerforceChecker::slotFinished(int exitCode, QProcess::ExitStatus exitStatus)
141 {
142     if (m_timedOut)
143         return;
144     switch (exitStatus) {
145     case QProcess::CrashExit:
146         emitFailed(tr("\"%1\" crashed.").arg(QDir::toNativeSeparators(m_binary)));
147         break;
148     case QProcess::NormalExit:
149         if (exitCode) {
150             const QString stdErr = QString::fromLocal8Bit(m_process.readAllStandardError());
151             emitFailed(tr("\"%1\" terminated with exit code %2: %3").
152                        arg(QDir::toNativeSeparators(m_binary)).arg(exitCode).arg(stdErr));
153         } else {
154             parseOutput(QString::fromLocal8Bit(m_process.readAllStandardOutput()));
155         }
156         break;
157     }
158 }
159
160 // Parse p4 client output for the top level
161 static inline QString clientRootFromOutput(const QString &in)
162 {
163     QRegExp regExp(QLatin1String("(\\n|\\r\\n|\\r)Root:\\s*(.*)(\\n|\\r\\n|\\r)"));
164     QTC_ASSERT(regExp.isValid(), return QString());
165     regExp.setMinimal(true);
166     // Normalize slashes and capitalization of Windows drive letters for caching.
167     if (regExp.indexIn(in) != -1)
168         return QFileInfo(regExp.cap(2).trimmed()).absoluteFilePath();
169     return QString();
170 }
171
172 void PerforceChecker::parseOutput(const QString &response)
173 {
174     if (!response.contains(QLatin1String("View:")) && !response.contains(QLatin1String("//depot/"))) {
175         emitFailed(tr("The client does not seem to contain any mapped files."));
176         return;
177     }
178     const QString repositoryRoot = clientRootFromOutput(response);
179     if (repositoryRoot.isEmpty()) {
180         //: Unable to determine root of the p4 client installation
181         emitFailed(tr("Unable to determine the client root."));
182         return;
183     }
184     // Check existence. No precise check here, might be a symlink
185     const QFileInfo fi(repositoryRoot);
186     if (fi.exists()) {
187         emitSucceeded(repositoryRoot);
188     } else {
189         emitFailed(tr("The repository \"%1\" does not exist.").
190                    arg(QDir::toNativeSeparators(repositoryRoot)));
191     }
192 }
193
194 void PerforceChecker::emitFailed(const QString &m)
195 {
196     resetOverrideCursor();
197     emit failed(m);
198 }
199
200 void PerforceChecker::emitSucceeded(const QString &m)
201 {
202     resetOverrideCursor();
203     emit succeeded(m);
204 }
205
206 bool PerforceChecker::useOverideCursor() const
207 {
208     return m_useOverideCursor;
209 }
210
211 void PerforceChecker::setUseOverideCursor(bool v)
212 {
213     m_useOverideCursor = v;
214 }
215
216 }
217 }
218