/************************************************************************** ** ** Copyright (c) 2013 Brian McGillion ** Contact: http://www.qt-project.org/legal ** ** This file is part of Qt Creator. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Digia. For licensing terms and ** conditions see http://qt.digia.com/licensing. For further information ** use the contact form at http://qt.digia.com/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Digia gives you certain additional ** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include "mercurialclient.h" #include "constants.h" #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Mercurial { namespace Internal { MercurialClient::MercurialClient(MercurialSettings *settings) : VcsBase::VcsBaseClient(settings) { } MercurialSettings *MercurialClient::settings() const { return dynamic_cast(VcsBase::VcsBaseClient::settings()); } bool MercurialClient::manifestSync(const QString &repository, const QString &relativeFilename) { // This only works when called from the repo and outputs paths relative to it. const QStringList args(QLatin1String("manifest")); QByteArray output; vcsFullySynchronousExec(repository, args, &output); const QDir repositoryDir(repository); const QFileInfo needle = QFileInfo(repositoryDir, relativeFilename); const QStringList files = QString::fromLocal8Bit(output).split(QLatin1Char('\n')); foreach (const QString &fileName, files) { const QFileInfo managedFile(repositoryDir, fileName); if (needle == managedFile) return true; } return false; } //bool MercurialClient::clone(const QString &directory, const QString &url) bool MercurialClient::synchronousClone(const QString &workingDir, const QString &srcLocation, const QString &dstLocation, const QStringList &extraOptions) { Q_UNUSED(workingDir); Q_UNUSED(extraOptions); QDir workingDirectory(srcLocation); QByteArray output; const unsigned flags = VcsBase::VcsBasePlugin::SshPasswordPrompt | VcsBase::VcsBasePlugin::ShowStdOutInLogWindow | VcsBase::VcsBasePlugin::ShowSuccessMessage; if (workingDirectory.exists()) { // Let's make first init QStringList arguments(QLatin1String("init")); if (!vcsFullySynchronousExec(workingDirectory.path(), arguments, &output)) return false; // Then pull remote repository arguments.clear(); arguments << QLatin1String("pull") << dstLocation; const Utils::SynchronousProcessResponse resp1 = vcsSynchronousExec(workingDirectory.path(), arguments, flags); if (resp1.result != Utils::SynchronousProcessResponse::Finished) return false; // By now, there is no hgrc file -> create it Utils::FileSaver saver(workingDirectory.path() + QLatin1String("/.hg/hgrc")); const QString hgrc = QLatin1String("[paths]\ndefault = ") + dstLocation + QLatin1Char('\n'); saver.write(hgrc.toUtf8()); if (!saver.finalize()) { VcsBase::VcsBaseOutputWindow::instance()->appendError(saver.errorString()); return false; } // And last update repository arguments.clear(); arguments << QLatin1String("update"); const Utils::SynchronousProcessResponse resp2 = vcsSynchronousExec(workingDirectory.path(), arguments, flags); return resp2.result == Utils::SynchronousProcessResponse::Finished; } else { QStringList arguments(QLatin1String("clone")); arguments << dstLocation << workingDirectory.dirName(); workingDirectory.cdUp(); const Utils::SynchronousProcessResponse resp = vcsSynchronousExec(workingDirectory.path(), arguments, flags); return resp.result == Utils::SynchronousProcessResponse::Finished; } } bool MercurialClient::synchronousPull(const QString &workingDir, const QString &srcLocation, const QStringList &extraOptions) { QStringList args; args << vcsCommandString(PullCommand) << extraOptions << srcLocation; // Disable UNIX terminals to suppress SSH prompting const unsigned flags = VcsBase::VcsBasePlugin::SshPasswordPrompt | VcsBase::VcsBasePlugin::ShowStdOutInLogWindow | VcsBase::VcsBasePlugin::ShowSuccessMessage; const QString binary = settings()->binaryPath(); const int timeoutSec = settings()->value(settings()->timeoutKey).toInt(); // cause mercurial doesn`t understand LANG QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); env.insert(QLatin1String("LANGUAGE"), QLatin1String("C")); const Utils::SynchronousProcessResponse resp = VcsBase::VcsBasePlugin::runVcs( workingDir, binary, args, timeoutSec * 1000, flags, 0, env); const bool ok = resp.result == Utils::SynchronousProcessResponse::Finished; parsePullOutput(resp.stdOut.trimmed()); return ok; } QString MercurialClient::branchQuerySync(const QString &repositoryRoot) { QByteArray output; if (vcsFullySynchronousExec(repositoryRoot, QStringList(QLatin1String("branch")), &output)) return QTextCodec::codecForLocale()->toUnicode(output).trimmed(); return QLatin1String("Unknown Branch"); } static inline QString msgParentRevisionFailed(const QString &workingDirectory, const QString &revision, const QString &why) { return MercurialClient::tr("Unable to find parent revisions of %1 in %2: %3"). arg(revision, QDir::toNativeSeparators(workingDirectory), why); } static inline QString msgParseParentsOutputFailed(const QString &output) { return MercurialClient::tr("Cannot parse output: %1").arg(output); } QStringList MercurialClient::parentRevisionsSync(const QString &workingDirectory, const QString &file /* = QString() */, const QString &revision) { QStringList parents; QStringList args; args << QLatin1String("parents") << QLatin1String("-r") <appendSilently(msgParentRevisionFailed(workingDirectory, revision, msgParseParentsOutputFailed(output))); return QStringList(); } QStringList changeSets = lines.front().simplified().split(QLatin1Char(' ')); if (changeSets.size() < 2) { outputWindow->appendSilently(msgParentRevisionFailed(workingDirectory, revision, msgParseParentsOutputFailed(output))); return QStringList(); } // Remove revision numbers const QChar colon = QLatin1Char(':'); const QStringList::iterator end = changeSets.end(); QStringList::iterator it = changeSets.begin(); for (++it; it != end; ++it) { const int colonIndex = it->indexOf(colon); if (colonIndex != -1) parents.push_back(it->mid(colonIndex + 1)); } return parents; } // Describe a change using an optional format QString MercurialClient::shortDescriptionSync(const QString &workingDirectory, const QString &revision, const QString &format) { QString description; QStringList args; args << QLatin1String("log") << QLatin1String("-r") <settings()->boolPointer(MercurialSettings::diffIgnoreWhiteSpaceKey)); mapSetting(addToggleButton(QLatin1String("-B"), tr("Ignore Blank Lines")), client->settings()->boolPointer(MercurialSettings::diffIgnoreBlankLinesKey)); } void executeCommand() { m_client->diff(m_params.workingDir, m_params.files, m_params.extraOptions); } private: MercurialClient *m_client; const MercurialDiffParameters m_params; }; VcsBase::VcsBaseEditorParameterWidget *MercurialClient::createDiffEditor( const QString &workingDir, const QStringList &files, const QStringList &extraOptions) { MercurialDiffParameters parameters; parameters.workingDir = workingDir; parameters.files = files; parameters.extraOptions = extraOptions; return new MercurialDiffParameterWidget(this, parameters); } } // namespace Internal } // namespace Mercurial #include "mercurialclient.moc"