1 /* 2 SPDX-FileCopyrightText: 2008 Evgeniy Ivanov <powerfox@kde.ru> 3 SPDX-FileCopyrightText: 2009 Hugo Parente Lima <hugo.pl@gmail.com> 4 5 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 6 */ 7 8 #ifndef KDEVPLATFORM_PLUGIN_GIT_PLUGIN_H 9 #define KDEVPLATFORM_PLUGIN_GIT_PLUGIN_H 10 11 #include <vcs/interfaces/idistributedversioncontrol.h> 12 #include <vcs/interfaces/icontentawareversioncontrol.h> 13 #include <vcs/dvcs/dvcsplugin.h> 14 #include <vcs/vcsstatusinfo.h> 15 #include <outputview/outputjob.h> 16 #include <vcs/vcsjob.h> 17 18 class KDirWatch; 19 class QDir; 20 21 class RepoStatusModel; 22 class CommitToolViewFactory; 23 24 namespace KDevelop 25 { 26 class VcsJob; 27 class VcsRevision; 28 } 29 30 class StandardJob : public KDevelop::VcsJob 31 { 32 Q_OBJECT 33 public: 34 StandardJob(KDevelop::IPlugin* parent, KJob* job, OutputJobVerbosity verbosity); 35 fetchResults()36 QVariant fetchResults() override { return QVariant(); } 37 void start() override; status()38 JobStatus status() const override { return m_status; } vcsPlugin()39 KDevelop::IPlugin* vcsPlugin() const override { return m_plugin; } 40 41 public Q_SLOTS: 42 void result(KJob*); 43 44 private: 45 KJob* m_job; 46 KDevelop::IPlugin* m_plugin; 47 JobStatus m_status; 48 }; 49 50 /** 51 * This is the main class of KDevelop's Git plugin. 52 * 53 * It implements the DVCS dependent things not implemented in KDevelop::DistributedVersionControlPlugin 54 * @author Evgeniy Ivanov <powerfox@kde.ru> 55 */ 56 class GitPlugin: public KDevelop::DistributedVersionControlPlugin, public KDevelop::IContentAwareVersionControl 57 { 58 Q_OBJECT 59 Q_INTERFACES(KDevelop::IBasicVersionControl KDevelop::IDistributedVersionControl KDevelop::IContentAwareVersionControl) 60 friend class GitInitTest; 61 public: 62 63 enum ExtendedState { 64 /* Unchanged in index (no staged changes) */ 65 GitXX = KDevelop::VcsStatusInfo::ItemUserState, // No changes in worktree 66 67 // Changed in worktree, not staged for commit 68 GitXM, // Modified in worktree 69 GitXD, // Deleted in worktree 70 GitXR, // Renamed in worktree 71 GitXC, // Copied in worktree 72 73 /* Changes in index (staged changes) */ 74 GitMX, // No changes in worktree 75 // Changed in worktree, not staged for commit 76 GitMM, // Modified in worktree 77 GitMD, // Deleted in worktree 78 79 /* Added to index (new item) */ 80 GitAX, // No changes in worktree 81 // Changes in worktree, not staged for commit 82 GitAM, // Modified in worktree 83 GitAD, // Deleted in worktree 84 85 /* Deleted from index */ 86 GitDX, // No changes in worktree (deleted in wt) 87 GitDR, // Renamed in worktree 88 GitDC, // Copied in worktree 89 90 /* Renamed in index */ 91 GitRX, // No changes in worktree 92 GitRM, // Modified in worktree 93 GitRD, // Deleted in worktree 94 95 /* Copied in index */ 96 GitCX, // No changes in worktree 97 GitCM, // Modified in worktree 98 GitCD, // Deleted in worktree 99 100 /* Special states */ 101 GitUntracked, // ? ? --- untracked files 102 GitConflicts, // U, AA, DD --- conflicts 103 GitInvalid = -1, // not really a state 104 }; 105 106 /** 107 * Enums with values which are used as function arguments 108 * instead of bools for better readability. 109 * 110 * The enums are named ${function_name}Params. 111 */ 112 enum ApplyParams { 113 Index = 0, 114 WorkTree = 2, 115 }; 116 117 118 explicit GitPlugin(QObject *parent, const QVariantList & args = QVariantList() ); 119 ~GitPlugin() override; 120 121 QString name() const override; 122 123 bool isValidRemoteRepositoryUrl(const QUrl& remoteLocation) override; 124 bool isVersionControlled(const QUrl &path) override; 125 126 KDevelop::VcsJob* copy(const QUrl& localLocationSrc, const QUrl& localLocationDstn) override; 127 KDevelop::VcsJob* move(const QUrl& localLocationSrc, const QUrl& localLocationDst) override; 128 129 //TODO 130 KDevelop::VcsJob* pull(const KDevelop::VcsLocation& localOrRepoLocationSrc, const QUrl& localRepositoryLocation) override; 131 KDevelop::VcsJob* push(const QUrl& localRepositoryLocation, const KDevelop::VcsLocation& localOrRepoLocationDst) override; 132 KDevelop::VcsJob* repositoryLocation(const QUrl& localLocation) override; 133 KDevelop::VcsJob* resolve(const QList<QUrl>& localLocations, RecursionMode recursion) override; 134 KDevelop::VcsJob* update(const QList<QUrl>& localLocations, const KDevelop::VcsRevision& rev, RecursionMode recursion) override; 135 KDevelop::VcsLocationWidget* vcsLocation(QWidget* parent) const override; 136 void setupCommitMessageEditor(const QUrl& localLocation, KTextEdit* editor) const override; 137 //End of 138 139 KDevelop::VcsJob* add(const QList<QUrl>& localLocations, 140 KDevelop::IBasicVersionControl::RecursionMode recursion = KDevelop::IBasicVersionControl::Recursive) override; 141 KDevelop::VcsJob* createWorkingCopy(const KDevelop::VcsLocation & localOrRepoLocationSrc, 142 const QUrl& localRepositoryRoot, KDevelop::IBasicVersionControl::RecursionMode) override; 143 144 KDevelop::VcsJob* remove(const QList<QUrl>& files) override; 145 KDevelop::VcsJob* status(const QList<QUrl>& localLocations, 146 KDevelop::IBasicVersionControl::RecursionMode recursion = KDevelop::IBasicVersionControl::Recursive) override; 147 KDevelop::VcsJob* commit(const QString& message, 148 const QList<QUrl>& localLocations, 149 KDevelop::IBasicVersionControl::RecursionMode recursion = KDevelop::IBasicVersionControl::Recursive) override; 150 151 /** 152 * Commits staged changes to the repo located at repoUrl. 153 * 154 * @param message the commit message 155 * @param repoUrl the url pointing to the repo directory (or a file in the repo) 156 */ 157 KDevelop::VcsJob* commitStaged(const QString& message, const QUrl& repoUrl); 158 159 KDevelop::VcsJob* diff(const QUrl& fileOrDirectory, const KDevelop::VcsRevision& srcRevision, const KDevelop::VcsRevision& dstRevision, 160 RecursionMode recursion) override; 161 /** 162 * Shows a diff of changes between srcRevision and dstRevision. 163 * 164 * @param repoPath a path pointing somewhere inside the repo 165 * @param srcRevision the source revision 166 * @param dstRevision the destination revision 167 * 168 * @note: This differs from the @ref:diff method in @ref:IBasicVersionControl in that it does not require 169 * a list of files but automatically shows all changed files 170 */ 171 KDevelop::VcsJob* diff(const QUrl& repoPath, const KDevelop::VcsRevision& srcRevision, const KDevelop::VcsRevision& dstRevision); 172 173 KDevelop::VcsJob* log( const QUrl& localLocation, const KDevelop::VcsRevision& rev, unsigned long limit) override; 174 KDevelop::VcsJob* log(const QUrl& localLocation, const KDevelop::VcsRevision& rev, const KDevelop::VcsRevision& limit) override; 175 KDevelop::VcsJob* annotate(const QUrl &localLocation, const KDevelop::VcsRevision &rev) override; 176 KDevelop::VcsJob* revert(const QList<QUrl>& localLocations, RecursionMode recursion) override; 177 178 /** 179 * Resets all changes in the specified files which were "staged for commit". 180 * 181 * @param localLocations the local files/dirs changes to which should be reset 182 * @param recursion defines whether changes should be reset recursively in all files 183 * in a directory, if localLocations contain a directory 184 */ 185 KDevelop::VcsJob* reset(const QList<QUrl>& localLocations, RecursionMode recursion); 186 187 /** 188 * Applies the patch given by a diff to the repo 189 * 190 * @param diff the patch 191 * @param applyTo where to apply the patch (index or worktree) 192 */ 193 KDevelop::VcsJob* apply(const KDevelop::VcsDiff& diff, ApplyParams applyTo = WorkTree); 194 195 // Begin: KDevelop::IDistributedVersionControl 196 KDevelop::VcsJob* init(const QUrl & directory) override; 197 198 // Branch management 199 KDevelop::VcsJob* tag(const QUrl& repository, const QString& commitMessage, const KDevelop::VcsRevision& rev, const QString& tagName) override; 200 KDevelop::VcsJob* branch(const QUrl& repository, const KDevelop::VcsRevision& rev, const QString& branchName) override; 201 KDevelop::VcsJob* branches(const QUrl& repository) override; 202 KDevelop::VcsJob* currentBranch(const QUrl& repository) override; 203 KDevelop::VcsJob* deleteBranch(const QUrl& repository, const QString& branchName) override; 204 KDevelop::VcsJob* switchBranch(const QUrl& repository, const QString& branchName) override; 205 KDevelop::VcsJob* renameBranch(const QUrl& repository, const QString& oldBranchName, const QString& newBranchName) override; 206 KDevelop::VcsJob* mergeBranch(const QUrl& repository, const QString& branchName) override; 207 KDevelop::VcsJob* rebase(const QUrl& repository, const QString& branchName); 208 209 //graph helpers 210 QVector<KDevelop::DVcsEvent> allCommits(const QString& repo) override; 211 212 //used in log 213 void parseLogOutput(const KDevelop::DVcsJob* job, 214 QVector<KDevelop::DVcsEvent>& commits) const override; 215 216 void additionalMenuEntries(QMenu* menu, const QList<QUrl>& urls) override; 217 218 KDevelop::DVcsJob* gitStash(const QDir& repository, const QStringList& args, KDevelop::OutputJob::OutputJobVerbosity verbosity); 219 220 bool hasStashes(const QDir& repository); 221 bool hasModifications(const QDir& repository); 222 bool hasModifications(const QDir& repo, const QUrl& file); 223 224 void registerRepositoryForCurrentBranchChanges(const QUrl& repository) override; 225 226 KDevelop::CheckInRepositoryJob* isInRepository(KTextEditor::Document* document) override; 227 228 KDevelop::DVcsJob* setConfigOption(const QUrl& repository, const QString& key, const QString& value, bool global = false); 229 QString readConfigOption(const QUrl& repository, const QString& key); 230 231 // this indicates whether the diff() function will generate a diff (patch) which 232 // includes the working copy directory name or not (in which case git diff is called 233 // with --no-prefix). usePrefix()234 bool usePrefix() const 235 { 236 return m_usePrefix; 237 } 238 setUsePrefix(bool p)239 void setUsePrefix(bool p) 240 { 241 m_usePrefix = p; 242 } 243 protected: 244 245 QUrl repositoryRoot(const QUrl& path); 246 247 bool isValidDirectory(const QUrl &dirPath) override; 248 249 KDevelop::DVcsJob* lsFiles(const QDir &repository, 250 const QStringList &args, 251 KDevelop::OutputJob::OutputJobVerbosity verbosity = KDevelop::OutputJob::Verbose); 252 KDevelop::DVcsJob* gitRevList(const QString &directory, 253 const QStringList &args); 254 KDevelop::DVcsJob* gitRevParse(const QString &repository, 255 const QStringList &args, 256 KDevelop::OutputJob::OutputJobVerbosity verbosity = KDevelop::OutputJob::Silent); 257 258 private Q_SLOTS: 259 void parseGitBlameOutput(KDevelop::DVcsJob *job); 260 void parseGitLogOutput(KDevelop::DVcsJob *job); 261 void parseGitDiffOutput(KDevelop::DVcsJob* job); 262 void parseGitRepoLocationOutput(KDevelop::DVcsJob* job); 263 void parseGitStatusOutput(KDevelop::DVcsJob* job); 264 void parseGitStatusOutput_old(KDevelop::DVcsJob* job); 265 void parseGitVersionOutput(KDevelop::DVcsJob* job); 266 void parseGitBranchOutput(KDevelop::DVcsJob* job); 267 void parseGitCurrentBranch(KDevelop::DVcsJob* job); 268 269 void ctxRebase(); 270 void ctxPushStash(); 271 void ctxPopStash(); 272 void ctxStashManager(); 273 274 void fileChanged(const QString& file); 275 void delayedBranchChanged(); 276 277 Q_SIGNALS: 278 void repositoryBranchChanged(const QUrl& repository); 279 280 private: 281 bool ensureValidGitIdentity(const QDir& dir); 282 void addNotVersionedFiles(const QDir& dir, const QList<QUrl>& files); 283 284 //commit dialog "main" helper 285 QStringList getLsFiles(const QDir &directory, const QStringList &args, 286 KDevelop::OutputJob::OutputJobVerbosity verbosity); 287 KDevelop::DVcsJob* errorsFound(const QString& error, KDevelop::OutputJob::OutputJobVerbosity verbosity); 288 289 void initBranchHash(const QString &repo); 290 291 /** 292 * Parses a git status --porcelain line 293 * 294 * @param statusLine a line as returned by `git status --porcelain` 295 * @returns the appropriate extended status 296 */ 297 static ExtendedState parseGitState(const QStringRef& statusLine); 298 299 /** 300 * Maps an extended state to a basic state 301 * 302 * @param state the extended state as provided by git (i.e. describing the combined status in the index & worktree) 303 */ 304 static KDevelop::VcsStatusInfo::State extendedStateToBasic(const ExtendedState state); 305 306 QList<QStringList> branchesShas; 307 QList<QUrl> m_urls; 308 309 /** Tells if it's older than 1.7.0 or not */ 310 bool m_oldVersion = false; 311 312 KDirWatch* m_watcher; 313 QList<QUrl> m_branchesChange; 314 bool m_usePrefix = true; 315 316 /** A tree model tracking and classifying changes into staged, unstaged and untracked */ 317 RepoStatusModel* m_repoStatusModel; 318 319 /** A factory for constructing the tool view for preparing commits */ 320 CommitToolViewFactory* m_commitToolViewFactory; 321 }; 322 323 QVariant runSynchronously(KDevelop::VcsJob* job); 324 325 #endif 326