1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt Creator.
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and The Qt Company. For licensing terms
13 ** and conditions see https://www.qt.io/terms-conditions. For further
14 ** information use the contact form at https://www.qt.io/contact-us.
15 **
16 ** GNU General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU
18 ** General Public License version 3 as published by the Free Software
19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 ** included in the packaging of this file. Please review the following
21 ** information to ensure the GNU General Public License requirements will
22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 **
24 ****************************************************************************/
25
26 #pragma once
27
28 #include "core_global.h"
29
30 #include <utils/id.h>
31 #include <utils/fileutils.h>
32
33 #include <QDateTime>
34 #include <QFlags>
35 #include <QHash>
36 #include <QObject>
37 #include <QString>
38
39 QT_FORWARD_DECLARE_CLASS(QMenu);
40
41 namespace Core {
42
43 class ShellCommand;
44
45 class CORE_EXPORT IVersionControl : public QObject
46 {
47 Q_OBJECT
48 public:
49 enum SettingsFlag {
50 AutoOpen = 0x1
51 };
52 Q_DECLARE_FLAGS(SettingsFlags, SettingsFlag)
53
54 enum Operation {
55 AddOperation, DeleteOperation, MoveOperation,
56 CreateRepositoryOperation,
57 SnapshotOperations,
58 AnnotateOperation,
59 InitialCheckoutOperation
60 };
61 Q_ENUM(SettingsFlag)
62 Q_ENUM(Operation)
63
64 enum OpenSupportMode {
65 NoOpen, /*!< Files can be edited without noticing the VCS */
66 OpenOptional, /*!< Files can be opened by the VCS, or hijacked */
67 OpenMandatory /*!< Files must always be opened by the VCS */
68 };
69
70 class CORE_EXPORT TopicCache
71 {
72 public:
73 virtual ~TopicCache();
74 QString topic(const QString &topLevel);
75
76 protected:
77 virtual QString trackFile(const QString &repository) = 0;
78 virtual QString refreshTopic(const QString &repository) = 0;
79
80 private:
81 class TopicData
82 {
83 public:
84 QDateTime timeStamp;
85 QString topic;
86 };
87
88 QHash<QString, TopicData> m_cache;
89
90 };
91
92 IVersionControl();
93 ~IVersionControl() override;
94
95 virtual QString displayName() const = 0;
96 virtual Utils::Id id() const = 0;
97
98 /*!
99 * \brief isVcsFileOrDirectory
100 * \param fileName
101 * \return True if filename is a file or directory that is maintained by the
102 * version control system.
103 *
104 * It will return true only for exact matches of the name, not for e.g. files in a
105 * directory owned by the version control system (e.g. .git/control).
106 *
107 * This method needs to be thread safe!
108 */
109 virtual bool isVcsFileOrDirectory(const Utils::FilePath &fileName) const = 0;
110
111 /*!
112 * Returns whether files in this directory should be managed with this
113 * version control.
114 * If \a topLevel is non-null, it should return the topmost directory,
115 * for which this IVersionControl should be used. The VcsManager assumes
116 * that all files in the returned directory are managed by the same IVersionControl.
117 */
118
119 virtual bool managesDirectory(const QString &filename, QString *topLevel = nullptr) const = 0;
120
121 /*!
122 * Returns whether \a fileName is managed by this version control.
123 *
124 * \a workingDirectory is assumed to be part of a valid repository (not necessarily its
125 * top level). \a fileName is expected to be relative to workingDirectory.
126 */
127 virtual bool managesFile(const QString &workingDirectory, const QString &fileName) const = 0;
128
129 /*!
130 * Returns the subset of \a filePaths that is not managed by this version control.
131 *
132 * The \a filePaths are expected to be absolute paths.
133 */
134 virtual QStringList unmanagedFiles(const QStringList &filePaths) const;
135
136 /*!
137 * Returns true is the VCS is configured to run.
138 */
139 virtual bool isConfigured() const = 0;
140 /*!
141 * Called to query whether a VCS supports the respective operations.
142 *
143 * Return false if the VCS is not configured yet.
144 */
145 virtual bool supportsOperation(Operation operation) const = 0;
146
147 /*!
148 * Returns the open support mode for \a fileName.
149 */
150 virtual OpenSupportMode openSupportMode(const QString &fileName) const;
151
152 /*!
153 * Called prior to save, if the file is read only. Should be implemented if
154 * the scc requires a operation before editing the file, e.g. 'p4 edit'
155 *
156 * \note The EditorManager calls this for the editors.
157 */
158 virtual bool vcsOpen(const QString &fileName) = 0;
159
160 /*!
161 * Returns settings.
162 */
163
settingsFlags()164 virtual SettingsFlags settingsFlags() const { return {}; }
165
166 /*!
167 * Called after a file has been added to a project If the version control
168 * needs to know which files it needs to track you should reimplement this
169 * function, e.g. 'p4 add', 'cvs add', 'svn add'.
170 *
171 * \note This function should be called from IProject subclasses after
172 * files are added to the project.
173 */
174 virtual bool vcsAdd(const QString &filename) = 0;
175
176 /*!
177 * Called after a file has been removed from the project (if the user
178 * wants), e.g. 'p4 delete', 'svn delete'.
179 */
180 virtual bool vcsDelete(const QString &filename) = 0;
181
182 /*!
183 * Called to rename a file, should do the actual on disk renaming
184 * (e.g. git mv, svn move, p4 move)
185 */
186 virtual bool vcsMove(const QString &from, const QString &to) = 0;
187
188 /*!
189 * Called to initialize the version control system in a directory.
190 */
191 virtual bool vcsCreateRepository(const QString &directory) = 0;
192
193 /*!
194 * Topic (e.g. name of the current branch)
195 */
196 virtual QString vcsTopic(const QString &topLevel);
197
198 /*!
199 * Display annotation for a file and scroll to line
200 */
201 virtual void vcsAnnotate(const QString &file, int line) = 0;
202
203 /*!
204 * Display text for Open operation
205 */
206 virtual QString vcsOpenText() const;
207
208 /*!
209 * Display text for Make Writable
210 */
211 virtual QString vcsMakeWritableText() const;
212
213 /*!
214 * Display details of reference
215 */
216 virtual void vcsDescribe(const QString &workingDirectory, const QString &reference) = 0;
217
218 /*!
219 * Return a list of paths where tools that came with the VCS may be installed.
220 * This is helpful on windows where e.g. git comes with a lot of nice unix tools.
221 */
222 virtual QStringList additionalToolsPath() const;
223
224 /*!
225 * Return a ShellCommand capable of checking out \a url into \a baseDirectory, where
226 * a new subdirectory with \a localName will be created.
227 *
228 * \a extraArgs are passed on to the command being run.
229 */
230 virtual ShellCommand *createInitialCheckoutCommand(const QString &url,
231 const Utils::FilePath &baseDirectory,
232 const QString &localName,
233 const QStringList &extraArgs);
234
235 virtual void fillLinkContextMenu(QMenu *menu,
236 const QString &workingDirectory,
237 const QString &reference);
238
239 virtual bool handleLink(const QString &workingDirectory, const QString &reference);
240
241 class CORE_EXPORT RepoUrl {
242 public:
243 RepoUrl(const QString &location);
244
245 QString protocol;
246 QString userName;
247 QString host;
248 QString path;
249 quint16 port = 0;
250 bool isValid = false;
251 };
252 virtual RepoUrl getRepoUrl(const QString &location) const;
253
254 void setTopicCache(TopicCache *topicCache);
255
256 signals:
257 void repositoryChanged(const QString &repository);
258 void filesChanged(const QStringList &files);
259 void configurationChanged();
260
261 private:
262 TopicCache *m_topicCache = nullptr;
263 };
264
265 } // namespace Core
266
Q_DECLARE_OPERATORS_FOR_FLAGS(Core::IVersionControl::SettingsFlags)267 Q_DECLARE_OPERATORS_FOR_FLAGS(Core::IVersionControl::SettingsFlags)
268
269 #if defined(WITH_TESTS)
270
271 #include <QSet>
272
273 namespace Core {
274
275 class CORE_EXPORT TestVersionControl : public IVersionControl
276 {
277 Q_OBJECT
278 public:
279 TestVersionControl(Utils::Id id, const QString &name) :
280 m_id(id), m_displayName(name)
281 { }
282 ~TestVersionControl() override;
283
284 bool isVcsFileOrDirectory(const Utils::FilePath &fileName) const final
285 { Q_UNUSED(fileName) return false; }
286
287 void setManagedDirectories(const QHash<QString, QString> &dirs);
288 void setManagedFiles(const QSet<QString> &files);
289
290 int dirCount() const { return m_dirCount; }
291 int fileCount() const { return m_fileCount; }
292
293 // IVersionControl interface
294 QString displayName() const override { return m_displayName; }
295 Utils::Id id() const override { return m_id; }
296 bool managesDirectory(const QString &filename, QString *topLevel) const override;
297 bool managesFile(const QString &workingDirectory, const QString &fileName) const override;
298 bool isConfigured() const override { return true; }
299 bool supportsOperation(Operation) const override { return false; }
300 bool vcsOpen(const QString &) override { return false; }
301 bool vcsAdd(const QString &) override { return false; }
302 bool vcsDelete(const QString &) override { return false; }
303 bool vcsMove(const QString &, const QString &) override { return false; }
304 bool vcsCreateRepository(const QString &) override { return false; }
305 void vcsAnnotate(const QString &, int) override {}
306 void vcsDescribe(const QString &, const QString &) override {}
307
308 private:
309 Utils::Id m_id;
310 QString m_displayName;
311 QHash<QString, QString> m_managedDirs;
312 QSet<QString> m_managedFiles;
313 mutable int m_dirCount = 0;
314 mutable int m_fileCount = 0;
315 };
316
317 } // namespace Core
318
319 #endif
320