File: gitplugin.h

package info (click to toggle)
kdevelop 4%3A25.04.0-1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 73,508 kB
  • sloc: cpp: 291,803; python: 4,322; javascript: 3,518; sh: 1,316; ansic: 703; xml: 414; php: 95; lisp: 66; makefile: 31; sed: 12
file content (367 lines) | stat: -rw-r--r-- 15,017 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
/*
    SPDX-FileCopyrightText: 2008 Evgeniy Ivanov <powerfox@kde.ru>
    SPDX-FileCopyrightText: 2009 Hugo Parente Lima <hugo.pl@gmail.com>

    SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/

#ifndef KDEVPLATFORM_PLUGIN_GIT_PLUGIN_H
#define KDEVPLATFORM_PLUGIN_GIT_PLUGIN_H

#include <vcs/interfaces/idistributedversioncontrol.h>
#include <vcs/interfaces/icontentawareversioncontrol.h>
#include <vcs/dvcs/dvcsplugin.h>
#include <vcs/vcsstatusinfo.h>
#include <outputview/outputjob.h>
#include <vcs/vcsjob.h>

#include <QDateTime>

class KDirWatch;
class QDir;

class RepoStatusModel;
class CommitToolViewFactory;

namespace KDevelop
{
    class VcsJob;
    class VcsRevision;
}

class StandardJob : public KDevelop::VcsJob
{
    Q_OBJECT
    public:
        StandardJob(KDevelop::IPlugin* parent, KJob* job, OutputJobVerbosity verbosity);

        QVariant fetchResults() override { return QVariant(); }
        void start() override;
        JobStatus status() const override { return m_status; }
        KDevelop::IPlugin* vcsPlugin() const override { return m_plugin; }

    public Q_SLOTS:
        void result(KJob*);

    private:
        KJob* m_job;
        KDevelop::IPlugin* m_plugin;
        JobStatus m_status;
};

/**
 * This is the main class of KDevelop's Git plugin.
 *
 * It implements the DVCS dependent things not implemented in KDevelop::DistributedVersionControlPlugin
 * @author Evgeniy Ivanov <powerfox@kde.ru>
 */
class GitPlugin: public KDevelop::DistributedVersionControlPlugin, public KDevelop::IContentAwareVersionControl
{
    Q_OBJECT
    Q_INTERFACES(KDevelop::IBasicVersionControl KDevelop::IDistributedVersionControl KDevelop::IContentAwareVersionControl)
    friend class GitInitTest;
public:

    enum ExtendedState {
        /* Unchanged in index (no staged changes) */
        GitXX = KDevelop::VcsStatusInfo::ItemUserState, // No changes in worktree

               // Changed in worktree, not staged for commit
        GitXM, // Modified in worktree
        GitXD, // Deleted in worktree
        GitXR, // Renamed in worktree
        GitXC, // Copied in worktree

        /* Changes in index (staged changes) */
        GitMX, // No changes in worktree
                  // Changed in worktree, not staged for commit
        GitMM, // Modified in worktree
        GitMD, // Deleted in worktree

        /* Added to index (new item) */
        GitAX, // No changes in worktree
                  // Changes in worktree, not staged for commit
        GitAM, // Modified in worktree
        GitAD, // Deleted in worktree

        /* Deleted from index */
        GitDX, // No changes in worktree (deleted in wt)
        GitDR, // Renamed in worktree
        GitDC, // Copied in worktree

        /* Renamed in index */
        GitRX, // No changes in worktree
        GitRM, // Modified in worktree
        GitRD, // Deleted in worktree

        /* Copied in index */
        GitCX, // No changes in worktree
        GitCM, // Modified in worktree
        GitCD, // Deleted in worktree

        /* Special states */
        GitUntracked, // ? ? --- untracked files
        GitConflicts, // U, AA, DD --- conflicts
        GitInvalid = -1, // not really a state
    };

    /**
     * Enums with values which are used as function arguments
     * instead of bools for better readability.
     *
     * The enums are named ${function_name}Params.
     */
    enum ApplyParams {
        Index = 0,
        WorkTree = 2,
    };

    explicit GitPlugin(QObject* parent, const KPluginMetaData& metaData, const QVariantList& args = QVariantList());
    ~GitPlugin() override;

    void unload() override;

    QString name() const override;

    bool isValidRemoteRepositoryUrl(const QUrl& remoteLocation) override;
    bool isVersionControlled(const QUrl &path) override;

    KDevelop::VcsJob* copy(const QUrl& localLocationSrc, const QUrl& localLocationDstn) override;
    KDevelop::VcsJob* move(const QUrl& localLocationSrc, const QUrl& localLocationDst) override;

    //TODO
    KDevelop::VcsJob* pull(const KDevelop::VcsLocation& localOrRepoLocationSrc, const QUrl& localRepositoryLocation) override;
    KDevelop::VcsJob* push(const QUrl& localRepositoryLocation, const KDevelop::VcsLocation& localOrRepoLocationDst) override;
    KDevelop::VcsJob* repositoryLocation(const QUrl& localLocation) override;
    KDevelop::VcsJob* resolve(const QList<QUrl>& localLocations, RecursionMode recursion) override;
    KDevelop::VcsJob* update(const QList<QUrl>& localLocations, const KDevelop::VcsRevision& rev, RecursionMode recursion) override;
    KDevelop::VcsLocationWidget* vcsLocation(QWidget* parent) const override;
    void setupCommitMessageEditor(const QUrl& localLocation, KTextEdit* editor) const override;
    //End of

    KDevelop::VcsJob* add(const QList<QUrl>& localLocations,
                          KDevelop::IBasicVersionControl::RecursionMode recursion = KDevelop::IBasicVersionControl::Recursive) override;
    KDevelop::VcsJob* createWorkingCopy(const KDevelop::VcsLocation & localOrRepoLocationSrc,
                            const QUrl& localRepositoryRoot, KDevelop::IBasicVersionControl::RecursionMode) override;

    KDevelop::VcsJob* remove(const QList<QUrl>& files) override;
    KDevelop::VcsJob* status(const QList<QUrl>& localLocations,
                             KDevelop::IBasicVersionControl::RecursionMode recursion = KDevelop::IBasicVersionControl::Recursive) override;
    KDevelop::VcsJob* commit(const QString& message,
                             const QList<QUrl>& localLocations,
                             KDevelop::IBasicVersionControl::RecursionMode recursion = KDevelop::IBasicVersionControl::Recursive) override;

    /**
     * Commits staged changes to the repo located at repoUrl.
     *
     * @param message the commit message
     * @param repoUrl the url pointing to the repo directory (or a file in the repo)
     */
    KDevelop::VcsJob* commitStaged(const QString& message, const QUrl& repoUrl);

    KDevelop::VcsJob* diff(const QUrl& fileOrDirectory, const KDevelop::VcsRevision& srcRevision, const KDevelop::VcsRevision& dstRevision,
                                   RecursionMode recursion) override;
    /**
     * Shows a diff of changes between srcRevision and dstRevision.
     *
     * @param repoPath a path pointing somewhere inside the repo
     * @param srcRevision the source revision
     * @param dstRevision the destination revision
     *
     * @note: This differs from the @ref:diff method in @ref:IBasicVersionControl in that it does not require
     * a list of files but automatically shows all changed files
     */
    KDevelop::VcsJob* diff(const QUrl& repoPath, const KDevelop::VcsRevision& srcRevision, const KDevelop::VcsRevision& dstRevision);

    KDevelop::VcsJob* log( const QUrl& localLocation, const KDevelop::VcsRevision& rev, unsigned long limit) override;
    KDevelop::VcsJob* log(const QUrl& localLocation, const KDevelop::VcsRevision& rev, const KDevelop::VcsRevision& limit) override;
    KDevelop::VcsJob* annotate(const QUrl &localLocation, const KDevelop::VcsRevision &rev) override;
    KDevelop::VcsJob* revert(const QList<QUrl>& localLocations, RecursionMode recursion) override;

    /**
     * Resets all changes in the specified files which were "staged for commit".
     *
     * @param localLocations the local files/dirs changes to which should be reset
     * @param recursion defines whether changes should be reset recursively in all files
     * in a directory, if localLocations contain a directory
     */
    KDevelop::VcsJob* reset(const QList<QUrl>& localLocations, RecursionMode recursion);

    /**
     * Applies the patch given by a diff to the repo
     *
     * @param diff the patch
     * @param applyTo where to apply the patch (index or worktree)
     */
    KDevelop::VcsJob* apply(const KDevelop::VcsDiff& diff, ApplyParams applyTo = WorkTree);

    // Begin:  KDevelop::IDistributedVersionControl
    KDevelop::VcsJob* init(const QUrl & directory) override;

    // Branch management
    KDevelop::VcsJob* tag(const QUrl& repository, const QString& commitMessage, const KDevelop::VcsRevision& rev, const QString& tagName) override;
    KDevelop::VcsJob* branch(const QUrl& repository, const KDevelop::VcsRevision& rev, const QString& branchName) override;
    KDevelop::VcsJob* branches(const QUrl& repository) override;
    KDevelop::VcsJob* currentBranch(const QUrl& repository) override;
    KDevelop::VcsJob* deleteBranch(const QUrl& repository, const QString& branchName) override;
    KDevelop::VcsJob* switchBranch(const QUrl& repository, const QString& branchName) override;
    KDevelop::VcsJob* renameBranch(const QUrl& repository, const QString& oldBranchName, const QString& newBranchName) override;
    KDevelop::VcsJob* mergeBranch(const QUrl& repository, const QString& branchName) override;
    KDevelop::VcsJob* rebase(const QUrl& repository, const QString& branchName);

    //graph helpers
    QVector<KDevelop::DVcsEvent> allCommits(const QString& repo) override;

    //used in log
    void parseLogOutput(const KDevelop::DVcsJob* job,
                        QVector<KDevelop::DVcsEvent>& commits) const override;

    void additionalMenuEntries(QMenu* menu, const QList<QUrl>& urls) override;

    // Stash Management

    /**
     * Structure to hold information about an item on the stash stack
     */
    struct StashItem {
        int stackDepth = -1;        /* Position on the stack */
        QString shortRef;           /* The reflog selector (e.g. stash@{0}) */
        QString parentSHA;          /* The short SHA of the commit on which the stash was made */
        QString parentDescription;  /* A short description of the commit on which the stash was made */
        QString branch;             /* The branch on which the stash was made */
        QString message;            /* The message with which the stash was made */
        QDateTime creationTime;     /* The date-time the stash item was committed */
    };

    /**
     * Returns a job to run `git stash` in the repository @p repository with
     * additional arguments @p args.
     *
     * The @p verbosity parameter will determine whether the job output will
     * be shown in the VCS Output ToolView.
     *
     * For example, a job to silently apply the top-most stashed item to the current
     * tree would be created as follows:
     *
     *      gitStash(repoDir, {QStringLiteral("apply")}, KDevelop::OutputJob::Silent)
     *
     */
    KDevelop::VcsJob* gitStash(const QDir& repository, const QStringList& args, KDevelop::OutputJob::OutputJobVerbosity verbosity);

    /**
     * The result (job->fetchResults()) will be a @ref QList of @ref StashItem s
     *
     * @p repository is the repository to work on
     * @p verbosity  determines whether the job output will be shown in the VCS Output ToolView
     */
    KDevelop::VcsJob* stashList(const QDir& repository, KDevelop::OutputJob::OutputJobVerbosity verbosity = KDevelop::OutputJob::Silent);

    bool hasStashes(const QDir& repository);
    bool hasModifications(const QDir& repository);
    bool hasModifications(const QDir& repo, const QUrl& file);

    void registerRepositoryForCurrentBranchChanges(const QUrl& repository) override;

    KDevelop::CheckInRepositoryJob* isInRepository(KTextEditor::Document* document) override;

    KDevelop::DVcsJob* setConfigOption(const QUrl& repository, const QString& key, const QString& value, bool global = false);
    QString readConfigOption(const QUrl& repository, const QString& key);

    // this indicates whether the diff() function will generate a diff (patch) which
    // includes the working copy directory name or not (in which case git diff is called
    // with --no-prefix).
    bool usePrefix() const
    {
        return m_usePrefix;
    }

    void setUsePrefix(bool p)
    {
        m_usePrefix = p;
    }
protected:

    QUrl repositoryRoot(const QUrl& path);

    bool isValidDirectory(const QUrl &dirPath) override;

    KDevelop::DVcsJob* lsFiles(const QDir &repository,
                     const QStringList &args,
                     KDevelop::OutputJob::OutputJobVerbosity verbosity = KDevelop::OutputJob::Verbose);
    KDevelop::DVcsJob* gitRevList(const QString &directory,
                        const QStringList &args);
    KDevelop::DVcsJob* gitRevParse(const QString &repository,
                         const QStringList &args,
                         KDevelop::OutputJob::OutputJobVerbosity verbosity = KDevelop::OutputJob::Silent);

private Q_SLOTS:
    void parseGitBlameOutput(KDevelop::DVcsJob *job);
    void parseGitLogOutput(KDevelop::DVcsJob *job);
    void parseGitDiffOutput(KDevelop::DVcsJob* job);
    void parseGitRepoLocationOutput(KDevelop::DVcsJob* job);
    void parseGitStatusOutput(KDevelop::DVcsJob* job);
    void parseGitStatusOutput_old(KDevelop::DVcsJob* job);
    void parseGitVersionOutput(KDevelop::DVcsJob* job);
    void parseGitBranchOutput(KDevelop::DVcsJob* job);
    void parseGitCurrentBranch(KDevelop::DVcsJob* job);
    void parseGitStashList(KDevelop::VcsJob* job);

    void ctxRebase();
    void ctxPushStash();
    void ctxPopStash();
    void ctxStashManager();

    void fileChanged(const QString& file);
    void delayedBranchChanged();

Q_SIGNALS:
    void repositoryBranchChanged(const QUrl& repository);

private:
    bool ensureValidGitIdentity(const QDir& dir);
    void addNotVersionedFiles(const QDir& dir, const QList<QUrl>& files);

    //commit dialog "main" helper
    QStringList getLsFiles(const QDir &directory, const QStringList &args,
        KDevelop::OutputJob::OutputJobVerbosity verbosity);
    KDevelop::DVcsJob* errorsFound(const QString& error, KDevelop::OutputJob::OutputJobVerbosity verbosity);

    void initBranchHash(const QString &repo);

    /**
     * Parses a git status --porcelain line
     *
     * @param statusLine a line as returned by `git status --porcelain`
     * @returns the appropriate extended status
     */
    static ExtendedState parseGitState(QStringView statusLine);

    /**
     * Maps an extended state to a basic state
     *
     * @param state the extended state as provided by git (i.e. describing the combined status in the index & worktree)
     */
    static KDevelop::VcsStatusInfo::State extendedStateToBasic(const ExtendedState state);

    QList<QStringList> branchesShas;
    QList<QUrl> m_urls;

    /** Tells if it's older than 1.7.0 or not */
    bool m_oldVersion = false;

    KDirWatch* m_watcher;
    QList<QUrl> m_branchesChange;
    bool m_usePrefix = true;

    /** A tree model tracking and classifying changes into staged, unstaged and untracked */
    RepoStatusModel* m_repoStatusModel;

    /** A factory for constructing the tool view for preparing commits */
    CommitToolViewFactory* m_commitToolViewFactory;
};

Q_DECLARE_METATYPE(GitPlugin::StashItem)

QVariant runSynchronously(KDevelop::VcsJob* job);

#endif