/**************************************************************************** ** ** Copyright (C) 2016 Brian McGillion ** Contact: https://www.qt.io/licensing/ ** ** 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 The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ****************************************************************************/ #include "mercurialclient.h" #include "mercurialplugin.h" #include "constants.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Core; using namespace DiffEditor; using namespace Utils; using namespace VcsBase; namespace Mercurial { namespace Internal { class MercurialDiffEditorController : public VcsBaseDiffEditorController { public: MercurialDiffEditorController(IDocument *document) : VcsBaseDiffEditorController(document) { setDisplayName("Hg Diff"); } void runCommand(const QList &args, QTextCodec *codec = nullptr); QStringList addConfigurationArguments(const QStringList &args) const; }; void MercurialDiffEditorController::runCommand(const QList &args, QTextCodec *codec) { // at this moment, don't ignore any errors VcsBaseDiffEditorController::runCommand(args, 0u, codec); } QStringList MercurialDiffEditorController::addConfigurationArguments(const QStringList &args) const { QStringList configArgs{ "-g", "-p" }; configArgs << "-U" << QString::number(contextLineCount()); if (ignoreWhitespace()) { configArgs << "-w" << "-b" << "-B" << "-Z"; } return args + configArgs; } ///////////////////////////////////////////////////////////// MercurialClient::MercurialClient(MercurialSettings *settings) : VcsBaseClient(settings) { } bool MercurialClient::manifestSync(const FilePath &repository, const QString &relativeFilename) { // This only works when called from the repo and outputs paths relative to it. const QStringList args(QLatin1String("manifest")); QtcProcess proc; vcsFullySynchronousExec(proc, repository, args); const QDir repositoryDir(repository.toString()); const QFileInfo needle = QFileInfo(repositoryDir, relativeFilename); const QStringList files = proc.stdOut().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 FilePath &workingDirectory, const QString &srcLocation, const QString &dstLocation, const QStringList &extraOptions) { Q_UNUSED(srcLocation) Q_UNUSED(extraOptions) const unsigned flags = VcsCommand::SshPasswordPrompt | VcsCommand::ShowStdOut | VcsCommand::ShowSuccessMessage; if (workingDirectory.exists()) { // Let's make first init QStringList arguments(QLatin1String("init")); QtcProcess proc; vcsFullySynchronousExec(proc, workingDirectory, arguments); if (proc.result() != QtcProcess::FinishedWithSuccess) return false; // Then pull remote repository arguments.clear(); arguments << QLatin1String("pull") << dstLocation; QtcProcess proc1; vcsSynchronousExec(proc1, workingDirectory, arguments, flags); if (proc1.result() != QtcProcess::FinishedWithSuccess) return false; // By now, there is no hgrc file -> create it FileSaver saver(workingDirectory.pathAppended(".hg/hgrc")); const QString hgrc = QLatin1String("[paths]\ndefault = ") + dstLocation + QLatin1Char('\n'); saver.write(hgrc.toUtf8()); if (!saver.finalize()) { VcsOutputWindow::appendError(saver.errorString()); return false; } // And last update repository arguments.clear(); arguments << QLatin1String("update"); QtcProcess proc2; vcsSynchronousExec(proc2, workingDirectory, arguments, flags); return proc2.result() == QtcProcess::FinishedWithSuccess; } else { QStringList arguments(QLatin1String("clone")); arguments << dstLocation << workingDirectory.parentDir().toString(); QtcProcess proc; vcsSynchronousExec(proc, workingDirectory.parentDir(), arguments, flags); return proc.result() == QtcProcess::FinishedWithSuccess; } } bool MercurialClient::synchronousPull(const FilePath &workingDir, const QString &srcLocation, const QStringList &extraOptions) { QStringList args; args << vcsCommandString(PullCommand) << extraOptions << srcLocation; // Disable UNIX terminals to suppress SSH prompting const unsigned flags = VcsCommand::SshPasswordPrompt | VcsCommand::ShowStdOut | VcsCommand::ShowSuccessMessage; // cause mercurial doesn`t understand LANG Environment env = Environment::systemEnvironment(); env.set("LANGUAGE", "C"); QtcProcess proc; proc.setTimeoutS(vcsTimeoutS()); VcsCommand command(workingDir, env); command.addFlags(flags); command.runCommand(proc, {vcsBinary(), args}); const bool ok = proc.result() == QtcProcess::FinishedWithSuccess; parsePullOutput(proc.stdOut().trimmed()); return ok; } QString MercurialClient::branchQuerySync(const QString &repositoryRoot) { QFile branchFile(repositoryRoot + QLatin1String("/.hg/branch")); if (branchFile.open(QFile::ReadOnly)) { const QByteArray branch = branchFile.readAll().trimmed(); if (!branch.isEmpty()) return QString::fromLocal8Bit(branch); } return QLatin1String("Unknown Branch"); } static QString msgParentRevisionFailed(const FilePath &workingDirectory, const QString &revision, const QString &why) { return MercurialClient::tr("Unable to find parent revisions of %1 in %2: %3"). arg(revision, workingDirectory.toUserOutput(), why); } static inline QString msgParseParentsOutputFailed(const QString &output) { return MercurialClient::tr("Cannot parse output: %1").arg(output); } QStringList MercurialClient::parentRevisionsSync(const FilePath &workingDirectory, const QString &file /* = QString() */, const QString &revision) { QStringList parents; QStringList args; args << QLatin1String("parents") << QLatin1String("-r") <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 FilePath &workingDirectory, const QString &revision, const QString &format) { QStringList args; args << QLatin1String("log") << QLatin1String("-r") <setReloader([controller, args] { controller->runCommand({controller->addConfigurationArguments(args)}); }); controller->setVcsBinary(settings().binaryPath.filePath()); controller->setVcsTimeoutS(settings().timeout.value()); controller->setProcessEnvironment(processEnvironment()); controller->setWorkingDirectory(workingDirectory); VcsBase::setSource(document, sourceCopy); EditorManager::activateEditorForDocument(document); controller->requestReload(); } void MercurialClient::parsePullOutput(const QString &output) { if (output.endsWith(QLatin1String("no changes found"))) return; if (output.endsWith(QLatin1String("(run 'hg update' to get a working copy)"))) { emit needUpdate(); return; } if (output.endsWith(QLatin1String("'hg merge' to merge)"))) emit needMerge(); } } // namespace Internal } // namespace Mercurial