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