OSDN Git Service

Update license.
[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 (info@qt.nokia.com)
8 **
9 **
10 ** GNU Lesser General Public License Usage
11 **
12 ** This file may be used under the terms of the GNU Lesser General Public
13 ** License version 2.1 as published by the Free Software Foundation and
14 ** appearing in the file LICENSE.LGPL included in the packaging of this file.
15 ** Please review the following information to ensure the GNU Lesser General
16 ** Public License version 2.1 requirements will be met:
17 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 **
19 ** In addition, as a special exception, Nokia gives you certain additional
20 ** rights. These rights are described in the Nokia Qt LGPL Exception
21 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 **
23 ** Other Usage
24 **
25 ** Alternatively, this file may be used in accordance with the terms and
26 ** conditions contained in a signed written agreement between you and Nokia.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **************************************************************************/
32
33 #include "perforcechecker.h"
34
35 #include <utils/qtcassert.h>
36 #include <utils/synchronousprocess.h>
37
38 #include <QtCore/QRegExp>
39 #include <QtCore/QTimer>
40 #include <QtCore/QFileInfo>
41 #include <QtCore/QDir>
42
43 #include <QtGui/QApplication>
44 #include <QtGui/QCursor>
45
46 namespace Perforce {
47 namespace Internal {
48
49 PerforceChecker::PerforceChecker(QObject *parent) :
50     QObject(parent),
51     m_timeOutMS(-1),
52     m_timedOut(false),
53     m_useOverideCursor(false),
54     m_isOverrideCursor(false)
55 {
56     connect(&m_process, SIGNAL(error(QProcess::ProcessError)),
57             this, SLOT(slotError(QProcess::ProcessError)));
58     connect(&m_process, SIGNAL(finished(int,QProcess::ExitStatus)),
59                 this, SLOT(slotFinished(int,QProcess::ExitStatus)));
60 }
61
62 PerforceChecker::~PerforceChecker()
63 {
64     resetOverrideCursor();
65 }
66
67 bool PerforceChecker::isRunning() const
68 {
69     return m_process.state() == QProcess::Running;
70 }
71
72 void PerforceChecker::resetOverrideCursor()
73 {
74     if (m_isOverrideCursor) {
75         QApplication::restoreOverrideCursor();
76         m_isOverrideCursor = false;
77     }
78 }
79
80 void PerforceChecker::start(const QString &binary,
81                             const QStringList &basicArgs,
82                             int timeoutMS)
83 {
84     if (isRunning()) {
85         emitFailed(QLatin1String("Internal error: process still running"));
86         return;
87     }
88     if (binary.isEmpty()) {
89         emitFailed(tr("No executable specified"));
90         return;
91     }
92     m_binary = binary;
93     QStringList args = basicArgs;
94     args << QLatin1String("client") << QLatin1String("-o");
95     m_process.start(m_binary, args);
96     m_process.closeWriteChannel();
97     // Timeout handling
98     m_timeOutMS = timeoutMS;
99     m_timedOut = false;
100     if (timeoutMS > 0)
101         QTimer::singleShot(m_timeOutMS, this, SLOT(slotTimeOut()));
102     // Cursor
103     if (m_useOverideCursor) {
104         m_isOverrideCursor = true;
105         QApplication::setOverrideCursor(QCursor(Qt::BusyCursor));
106     }
107 }
108
109 void PerforceChecker::slotTimeOut()
110 {
111     if (!isRunning())
112         return;
113     m_timedOut = true;
114     Utils::SynchronousProcess::stopProcess(m_process);
115     emitFailed(tr("\"%1\" timed out after %2ms.").
116                arg(m_binary).arg(m_timeOutMS));
117 }
118
119 void PerforceChecker::slotError(QProcess::ProcessError error)
120 {
121     if (m_timedOut)
122         return;
123     switch (error) {
124     case QProcess::FailedToStart:
125         emitFailed(tr("Unable to launch \"%1\": %2").
126                    arg(QDir::toNativeSeparators(m_binary), m_process.errorString()));
127         break;
128     case QProcess::Crashed: // Handled elsewhere
129     case QProcess::Timedout:
130         break;
131     case QProcess::ReadError:
132     case QProcess::WriteError:
133     case QProcess::UnknownError:
134         Utils::SynchronousProcess::stopProcess(m_process);
135         break;
136     }
137 }
138
139 void PerforceChecker::slotFinished(int exitCode, QProcess::ExitStatus exitStatus)
140 {
141     if (m_timedOut)
142         return;
143     switch (exitStatus) {
144     case QProcess::CrashExit:
145         emitFailed(tr("\"%1\" crashed.").arg(QDir::toNativeSeparators(m_binary)));
146         break;
147     case QProcess::NormalExit:
148         if (exitCode) {
149             const QString stdErr = QString::fromLocal8Bit(m_process.readAllStandardError());
150             emitFailed(tr("\"%1\" terminated with exit code %2: %3").
151                        arg(QDir::toNativeSeparators(m_binary)).arg(exitCode).arg(stdErr));
152         } else {
153             parseOutput(QString::fromLocal8Bit(m_process.readAllStandardOutput()));
154         }
155         break;
156     }
157 }
158
159 // Parse p4 client output for the top level
160 static inline QString clientRootFromOutput(const QString &in)
161 {
162     QRegExp regExp(QLatin1String("(\\n|\\r\\n|\\r)Root:\\s*(.*)(\\n|\\r\\n|\\r)"));
163     QTC_ASSERT(regExp.isValid(), return QString());
164     regExp.setMinimal(true);
165     // Normalize slashes and capitalization of Windows drive letters for caching.
166     if (regExp.indexIn(in) != -1)
167         return QFileInfo(regExp.cap(2).trimmed()).absoluteFilePath();
168     return QString();
169 }
170
171 void PerforceChecker::parseOutput(const QString &response)
172 {
173     if (!response.contains(QLatin1String("View:")) && !response.contains(QLatin1String("//depot/"))) {
174         emitFailed(tr("The client does not seem to contain any mapped files."));
175         return;
176     }
177     const QString repositoryRoot = clientRootFromOutput(response);
178     if (repositoryRoot.isEmpty()) {
179         //: Unable to determine root of the p4 client installation
180         emitFailed(tr("Unable to determine the client root."));
181         return;
182     }
183     // Check existence. No precise check here, might be a symlink
184     const QFileInfo fi(repositoryRoot);
185     if (fi.exists()) {
186         emitSucceeded(repositoryRoot);
187     } else {
188         emitFailed(tr("The repository \"%1\" does not exist.").
189                    arg(QDir::toNativeSeparators(repositoryRoot)));
190     }
191 }
192
193 void PerforceChecker::emitFailed(const QString &m)
194 {
195     resetOverrideCursor();
196     emit failed(m);
197 }
198
199 void PerforceChecker::emitSucceeded(const QString &m)
200 {
201     resetOverrideCursor();
202     emit succeeded(m);
203 }
204
205 bool PerforceChecker::useOverideCursor() const
206 {
207     return m_useOverideCursor;
208 }
209
210 void PerforceChecker::setUseOverideCursor(bool v)
211 {
212     m_useOverideCursor = v;
213 }
214
215 }
216 }
217