1 /**************************************************************************
3 ** This file is part of Qt Creator
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
7 ** Contact: Nokia Corporation (info@qt.nokia.com)
10 ** GNU Lesser General Public License Usage
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.
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.
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.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
31 **************************************************************************/
33 #include "perforcechecker.h"
35 #include <utils/qtcassert.h>
36 #include <utils/synchronousprocess.h>
38 #include <QtCore/QRegExp>
39 #include <QtCore/QTimer>
40 #include <QtCore/QFileInfo>
41 #include <QtCore/QDir>
43 #include <QtGui/QApplication>
44 #include <QtGui/QCursor>
49 PerforceChecker::PerforceChecker(QObject *parent) :
53 m_useOverideCursor(false),
54 m_isOverrideCursor(false)
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)));
62 PerforceChecker::~PerforceChecker()
64 resetOverrideCursor();
67 bool PerforceChecker::isRunning() const
69 return m_process.state() == QProcess::Running;
72 void PerforceChecker::resetOverrideCursor()
74 if (m_isOverrideCursor) {
75 QApplication::restoreOverrideCursor();
76 m_isOverrideCursor = false;
80 void PerforceChecker::start(const QString &binary,
81 const QStringList &basicArgs,
85 emitFailed(QLatin1String("Internal error: process still running"));
88 if (binary.isEmpty()) {
89 emitFailed(tr("No executable specified"));
93 QStringList args = basicArgs;
94 args << QLatin1String("client") << QLatin1String("-o");
95 m_process.start(m_binary, args);
96 m_process.closeWriteChannel();
98 m_timeOutMS = timeoutMS;
101 QTimer::singleShot(m_timeOutMS, this, SLOT(slotTimeOut()));
103 if (m_useOverideCursor) {
104 m_isOverrideCursor = true;
105 QApplication::setOverrideCursor(QCursor(Qt::BusyCursor));
109 void PerforceChecker::slotTimeOut()
114 Utils::SynchronousProcess::stopProcess(m_process);
115 emitFailed(tr("\"%1\" timed out after %2ms.").
116 arg(m_binary).arg(m_timeOutMS));
119 void PerforceChecker::slotError(QProcess::ProcessError error)
124 case QProcess::FailedToStart:
125 emitFailed(tr("Unable to launch \"%1\": %2").
126 arg(QDir::toNativeSeparators(m_binary), m_process.errorString()));
128 case QProcess::Crashed: // Handled elsewhere
129 case QProcess::Timedout:
131 case QProcess::ReadError:
132 case QProcess::WriteError:
133 case QProcess::UnknownError:
134 Utils::SynchronousProcess::stopProcess(m_process);
139 void PerforceChecker::slotFinished(int exitCode, QProcess::ExitStatus exitStatus)
143 switch (exitStatus) {
144 case QProcess::CrashExit:
145 emitFailed(tr("\"%1\" crashed.").arg(QDir::toNativeSeparators(m_binary)));
147 case QProcess::NormalExit:
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));
153 parseOutput(QString::fromLocal8Bit(m_process.readAllStandardOutput()));
159 // Parse p4 client output for the top level
160 static inline QString clientRootFromOutput(const QString &in)
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();
171 void PerforceChecker::parseOutput(const QString &response)
173 if (!response.contains(QLatin1String("View:")) && !response.contains(QLatin1String("//depot/"))) {
174 emitFailed(tr("The client does not seem to contain any mapped files."));
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."));
183 // Check existence. No precise check here, might be a symlink
184 const QFileInfo fi(repositoryRoot);
186 emitSucceeded(repositoryRoot);
188 emitFailed(tr("The repository \"%1\" does not exist.").
189 arg(QDir::toNativeSeparators(repositoryRoot)));
193 void PerforceChecker::emitFailed(const QString &m)
195 resetOverrideCursor();
199 void PerforceChecker::emitSucceeded(const QString &m)
201 resetOverrideCursor();
205 bool PerforceChecker::useOverideCursor() const
207 return m_useOverideCursor;
210 void PerforceChecker::setUseOverideCursor(bool v)
212 m_useOverideCursor = v;