1 /**************************************************************************
3 ** This file is part of Qt Creator
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
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
16 ** GNU Lesser General Public License Usage
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.
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.
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
32 **************************************************************************/
34 #include "perforcechecker.h"
36 #include <utils/qtcassert.h>
37 #include <utils/synchronousprocess.h>
39 #include <QtCore/QRegExp>
40 #include <QtCore/QTimer>
41 #include <QtCore/QFileInfo>
42 #include <QtCore/QDir>
44 #include <QtGui/QApplication>
45 #include <QtGui/QCursor>
50 PerforceChecker::PerforceChecker(QObject *parent) :
54 m_useOverideCursor(false),
55 m_isOverrideCursor(false)
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)));
63 PerforceChecker::~PerforceChecker()
65 resetOverrideCursor();
68 bool PerforceChecker::isRunning() const
70 return m_process.state() == QProcess::Running;
73 void PerforceChecker::resetOverrideCursor()
75 if (m_isOverrideCursor) {
76 QApplication::restoreOverrideCursor();
77 m_isOverrideCursor = false;
81 void PerforceChecker::start(const QString &binary,
82 const QStringList &basicArgs,
86 emitFailed(QLatin1String("Internal error: process still running"));
89 if (binary.isEmpty()) {
90 emitFailed(tr("No executable specified"));
94 QStringList args = basicArgs;
95 args << QLatin1String("client") << QLatin1String("-o");
96 m_process.start(m_binary, args);
97 m_process.closeWriteChannel();
99 m_timeOutMS = timeoutMS;
102 QTimer::singleShot(m_timeOutMS, this, SLOT(slotTimeOut()));
104 if (m_useOverideCursor) {
105 m_isOverrideCursor = true;
106 QApplication::setOverrideCursor(QCursor(Qt::BusyCursor));
110 void PerforceChecker::slotTimeOut()
115 Utils::SynchronousProcess::stopProcess(m_process);
116 emitFailed(tr("\"%1\" timed out after %2ms.").
117 arg(m_binary).arg(m_timeOutMS));
120 void PerforceChecker::slotError(QProcess::ProcessError error)
125 case QProcess::FailedToStart:
126 emitFailed(tr("Unable to launch \"%1\": %2").
127 arg(QDir::toNativeSeparators(m_binary), m_process.errorString()));
129 case QProcess::Crashed: // Handled elsewhere
130 case QProcess::Timedout:
132 case QProcess::ReadError:
133 case QProcess::WriteError:
134 case QProcess::UnknownError:
135 Utils::SynchronousProcess::stopProcess(m_process);
140 void PerforceChecker::slotFinished(int exitCode, QProcess::ExitStatus exitStatus)
144 switch (exitStatus) {
145 case QProcess::CrashExit:
146 emitFailed(tr("\"%1\" crashed.").arg(QDir::toNativeSeparators(m_binary)));
148 case QProcess::NormalExit:
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));
154 parseOutput(QString::fromLocal8Bit(m_process.readAllStandardOutput()));
160 // Parse p4 client output for the top level
161 static inline QString clientRootFromOutput(const QString &in)
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();
172 void PerforceChecker::parseOutput(const QString &response)
174 if (!response.contains(QLatin1String("View:")) && !response.contains(QLatin1String("//depot/"))) {
175 emitFailed(tr("The client does not seem to contain any mapped files."));
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."));
184 // Check existence. No precise check here, might be a symlink
185 const QFileInfo fi(repositoryRoot);
187 emitSucceeded(repositoryRoot);
189 emitFailed(tr("The repository \"%1\" does not exist.").
190 arg(QDir::toNativeSeparators(repositoryRoot)));
194 void PerforceChecker::emitFailed(const QString &m)
196 resetOverrideCursor();
200 void PerforceChecker::emitSucceeded(const QString &m)
202 resetOverrideCursor();
206 bool PerforceChecker::useOverideCursor() const
208 return m_useOverideCursor;
211 void PerforceChecker::setUseOverideCursor(bool v)
213 m_useOverideCursor = v;