subversionclient.cpp 12.3 KB
Newer Older
1
2
/****************************************************************************
**
Eike Ziller's avatar
Eike Ziller committed
3
4
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
5
6
7
8
9
10
11
**
** 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
Eike Ziller's avatar
Eike Ziller committed
12
13
** a written agreement between you and The Qt Company.  For licensing terms and
** conditions see http://www.qt.io/terms-conditions.  For further information
Eike Ziller's avatar
Eike Ziller committed
14
** use the contact form at http://www.qt.io/contact-us.
15
16
17
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
Eike Ziller's avatar
Eike Ziller committed
18
19
20
21
22
23
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24
**
Eike Ziller's avatar
Eike Ziller committed
25
26
** In addition, as a special exception, The Qt Company gives you certain additional
** rights.  These rights are described in The Qt Company LGPL Exception
27
28
29
30
31
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "subversionclient.h"
32
#include "subversionconstants.h"
33
34
#include "subversionplugin.h"
#include "subversionsettings.h"
35

hjk's avatar
hjk committed
36
#include <vcsbase/vcscommand.h>
37
#include <vcsbase/vcsbaseconstants.h>
38
#include <vcsbase/vcsbaseeditor.h>
39
#include <vcsbase/vcsbaseeditorparameterwidget.h>
40
41
#include <vcsbase/vcsbaseplugin.h>
#include <utils/qtcassert.h>
42
#include <utils/synchronousprocess.h>
43
44
45
#include <diffeditor/diffeditorcontroller.h>
#include <diffeditor/diffutils.h>
#include <coreplugin/editormanager/editormanager.h>
46
47
48
49
50
51

#include <QDir>
#include <QFileInfo>
#include <QTextStream>
#include <QDebug>

52
53
using namespace Core;
using namespace DiffEditor;
hjk's avatar
hjk committed
54
55
56
using namespace Utils;
using namespace VcsBase;

57
58
59
namespace Subversion {
namespace Internal {

60
61
62
63
class SubversionLogParameterWidget : public VcsBaseEditorParameterWidget
{
    Q_OBJECT
public:
64
    SubversionLogParameterWidget(VcsBaseClientSettings &settings, QWidget *parent = 0) :
65
66
67
68
        VcsBaseEditorParameterWidget(parent)
    {
        mapSetting(addToggleButton(QLatin1String("--verbose"), tr("Verbose"),
                                   tr("Show files changed in each revision")),
69
                   settings.boolPointer(SubversionSettings::logVerboseKey));
70
71
72
    }
};

73
SubversionClient::SubversionClient() : VcsBaseClient(new SubversionSettings)
74
{
75
    setLogParameterWidgetCreator([this] { return new SubversionLogParameterWidget(settings()); });
76
77
}

hjk's avatar
hjk committed
78
79
80
81
VcsCommand *SubversionClient::createCommitCmd(const QString &repositoryRoot,
                                              const QStringList &files,
                                              const QString &commitMessageFile,
                                              const QStringList &extraOptions) const
82
83
84
{
    const QStringList svnExtraOptions =
            QStringList(extraOptions)
85
            << SubversionClient::addAuthenticationOptions(settings())
86
            << QLatin1String(Constants::NON_INTERACTIVE_OPTION)
87
            << QLatin1String("--encoding") << QLatin1String("UTF-8")
88
89
            << QLatin1String("--file") << commitMessageFile;

hjk's avatar
hjk committed
90
    VcsCommand *cmd = createCommand(repositoryRoot);
Tobias Hunger's avatar
Tobias Hunger committed
91
    cmd->addFlags(VcsCommand::ShowStdOut);
92
    QStringList args(vcsCommandString(CommitCommand));
93
    cmd->addJob(vcsBinary(), args << svnExtraOptions << files);
94
95
96
97
98
99
100
101
102
103
104
    return cmd;
}

void SubversionClient::commit(const QString &repositoryRoot,
                              const QStringList &files,
                              const QString &commitMessageFile,
                              const QStringList &extraOptions)
{
    if (Subversion::Constants::debug)
        qDebug() << Q_FUNC_INFO << commitMessageFile << files;

hjk's avatar
hjk committed
105
    VcsCommand *cmd = createCommitCmd(repositoryRoot, files, commitMessageFile, extraOptions);
106
107
108
    cmd->execute();
}

109
Id SubversionClient::vcsEditorKind(VcsCommandTag cmd) const
110
{
111
112
113
    switch (cmd) {
    case VcsBaseClient::LogCommand: return Constants::SUBVERSION_LOG_EDITOR_ID;
    case VcsBaseClient::AnnotateCommand: return Constants::SUBVERSION_BLAME_EDITOR_ID;
114
    default:
115
        return Id();
116
    }
117
118
119
}

// Add authorization options to the command line arguments.
120
QStringList SubversionClient::addAuthenticationOptions(const VcsBaseClientSettings &settings)
121
{
122
    if (!static_cast<const SubversionSettings &>(settings).hasAuthentication())
123
124
125
126
127
        return QStringList();

    const QString userName = settings.stringValue(SubversionSettings::userKey);
    const QString password = settings.stringValue(SubversionSettings::passwordKey);

128
    if (userName.isEmpty())
129
130
        return QStringList();

131
132
133
134
135
136
137
138
139
140
    QStringList rc;
    rc.push_back(QLatin1String("--username"));
    rc.push_back(userName);
    if (!password.isEmpty()) {
        rc.push_back(QLatin1String("--password"));
        rc.push_back(password);
    }
    return rc;
}

Tobias Hunger's avatar
Tobias Hunger committed
141
142
143
144
145
146
147
148
149
150
151
QString SubversionClient::synchronousTopic(const QString &repository)
{
    QStringList args;
    args << QLatin1String("info");

    QByteArray stdOut;
    if (!vcsFullySynchronousExec(repository, args, &stdOut))
        return QString();

    const QString revisionString = QLatin1String("Revision: ");
    // stdOut is ASCII only (at least in those areas we care about).
152
    QString output = commandOutputFromLocal8Bit(stdOut);
Tobias Hunger's avatar
Tobias Hunger committed
153
154
155
156
157
158
159
    foreach (const QString &line, output.split(QLatin1Char('\n'))) {
        if (line.startsWith(revisionString))
            return QString::fromLatin1("r") + line.mid(revisionString.count());
    }
    return QString();
}

160
class DiffController : public DiffEditorController
161
162
163
{
    Q_OBJECT
public:
164
    DiffController(IDocument *document, const SubversionClient *client, const QString &directory);
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182

    void setFilesList(const QStringList &filesList);
    void setChangeNumber(int changeNumber);

protected:
    void reload();

private slots:
    void slotTextualDiffOutputReceived(const QString &contents);

private:
    QString getDescription() const;
    void postCollectTextualDiffOutput();
    QProcessEnvironment processEnvironment() const;

    const SubversionClient *m_client;
    QString m_workingDirectory;
    QStringList m_filesList;
183
    int m_changeNumber = 0;
184
185
};

186
187
188
DiffController::DiffController(IDocument *document, const SubversionClient *client, const QString &directory) :
    DiffEditorController(document),
    m_client(client),
189
    m_workingDirectory(directory)
190
{
191
    forceContextLineCount(3); // SVN can not change that when using internal diff
192
193
}

194
QProcessEnvironment DiffController::processEnvironment() const
195
196
197
198
{
    return m_client->processEnvironment();
}

199
void DiffController::setFilesList(const QStringList &filesList)
200
201
202
203
204
205
206
{
    if (isReloading())
        return;

    m_filesList = filesList;
}

207
void DiffController::setChangeNumber(int changeNumber)
208
209
210
211
212
213
214
{
    if (isReloading())
        return;

    m_changeNumber = qMax(changeNumber, 0);
}

215
QString DiffController::getDescription() const
216
217
{
    QStringList args(QLatin1String("log"));
218
    args << SubversionClient::addAuthenticationOptions(m_client->settings());
219
220
221
222
    args << QLatin1String("-r");
    args << QString::number(m_changeNumber);
    const SubversionResponse logResponse =
            SubversionPlugin::instance()->runSvn(m_workingDirectory, args,
223
                                                 m_client->vcsTimeoutS(),
Tobias Hunger's avatar
Tobias Hunger committed
224
                                                 VcsCommand::SshPasswordPrompt);
225
226
227
228
229
230
231

    if (logResponse.error)
        return QString();

    return logResponse.stdOut;
}

232
void DiffController::postCollectTextualDiffOutput()
233
{
234
    auto command = new VcsCommand(m_workingDirectory, processEnvironment());
235
    command->setCodec(EditorManager::defaultTextCodec());
236
    connect(command, &VcsCommand::stdOutText, this, &DiffController::slotTextualDiffOutputReceived);
237
238
//    command->addFlags(diffExecutionFlags());

239
    QStringList args;
240
    args << QLatin1String("diff");
241
    args << m_client->addAuthenticationOptions(m_client->settings());
242
    args << QLatin1String("--internal-diff");
243
    if (ignoreWhitespace())
244
245
246
247
248
249
250
251
        args << QLatin1String("-x") << QLatin1String("-uw");
    if (m_changeNumber) {
        args << QLatin1String("-r") << QString::number(m_changeNumber - 1)
             + QLatin1String(":") + QString::number(m_changeNumber);
    } else {
        args << m_filesList;
    }

252
    command->addJob(m_client->vcsBinary(), args, m_client->vcsTimeoutS());
253
254
255
    command->execute();
}

256
void DiffController::slotTextualDiffOutputReceived(const QString &contents)
257
258
{
    bool ok;
259
260
261
    QList<FileData> fileDataList
            = DiffUtils::readPatch(contents, &ok);
    setDiffFiles(fileDataList, m_workingDirectory);
262

263
    reloadFinished(true);
264
265
}

266
void DiffController::reload()
267
268
269
270
{
    const QString description = m_changeNumber
            ? getDescription() : QString();
    postCollectTextualDiffOutput();
271
    setDescription(description);
272
273
}

274
275
276
277
DiffController *SubversionClient::findOrCreateDiffEditor(const QString &documentId,
                                                         const QString &source,
                                                         const QString &title,
                                                         const QString &workingDirectory) const
278
{
279
280
281
    IDocument *document = DiffEditorController::findOrCreateDocument(documentId, title);
    DiffController *controller = qobject_cast<DiffController *>(
                DiffEditorController::controller(document));
282
283
    if (!controller)
        controller = new DiffController(document, this, workingDirectory);
284
    VcsBasePlugin::setSource(document, source);
285
    return controller;
286
287
}

288
void SubversionClient::diff(const QString &workingDirectory, const QStringList &files, const QStringList &extraOptions)
289
{
290
291
    Q_UNUSED(extraOptions);

292
293
294
295
    const QString vcsCmdString = vcsCommandString(DiffCommand);
    const QString documentId = VcsBaseEditor::getTitleId(workingDirectory, files);
    const QString title = vcsEditorTitle(vcsCmdString, documentId);

296
297
298
299
    DiffController *controller = findOrCreateDiffEditor(documentId, workingDirectory, title,
                                                        workingDirectory);
    controller->setFilesList(files);
    controller->requestReload();
300
301
}

302
303
304
305
306
void SubversionClient::log(const QString &workingDir,
                           const QStringList &files,
                           const QStringList &extraOptions,
                           bool enableAnnotationContextMenu)
{
307
    const auto logCount = settings().intValue(SubversionSettings::logCountKey);
308
309
    QStringList svnExtraOptions =
            QStringList(extraOptions)
310
            << SubversionClient::addAuthenticationOptions(settings());
311
312
313
314
315
316
317
318
319
320
321
322
    if (logCount > 0)
        svnExtraOptions << QLatin1String("-l") << QString::number(logCount);

    QStringList nativeFiles;
    foreach (const QString& file, files)
        nativeFiles.append(QDir::toNativeSeparators(file));

    // subversion stores log in UTF-8 and returns it back in user system locale.
    // So we do not need to encode it.
    VcsBaseClient::log(workingDir, files, svnExtraOptions, enableAnnotationContextMenu);
}

323
324
325
326
327
328
329
void SubversionClient::describe(const QString &workingDirectory, int changeNumber, const QString &title)
{
    const QString documentId = VcsBaseEditor::editorTag(DiffOutput,
                                                        workingDirectory,
                                                        QStringList(),
                                                        QString::number(changeNumber));

330
331
332
    DiffController *controller = findOrCreateDiffEditor(documentId, workingDirectory, title, workingDirectory);
    controller->setChangeNumber(changeNumber);
    controller->requestReload();
333
334
335
336
337
338
339
340
341
342
343
344
345
346
}

QString SubversionClient::findTopLevelForFile(const QFileInfo &file) const
{
    Q_UNUSED(file)
    return QString();
}

QStringList SubversionClient::revisionSpec(const QString &revision) const
{
    Q_UNUSED(revision)
    return QStringList();
}

hjk's avatar
hjk committed
347
VcsBaseClient::StatusItem SubversionClient::parseStatusLine(const QString &line) const
348
349
{
    Q_UNUSED(line)
hjk's avatar
hjk committed
350
    return VcsBaseClient::StatusItem();
351
352
353
354
355
356
}

} // namespace Internal
} // namespace Subversion

#include "subversionclient.moc"