bazaarclient.cpp 12.5 KB
Newer Older
cerf's avatar
cerf committed
1
2
/**************************************************************************
**
3
** Copyright (c) 2013 Hugues Delorme
hjk's avatar
hjk committed
4
** Contact: http://www.qt-project.org/legal
cerf's avatar
cerf committed
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
cerf's avatar
cerf committed
7
**
hjk's avatar
hjk committed
8
9
10
11
12
13
14
** 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.
cerf's avatar
cerf committed
15
16
**
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17
18
19
20
21
22
23
24
25
** 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
cerf's avatar
cerf committed
26
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
28
****************************************************************************/
cerf's avatar
cerf committed
29
30
31
32
#include "bazaarclient.h"
#include "constants.h"

#include <vcsbase/vcsbaseplugin.h>
33
#include <vcsbase/vcsbaseeditorparameterwidget.h>
34
#include <utils/synchronousprocess.h>
35

36
37
38
#include <QDir>
#include <QFileInfo>
#include <QTextStream>
hjk's avatar
hjk committed
39
#include <QDebug>
cerf's avatar
cerf committed
40
41
42
43

namespace Bazaar {
namespace Internal {

44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
class BazaarDiffExitCodeInterpreter : public Utils::ExitCodeInterpreter
{
    Q_OBJECT
public:
    BazaarDiffExitCodeInterpreter(QObject *parent) : Utils::ExitCodeInterpreter(parent) {}
    Utils::SynchronousProcessResponse::Result interpretExitCode(int code) const;

};

Utils::SynchronousProcessResponse::Result BazaarDiffExitCodeInterpreter::interpretExitCode(int code) const
{
    if (code < 0 || code > 2)
        return Utils::SynchronousProcessResponse::FinishedError;
    return Utils::SynchronousProcessResponse::Finished;
}

60
BazaarClient::BazaarClient(BazaarSettings *settings) :
hjk's avatar
hjk committed
61
    VcsBase::VcsBaseClient(settings)
cerf's avatar
cerf committed
62
63
64
{
}

65
66
BazaarSettings *BazaarClient::settings() const
{
hjk's avatar
hjk committed
67
    return dynamic_cast<BazaarSettings *>(VcsBase::VcsBaseClient::settings());
68
69
}

70
71
72
73
bool BazaarClient::synchronousSetUserId()
{
    QStringList args;
    args << QLatin1String("whoami")
74
75
         << (settings()->stringValue(BazaarSettings::userNameKey) + QLatin1String(" <")
             + settings()->stringValue(BazaarSettings::userEmailKey) + QLatin1Char('>'));
76
77
78
79
    QByteArray stdOut;
    return vcsFullySynchronousExec(QDir::currentPath(), args, &stdOut);
}

cerf's avatar
cerf committed
80
81
82
83
84
85
86
87
88
89
90
BranchInfo BazaarClient::synchronousBranchQuery(const QString &repositoryRoot) const
{
    QFile branchConfFile(repositoryRoot + QDir::separator() +
                         QLatin1String(Constants::BAZAARREPO) +
                         QLatin1String("/branch/branch.conf"));
    if (!branchConfFile.open(QIODevice::ReadOnly))
        return BranchInfo(QString(), false);

    QTextStream ts(&branchConfFile);
    QString branchLocation;
    QString isBranchBound;
91
92
    QRegExp branchLocationRx(QLatin1String("bound_location\\s*=\\s*(.+)$"));
    QRegExp isBranchBoundRx(QLatin1String("bound\\s*=\\s*(.+)$"));
cerf's avatar
cerf committed
93
94
95
96
97
98
99
100
101
102
103
104
    while (!ts.atEnd() && (branchLocation.isEmpty() || isBranchBound.isEmpty())) {
        const QString line = ts.readLine();
        if (branchLocationRx.indexIn(line) != -1)
            branchLocation = branchLocationRx.cap(1);
        else if (isBranchBoundRx.indexIn(line) != -1)
            isBranchBound = isBranchBoundRx.cap(1);
    }
    if (isBranchBound.simplified().toLower() == QLatin1String("true"))
        return BranchInfo(branchLocation, true);
    return BranchInfo(repositoryRoot, false);
}

105
106
107
void BazaarClient::commit(const QString &repositoryRoot, const QStringList &files,
                          const QString &commitMessageFile, const QStringList &extraOptions)
{
hjk's avatar
hjk committed
108
    VcsBaseClient::commit(repositoryRoot, files, commitMessageFile,
109
110
111
112
113
114
115
                          QStringList(extraOptions) << QLatin1String("-F") << commitMessageFile);
}

void BazaarClient::annotate(const QString &workingDir, const QString &file,
                            const QString revision, int lineNumber,
                            const QStringList &extraOptions)
{
hjk's avatar
hjk committed
116
    VcsBaseClient::annotate(workingDir, file, revision, lineNumber,
117
118
119
                            QStringList(extraOptions) << QLatin1String("--long"));
}

cerf's avatar
cerf committed
120
121
122
123
124
QString BazaarClient::findTopLevelForFile(const QFileInfo &file) const
{
    const QString repositoryCheckFile =
            QLatin1String(Constants::BAZAARREPO) + QLatin1String("/branch-format");
    return file.isDir() ?
hjk's avatar
hjk committed
125
                VcsBase::VcsBasePlugin::findRepositoryForDirectory(file.absoluteFilePath(),
cerf's avatar
cerf committed
126
                                                                   repositoryCheckFile) :
hjk's avatar
hjk committed
127
                VcsBase::VcsBasePlugin::findRepositoryForDirectory(file.absolutePath(),
cerf's avatar
cerf committed
128
129
130
                                                                   repositoryCheckFile);
}

131
132
133
134
void BazaarClient::view(const QString &source, const QString &id, const QStringList &extraOptions)
{
    QStringList args(QLatin1String("log"));
    args << QLatin1String("-p") << QLatin1String("-v") << extraOptions;
hjk's avatar
hjk committed
135
    VcsBaseClient::view(source, id, args);
136
137
}

hjk's avatar
hjk committed
138
Core::Id BazaarClient::vcsEditorKind(VcsCommand cmd) const
cerf's avatar
cerf committed
139
{
140
    switch (cmd) {
Tobias Hunger's avatar
Tobias Hunger committed
141
    case AnnotateCommand:
hjk's avatar
hjk committed
142
        return Constants::ANNOTATELOG;
Tobias Hunger's avatar
Tobias Hunger committed
143
    case DiffCommand:
hjk's avatar
hjk committed
144
        return Constants::DIFFLOG;
Tobias Hunger's avatar
Tobias Hunger committed
145
    case LogCommand:
hjk's avatar
hjk committed
146
        return Constants::FILELOG;
Tobias Hunger's avatar
Tobias Hunger committed
147
    default:
hjk's avatar
hjk committed
148
        return Core::Id();
cerf's avatar
cerf committed
149
150
151
    }
}

152
153
154
155
156
157
158
159
160
161
QString BazaarClient::vcsCommandString(VcsCommand cmd) const
{
    switch (cmd) {
    case CloneCommand:
        return QLatin1String("branch");
    default:
        return VcsBaseClient::vcsCommandString(cmd);
    }
}

162
163
164
165
166
167
168
169
170
171
Utils::ExitCodeInterpreter *BazaarClient::exitCodeInterpreter(VcsCommand cmd, QObject *parent) const
{
    switch (cmd) {
    case DiffCommand:
        return new BazaarDiffExitCodeInterpreter(parent);
    default:
        return 0;
    }
}

172
QStringList BazaarClient::revisionSpec(const QString &revision) const
cerf's avatar
cerf committed
173
174
175
176
177
178
179
{
    QStringList args;
    if (!revision.isEmpty())
        args << QLatin1String("-r") << revision;
    return args;
}

180
BazaarClient::StatusItem BazaarClient::parseStatusLine(const QString &line) const
cerf's avatar
cerf committed
181
{
182
    StatusItem item;
cerf's avatar
cerf committed
183
184
185
    if (!line.isEmpty()) {
        const QChar flagVersion = line[0];
        if (flagVersion == QLatin1Char('+'))
186
            item.flags = QLatin1String("Versioned");
cerf's avatar
cerf committed
187
        else if (flagVersion == QLatin1Char('-'))
188
            item.flags = QLatin1String("Unversioned");
cerf's avatar
cerf committed
189
        else if (flagVersion == QLatin1Char('R'))
190
            item.flags = QLatin1String("Renamed");
cerf's avatar
cerf committed
191
        else if (flagVersion == QLatin1Char('?'))
192
            item.flags = QLatin1String("Unknown");
cerf's avatar
cerf committed
193
        else if (flagVersion == QLatin1Char('X'))
194
            item.flags = QLatin1String("Nonexistent");
cerf's avatar
cerf committed
195
        else if (flagVersion == QLatin1Char('C'))
196
            item.flags = QLatin1String("Conflict");
cerf's avatar
cerf committed
197
        else if (flagVersion == QLatin1Char('P'))
198
            item.flags = QLatin1String("PendingMerge");
cerf's avatar
cerf committed
199
200
201
202
203

        const int lineLength = line.length();
        if (lineLength >= 2) {
            const QChar flagContents = line[1];
            if (flagContents == QLatin1Char('N'))
204
                item.flags = QLatin1String("Created");
cerf's avatar
cerf committed
205
            else if (flagContents == QLatin1Char('D'))
206
                item.flags = QLatin1String("Deleted");
cerf's avatar
cerf committed
207
            else if (flagContents == QLatin1Char('K'))
208
                item.flags = QLatin1String("KindChanged");
cerf's avatar
cerf committed
209
            else if (flagContents == QLatin1Char('M'))
210
                item.flags = QLatin1String("Modified");
cerf's avatar
cerf committed
211
212
213
214
        }
        if (lineLength >= 3) {
            const QChar flagExec = line[2];
            if (flagExec == QLatin1Char('*'))
215
                item.flags = QLatin1String("ExecuteBitChanged");
cerf's avatar
cerf committed
216
217
218
        }
        // The status string should be similar to "xxx file_with_changes"
        // so just should take the file name part and store it
219
        item.file = line.mid(4);
cerf's avatar
cerf committed
220
    }
221
    return item;
cerf's avatar
cerf committed
222
223
}

224
225
226
// Collect all parameters required for a diff or log to be able to associate
// them with an editor and re-run the command with parameters.
struct BazaarCommandParameters
227
{
228
229
230
231
232
233
234
    BazaarCommandParameters(const QString &workDir,
                            const QStringList &inFiles,
                            const QStringList &options) :
        workingDir(workDir), files(inFiles), extraOptions(options)
    {
    }

235
236
    QString workingDir;
    QStringList files;
237
    QStringList extraOptions;
238
239
240
};

// Parameter widget controlling whitespace diff mode, associated with a parameter
hjk's avatar
hjk committed
241
class BazaarDiffParameterWidget : public VcsBase::VcsBaseEditorParameterWidget
242
243
244
{
    Q_OBJECT
public:
245
246
    BazaarDiffParameterWidget(BazaarClient *client,
                              const BazaarCommandParameters &p, QWidget *parent = 0) :
hjk's avatar
hjk committed
247
        VcsBase::VcsBaseEditorParameterWidget(parent), m_client(client), m_params(p)
248
    {
249
        mapSetting(addToggleButton(QLatin1String("-w"), tr("Ignore Whitespace")),
250
                   client->settings()->boolPointer(BazaarSettings::diffIgnoreWhiteSpaceKey));
251
        mapSetting(addToggleButton(QLatin1String("-B"), tr("Ignore Blank Lines")),
252
                   client->settings()->boolPointer(BazaarSettings::diffIgnoreBlankLinesKey));
253
    }
254

255
256
257
258
    QStringList arguments() const
    {
        QStringList args;
        // Bazaar wants "--diff-options=-w -B.."
hjk's avatar
hjk committed
259
        const QStringList formatArguments = VcsBaseEditorParameterWidget::arguments();
260
261
        if (!formatArguments.isEmpty()) {
            const QString a = QLatin1String("--diff-options=")
262
                    + formatArguments.join(QString(QLatin1Char(' ')));
263
264
265
266
            args.append(a);
        }
        return args;
    }
267

268
269
270
271
    void executeCommand()
    {
        m_client->diff(m_params.workingDir, m_params.files, m_params.extraOptions);
    }
272
273

private:
274
275
    BazaarClient *m_client;
    const BazaarCommandParameters m_params;
276
277
};

hjk's avatar
hjk committed
278
VcsBase::VcsBaseEditorParameterWidget *BazaarClient::createDiffEditor(
279
        const QString &workingDir, const QStringList &files, const QStringList &extraOptions)
280
{
281
282
    const BazaarCommandParameters parameters(workingDir, files, extraOptions);
    return new BazaarDiffParameterWidget(this, parameters);
283
284
}

hjk's avatar
hjk committed
285
class BazaarLogParameterWidget : public VcsBase::VcsBaseEditorParameterWidget
cerf's avatar
cerf committed
286
287
288
289
290
{
    Q_OBJECT
public:
    BazaarLogParameterWidget(BazaarClient *client,
                             const BazaarCommandParameters &p, QWidget *parent = 0) :
hjk's avatar
hjk committed
291
        VcsBase::VcsBaseEditorParameterWidget(parent), m_client(client), m_params(p)
cerf's avatar
cerf committed
292
293
294
    {
        mapSetting(addToggleButton(QLatin1String("--verbose"), tr("Verbose"),
                                   tr("Show files changed in each revision")),
295
                   m_client->settings()->boolPointer(BazaarSettings::logVerboseKey));
cerf's avatar
cerf committed
296
297
        mapSetting(addToggleButton(QLatin1String("--forward"), tr("Forward"),
                                   tr("Show from oldest to newest")),
298
                   m_client->settings()->boolPointer(BazaarSettings::logForwardKey));
cerf's avatar
cerf committed
299
300
        mapSetting(addToggleButton(QLatin1String("--include-merges"), tr("Include merges"),
                                   tr("Show merged revisions")),
301
                   m_client->settings()->boolPointer(BazaarSettings::logIncludeMergesKey));
cerf's avatar
cerf committed
302
303
304
305
306
307

        QList<ComboBoxItem> logChoices;
        logChoices << ComboBoxItem(tr("Detailed"), QLatin1String("long"))
                   << ComboBoxItem(tr("Moderately short"), QLatin1String("short"))
                   << ComboBoxItem(tr("One line"), QLatin1String("line"))
                   << ComboBoxItem(tr("GNU ChangeLog"), QLatin1String("gnu-changelog"));
308
        mapSetting(addComboBox(QStringList(QLatin1String("--log-format=%1")), logChoices),
309
                   m_client->settings()->stringPointer(BazaarSettings::logFormatKey));
cerf's avatar
cerf committed
310
311
312
313
314
315
316
317
    }

    void executeCommand()
    {
        m_client->log(m_params.workingDir, m_params.files, m_params.extraOptions);
    }

private:
cerf's avatar
cerf committed
318
    BazaarClient *m_client;
cerf's avatar
cerf committed
319
320
321
    const BazaarCommandParameters m_params;
};

hjk's avatar
hjk committed
322
VcsBase::VcsBaseEditorParameterWidget *BazaarClient::createLogEditor(
323
        const QString &workingDir, const QStringList &files, const QStringList &extraOptions)
cerf's avatar
cerf committed
324
325
326
327
328
{
    const BazaarCommandParameters parameters(workingDir, files, extraOptions);
    return new BazaarLogParameterWidget(this, parameters);
}

329
} // namespace Internal
cerf's avatar
cerf committed
330
} // namespace Bazaar
331
332

#include "bazaarclient.moc"