2022-08-19 15:59:36 +02:00
|
|
|
// Copyright (C) 2016 The Qt Company Ltd.
|
2022-12-21 10:12:09 +01:00
|
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
2013-09-27 15:39:16 +02:00
|
|
|
|
|
|
|
|
#include "subversionclient.h"
|
2014-05-19 18:40:37 +02:00
|
|
|
#include "subversionconstants.h"
|
2014-11-06 13:23:40 +01:00
|
|
|
#include "subversionsettings.h"
|
2023-01-22 17:10:49 +01:00
|
|
|
#include "subversiontr.h"
|
2013-09-27 15:39:16 +02:00
|
|
|
|
2021-05-05 18:21:22 +02:00
|
|
|
#include <coreplugin/editormanager/editormanager.h>
|
|
|
|
|
|
2016-11-07 09:12:42 +01:00
|
|
|
#include <utils/algorithm.h>
|
2022-07-29 14:41:15 +02:00
|
|
|
#include <utils/commandline.h>
|
2022-05-06 12:42:03 +02:00
|
|
|
#include <utils/environment.h>
|
2016-10-25 14:00:18 +02:00
|
|
|
#include <utils/hostosinfo.h>
|
2023-05-03 17:05:35 +02:00
|
|
|
#include <utils/process.h>
|
2022-08-01 10:49:13 +02:00
|
|
|
|
|
|
|
|
#include <vcsbase/vcsbaseconstants.h>
|
|
|
|
|
#include <vcsbase/vcsbasediffeditorcontroller.h>
|
|
|
|
|
#include <vcsbase/vcsbaseeditor.h>
|
|
|
|
|
#include <vcsbase/vcsbaseeditorconfig.h>
|
|
|
|
|
#include <vcsbase/vcsbaseplugin.h>
|
|
|
|
|
#include <vcsbase/vcscommand.h>
|
2016-10-25 14:00:18 +02:00
|
|
|
|
2013-09-27 15:39:16 +02:00
|
|
|
#include <QDir>
|
|
|
|
|
#include <QFileInfo>
|
|
|
|
|
#include <QTextStream>
|
|
|
|
|
#include <QDebug>
|
|
|
|
|
|
2015-01-30 16:59:25 +01:00
|
|
|
using namespace Core;
|
|
|
|
|
using namespace DiffEditor;
|
2014-08-27 18:55:41 +02:00
|
|
|
using namespace Utils;
|
|
|
|
|
using namespace VcsBase;
|
|
|
|
|
|
2013-09-27 15:39:16 +02:00
|
|
|
namespace Subversion {
|
|
|
|
|
namespace Internal {
|
|
|
|
|
|
2016-10-23 04:42:43 +03:00
|
|
|
class SubversionLogConfig : public VcsBaseEditorConfig
|
2015-01-26 15:29:09 +01:00
|
|
|
{
|
|
|
|
|
Q_OBJECT
|
|
|
|
|
public:
|
2023-05-15 13:52:03 +02:00
|
|
|
explicit SubversionLogConfig(QToolBar *toolBar)
|
|
|
|
|
: VcsBaseEditorConfig(toolBar)
|
2015-01-26 15:29:09 +01:00
|
|
|
{
|
2023-01-22 17:10:49 +01:00
|
|
|
mapSetting(addToggleButton("--verbose", Tr::tr("Verbose"),
|
|
|
|
|
Tr::tr("Show files changed in each revision")),
|
2023-05-15 13:52:03 +02:00
|
|
|
&settings().logVerbose);
|
2015-01-26 15:29:09 +01:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2023-05-15 13:52:03 +02:00
|
|
|
SubversionClient::SubversionClient() : VcsBaseClient(&Internal::settings())
|
2013-09-27 15:39:16 +02:00
|
|
|
{
|
2023-05-15 13:52:03 +02:00
|
|
|
setLogConfigCreator([](QToolBar *toolBar) { return new SubversionLogConfig(toolBar); });
|
2013-09-27 15:39:16 +02:00
|
|
|
}
|
|
|
|
|
|
2021-07-30 16:46:27 +02:00
|
|
|
bool SubversionClient::doCommit(const FilePath &repositoryRoot,
|
2019-01-16 23:45:22 +02:00
|
|
|
const QStringList &files,
|
|
|
|
|
const QString &commitMessageFile,
|
|
|
|
|
const QStringList &extraOptions) const
|
2014-05-19 18:40:37 +02:00
|
|
|
{
|
2023-01-17 13:10:21 +02:00
|
|
|
CommandLine args{vcsBinary()};
|
2022-07-29 14:41:15 +02:00
|
|
|
args << vcsCommandString(CommitCommand)
|
|
|
|
|
<< extraOptions
|
2023-01-17 13:10:21 +02:00
|
|
|
<< AddAuthOptions()
|
2022-07-29 14:41:15 +02:00
|
|
|
<< QLatin1String(Constants::NON_INTERACTIVE_OPTION)
|
|
|
|
|
<< QLatin1String("--encoding")
|
|
|
|
|
<< QLatin1String("UTF-8")
|
|
|
|
|
<< QLatin1String("--file")
|
|
|
|
|
<< commitMessageFile
|
|
|
|
|
<< escapeFiles(files);
|
|
|
|
|
const CommandResult result = vcsSynchronousExec(repositoryRoot, args,
|
2022-10-05 19:08:53 +02:00
|
|
|
RunFlags::ShowStdOut | RunFlags::UseEventLoop);
|
2022-07-29 14:41:15 +02:00
|
|
|
return result.result() == ProcessResult::FinishedWithSuccess;
|
2014-05-19 18:40:37 +02:00
|
|
|
}
|
|
|
|
|
|
2021-07-30 16:46:27 +02:00
|
|
|
void SubversionClient::commit(const FilePath &repositoryRoot,
|
2014-05-19 18:40:37 +02:00
|
|
|
const QStringList &files,
|
|
|
|
|
const QString &commitMessageFile,
|
|
|
|
|
const QStringList &extraOptions)
|
|
|
|
|
{
|
|
|
|
|
if (Subversion::Constants::debug)
|
|
|
|
|
qDebug() << Q_FUNC_INFO << commitMessageFile << files;
|
|
|
|
|
|
2019-01-16 23:45:22 +02:00
|
|
|
doCommit(repositoryRoot, files, commitMessageFile, extraOptions);
|
2014-05-19 18:40:37 +02:00
|
|
|
}
|
|
|
|
|
|
2015-02-03 23:52:10 +02:00
|
|
|
Id SubversionClient::vcsEditorKind(VcsCommandTag cmd) const
|
2013-09-27 15:39:16 +02:00
|
|
|
{
|
2015-01-26 15:29:09 +01:00
|
|
|
switch (cmd) {
|
|
|
|
|
case VcsBaseClient::LogCommand: return Constants::SUBVERSION_LOG_EDITOR_ID;
|
|
|
|
|
case VcsBaseClient::AnnotateCommand: return Constants::SUBVERSION_BLAME_EDITOR_ID;
|
2015-01-27 14:33:07 +01:00
|
|
|
default:
|
2015-02-03 23:52:10 +02:00
|
|
|
return Id();
|
2015-01-26 15:29:09 +01:00
|
|
|
}
|
2013-09-27 15:39:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add authorization options to the command line arguments.
|
2023-01-18 10:10:41 +02:00
|
|
|
CommandLine &operator<<(Utils::CommandLine &command, SubversionClient::AddAuthOptions)
|
2013-09-27 15:39:16 +02:00
|
|
|
{
|
2023-05-15 13:52:03 +02:00
|
|
|
if (!settings().hasAuthentication())
|
2023-01-17 13:10:21 +02:00
|
|
|
return command;
|
2014-11-04 17:23:16 +01:00
|
|
|
|
2023-05-15 13:52:03 +02:00
|
|
|
const QString userName = settings().userName();
|
|
|
|
|
const QString password = settings().password();
|
2014-11-04 17:23:16 +01:00
|
|
|
|
2013-09-27 15:39:16 +02:00
|
|
|
if (userName.isEmpty())
|
2023-01-17 13:10:21 +02:00
|
|
|
return command;
|
2014-11-04 17:23:16 +01:00
|
|
|
|
2023-01-17 13:10:21 +02:00
|
|
|
command << "--username" << userName;
|
2013-09-27 15:39:16 +02:00
|
|
|
if (!password.isEmpty()) {
|
2023-01-17 13:10:21 +02:00
|
|
|
command << "--password";
|
|
|
|
|
command.addMaskedArg(password);
|
2013-09-27 15:39:16 +02:00
|
|
|
}
|
2023-01-17 13:10:21 +02:00
|
|
|
return command;
|
2013-09-27 15:39:16 +02:00
|
|
|
}
|
|
|
|
|
|
2021-07-30 16:46:27 +02:00
|
|
|
QString SubversionClient::synchronousTopic(const FilePath &repository) const
|
2014-11-04 16:35:14 +01:00
|
|
|
{
|
|
|
|
|
QStringList args;
|
|
|
|
|
|
2016-10-25 14:00:18 +02:00
|
|
|
QString svnVersionBinary = vcsBinary().toString();
|
|
|
|
|
int pos = svnVersionBinary.lastIndexOf('/');
|
|
|
|
|
if (pos < 0)
|
|
|
|
|
svnVersionBinary.clear();
|
|
|
|
|
else
|
|
|
|
|
svnVersionBinary = svnVersionBinary.left(pos + 1);
|
|
|
|
|
svnVersionBinary.append(HostOsInfo::withExecutableSuffix("svnversion"));
|
2022-09-02 15:12:13 +02:00
|
|
|
const CommandResult result = vcsSynchronousExec(repository,
|
2022-07-29 14:41:15 +02:00
|
|
|
{FilePath::fromString(svnVersionBinary), args});
|
|
|
|
|
if (result.result() == ProcessResult::FinishedWithSuccess)
|
|
|
|
|
return result.cleanedStdOut().trimmed();
|
|
|
|
|
return {};
|
2014-11-04 16:35:14 +01:00
|
|
|
}
|
|
|
|
|
|
2016-11-07 09:12:42 +01:00
|
|
|
QString SubversionClient::escapeFile(const QString &file)
|
|
|
|
|
{
|
|
|
|
|
return (file.contains('@') && !file.endsWith('@')) ? file + '@' : file;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QStringList SubversionClient::escapeFiles(const QStringList &files)
|
|
|
|
|
{
|
|
|
|
|
return Utils::transform(files, &SubversionClient::escapeFile);
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-30 14:50:28 +02:00
|
|
|
class SubversionDiffEditorController : public VcsBaseDiffEditorController
|
2014-11-06 13:23:40 +01:00
|
|
|
{
|
|
|
|
|
Q_OBJECT
|
|
|
|
|
public:
|
2023-01-17 13:10:21 +02:00
|
|
|
SubversionDiffEditorController(IDocument *document);
|
2014-11-06 13:23:40 +01:00
|
|
|
|
|
|
|
|
void setFilesList(const QStringList &filesList);
|
|
|
|
|
void setChangeNumber(int changeNumber);
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
QStringList m_filesList;
|
2015-06-18 15:23:57 +02:00
|
|
|
int m_changeNumber = 0;
|
2014-11-06 13:23:40 +01:00
|
|
|
};
|
|
|
|
|
|
2023-01-17 13:10:21 +02:00
|
|
|
SubversionDiffEditorController::SubversionDiffEditorController(IDocument *document)
|
2022-12-15 14:39:02 +01:00
|
|
|
: VcsBaseDiffEditorController(document)
|
|
|
|
|
{
|
|
|
|
|
setDisplayName("Svn Diff");
|
|
|
|
|
forceContextLineCount(3); // SVN cannot change that when using internal diff
|
|
|
|
|
|
|
|
|
|
using namespace Tasking;
|
|
|
|
|
|
|
|
|
|
const TreeStorage<QString> diffInputStorage = inputStorage();
|
|
|
|
|
|
2023-05-03 16:00:22 +02:00
|
|
|
const auto setupDescription = [this](Process &process) {
|
2023-01-20 03:31:00 +01:00
|
|
|
if (m_changeNumber == 0)
|
|
|
|
|
return TaskAction::StopWithDone;
|
2023-01-17 13:10:21 +02:00
|
|
|
setupCommand(process, {"log", "-r", QString::number(m_changeNumber)});
|
|
|
|
|
CommandLine command = process.commandLine();
|
|
|
|
|
command << SubversionClient::AddAuthOptions();
|
|
|
|
|
process.setCommand(command);
|
2023-01-22 17:10:49 +01:00
|
|
|
setDescription(Tr::tr("Waiting for data..."));
|
2023-01-20 03:31:00 +01:00
|
|
|
return TaskAction::Continue;
|
2022-12-15 14:39:02 +01:00
|
|
|
};
|
2023-05-03 16:00:22 +02:00
|
|
|
const auto onDescriptionDone = [this](const Process &process) {
|
2022-12-15 14:39:02 +01:00
|
|
|
setDescription(process.cleanedStdOut());
|
|
|
|
|
};
|
2023-05-03 16:00:22 +02:00
|
|
|
const auto onDescriptionError = [this](const Process &) {
|
2022-12-15 14:39:02 +01:00
|
|
|
setDescription({});
|
|
|
|
|
};
|
|
|
|
|
|
2023-05-03 16:00:22 +02:00
|
|
|
const auto setupDiff = [this](Process &process) {
|
2023-01-17 13:10:21 +02:00
|
|
|
QStringList args = QStringList{"diff"} << "--internal-diff";
|
2022-12-15 14:39:02 +01:00
|
|
|
if (ignoreWhitespace())
|
|
|
|
|
args << "-x" << "-uw";
|
|
|
|
|
if (m_changeNumber)
|
|
|
|
|
args << "-r" << QString::number(m_changeNumber - 1) + ":" + QString::number(m_changeNumber);
|
|
|
|
|
else
|
|
|
|
|
args << m_filesList;
|
|
|
|
|
|
|
|
|
|
setupCommand(process, args);
|
2023-01-17 13:10:21 +02:00
|
|
|
CommandLine command = process.commandLine();
|
|
|
|
|
command << SubversionClient::AddAuthOptions();
|
|
|
|
|
process.setCommand(command);
|
2022-12-15 14:39:02 +01:00
|
|
|
};
|
2023-05-03 16:00:22 +02:00
|
|
|
const auto onDiffDone = [diffInputStorage](const Process &process) {
|
2023-02-20 20:58:38 +01:00
|
|
|
*diffInputStorage = process.cleanedStdOut();
|
2022-12-15 14:39:02 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const Group root {
|
|
|
|
|
Storage(diffInputStorage),
|
|
|
|
|
parallel,
|
|
|
|
|
Group {
|
|
|
|
|
optional,
|
2023-05-03 14:06:15 +02:00
|
|
|
ProcessTask(setupDescription, onDescriptionDone, onDescriptionError)
|
2022-12-15 14:39:02 +01:00
|
|
|
},
|
|
|
|
|
Group {
|
2023-05-03 14:06:15 +02:00
|
|
|
ProcessTask(setupDiff, onDiffDone),
|
2022-12-15 14:39:02 +01:00
|
|
|
postProcessTask()
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
setReloadRecipe(root);
|
|
|
|
|
}
|
2014-11-06 13:23:40 +01:00
|
|
|
|
2017-06-30 14:50:28 +02:00
|
|
|
void SubversionDiffEditorController::setFilesList(const QStringList &filesList)
|
2014-11-06 13:23:40 +01:00
|
|
|
{
|
|
|
|
|
if (isReloading())
|
|
|
|
|
return;
|
|
|
|
|
|
2016-11-07 09:12:42 +01:00
|
|
|
m_filesList = SubversionClient::escapeFiles(filesList);
|
2014-11-06 13:23:40 +01:00
|
|
|
}
|
|
|
|
|
|
2017-06-30 14:50:28 +02:00
|
|
|
void SubversionDiffEditorController::setChangeNumber(int changeNumber)
|
2014-11-06 13:23:40 +01:00
|
|
|
{
|
|
|
|
|
if (isReloading())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
m_changeNumber = qMax(changeNumber, 0);
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-30 14:50:28 +02:00
|
|
|
SubversionDiffEditorController *SubversionClient::findOrCreateDiffEditor(const QString &documentId,
|
2023-01-20 10:35:45 +01:00
|
|
|
const FilePath &source, const QString &title, const FilePath &workingDirectory)
|
2014-11-06 13:23:40 +01:00
|
|
|
{
|
2023-05-15 13:52:03 +02:00
|
|
|
SubversionSettings &settings = Internal::settings();
|
2015-04-06 15:01:05 +03:00
|
|
|
IDocument *document = DiffEditorController::findOrCreateDocument(documentId, title);
|
2018-09-20 00:57:48 +03:00
|
|
|
auto controller = qobject_cast<SubversionDiffEditorController *>(
|
2015-04-06 15:01:05 +03:00
|
|
|
DiffEditorController::controller(document));
|
2020-02-04 08:11:50 +01:00
|
|
|
if (!controller) {
|
2023-01-17 13:10:21 +02:00
|
|
|
controller = new SubversionDiffEditorController(document);
|
2023-05-15 18:32:01 +02:00
|
|
|
controller->setVcsBinary(settings.binaryPath());
|
2020-02-04 08:11:50 +01:00
|
|
|
controller->setProcessEnvironment(processEnvironment());
|
|
|
|
|
controller->setWorkingDirectory(workingDirectory);
|
|
|
|
|
}
|
2020-01-22 13:29:46 +01:00
|
|
|
VcsBase::setSource(document, source);
|
2017-06-30 14:50:28 +02:00
|
|
|
EditorManager::activateEditorForDocument(document);
|
2015-01-30 16:59:25 +01:00
|
|
|
return controller;
|
2014-11-06 13:23:40 +01:00
|
|
|
}
|
|
|
|
|
|
2022-10-06 12:51:50 +02:00
|
|
|
void SubversionClient::diff(const FilePath &workingDirectory, const QStringList &files,
|
|
|
|
|
const QStringList &extraOptions)
|
2014-11-06 13:23:40 +01:00
|
|
|
{
|
2019-07-23 10:58:00 +02:00
|
|
|
Q_UNUSED(extraOptions)
|
2015-01-06 15:46:58 +01:00
|
|
|
|
2014-11-06 13:23:40 +01:00
|
|
|
const QString vcsCmdString = vcsCommandString(DiffCommand);
|
2016-11-24 09:58:11 +01:00
|
|
|
const QString documentId = QLatin1String(Constants::SUBVERSION_PLUGIN)
|
|
|
|
|
+ QLatin1String(".Diff.") + VcsBaseEditor::getTitleId(workingDirectory, files);
|
2014-11-06 13:23:40 +01:00
|
|
|
const QString title = vcsEditorTitle(vcsCmdString, documentId);
|
|
|
|
|
|
2021-07-30 16:46:27 +02:00
|
|
|
SubversionDiffEditorController *controller =
|
2023-01-20 10:35:45 +01:00
|
|
|
findOrCreateDiffEditor(documentId, workingDirectory, title, workingDirectory);
|
2015-01-30 16:59:25 +01:00
|
|
|
controller->setFilesList(files);
|
|
|
|
|
controller->requestReload();
|
2014-11-06 13:23:40 +01:00
|
|
|
}
|
|
|
|
|
|
2023-01-17 13:10:21 +02:00
|
|
|
void SubversionClient::log(const FilePath &workingDir,
|
|
|
|
|
const QStringList &files,
|
|
|
|
|
const QStringList &extraOptions,
|
|
|
|
|
bool enableAnnotationContextMenu,
|
|
|
|
|
const std::function<void(Utils::CommandLine &)> &addAuthOptions)
|
2015-01-26 15:29:09 +01:00
|
|
|
{
|
2021-03-19 14:19:16 +01:00
|
|
|
auto &settings = static_cast<SubversionSettings &>(this->settings());
|
2023-05-12 16:51:12 +02:00
|
|
|
const int logCount = settings.logCount();
|
2021-03-18 18:23:21 +01:00
|
|
|
QStringList svnExtraOptions = extraOptions;
|
2015-01-26 15:29:09 +01:00
|
|
|
if (logCount > 0)
|
|
|
|
|
svnExtraOptions << QLatin1String("-l") << QString::number(logCount);
|
|
|
|
|
|
|
|
|
|
// subversion stores log in UTF-8 and returns it back in user system locale.
|
|
|
|
|
// So we do not need to encode it.
|
2023-01-17 13:10:21 +02:00
|
|
|
VcsBaseClient::log(workingDir,
|
|
|
|
|
escapeFiles(files),
|
|
|
|
|
svnExtraOptions,
|
|
|
|
|
enableAnnotationContextMenu,
|
|
|
|
|
addAuthOptions);
|
2015-01-26 15:29:09 +01:00
|
|
|
}
|
|
|
|
|
|
2022-10-06 12:51:50 +02:00
|
|
|
void SubversionClient::describe(const FilePath &workingDirectory, int changeNumber,
|
|
|
|
|
const QString &title)
|
2014-11-06 13:23:40 +01:00
|
|
|
{
|
2016-11-24 09:58:11 +01:00
|
|
|
const QString documentId = QLatin1String(Constants::SUBVERSION_PLUGIN)
|
2022-10-06 12:51:50 +02:00
|
|
|
+ QLatin1String(".Describe.") + VcsBaseEditor::editorTag(DiffOutput,
|
|
|
|
|
workingDirectory, {}, QString::number(changeNumber));
|
2014-11-06 13:23:40 +01:00
|
|
|
|
2022-10-06 12:51:50 +02:00
|
|
|
SubversionDiffEditorController *controller = findOrCreateDiffEditor(documentId,
|
2023-01-20 10:35:45 +01:00
|
|
|
workingDirectory, title, workingDirectory);
|
2015-01-30 16:59:25 +01:00
|
|
|
controller->setChangeNumber(changeNumber);
|
|
|
|
|
controller->requestReload();
|
2013-09-27 15:39:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace Internal
|
|
|
|
|
} // namespace Subversion
|
|
|
|
|
|
|
|
|
|
#include "subversionclient.moc"
|