Prepare release and bump version numbers to 2.17.0.2
[TortoiseGit.git] / src / Git / TGitPath.h
blobfdec8eb6e23b6dfc20f2011028f05e6395a2c845
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2024 - TortoiseGit
4 // Copyright (C) 2003-2008, 2014 - TortoiseSVN
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software Foundation,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #pragma once
22 #include "gittype.h"
24 #define PARENT_MASK 0xFFFFFF
25 #define MERGE_MASK (0x1000000)
27 class CTGitPath
29 public:
30 CTGitPath();
31 #ifdef GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_H_
32 virtual ~CTGitPath();
33 #else
34 ~CTGitPath();
35 #endif
36 CTGitPath(const CString& sUnknownPath);
37 CTGitPath(const CString& sUnknownPath, bool bIsDirectory);
38 int m_ParentNo = 0;
40 enum class StagingStatus
42 DontCare,
43 TotallyStaged,
44 PartiallyStaged,
45 TotallyUnstaged
48 enum Actions : unsigned int
50 LOGACTIONS_ADDED = 0x00000001,
51 LOGACTIONS_MODIFIED = 0x00000002,
52 LOGACTIONS_REPLACED = 0x00000004,
53 LOGACTIONS_DELETED = 0x00000008,
54 LOGACTIONS_UNMERGED = 0x00000010,
55 LOGACTIONS_COPY = 0x00000040,
56 LOGACTIONS_MERGED = 0x00000080,
57 LOGACTIONS_ASSUMEVALID = 0x00000200,
58 LOGACTIONS_SKIPWORKTREE = 0x00000400,
59 LOGACTIONS_MISSING = 0x00001000,
60 LOGACTIONS_UNVER = 0x80000000,
61 LOGACTIONS_IGNORE = 0x40000000,
63 // For log filter only
64 LOGACTIONS_HIDE = 0x20000000,
65 LOGACTIONS_GRAY = 0x10000000,
68 CString m_StatAdd;
69 CString m_StatDel;
70 StagingStatus m_stagingStatus = StagingStatus::DontCare;
71 #ifdef TGIT_LFS
72 CString m_LFSLockOwner;
73 #endif
74 unsigned int m_Action = 0;
75 bool m_Checked = false;
76 static unsigned ParseStatus(const char status);
77 inline void ParseAndUpdateStatus(const char status) { m_Action |= ParseStatus(status); }
78 unsigned int ParseAndUpdateStatus(git_delta_t status);
79 CString GetActionName() const;
80 static CString GetActionName(unsigned int action);
81 /**
82 * Set the path as an UTF8 string with forward slashes
84 void SetFromGit(const char* pPath);
85 void SetFromGit(const char* pPath, bool bIsDirectory);
86 void SetFromGit(const wchar_t* pPath, bool bIsDirectory);
87 void SetFromGit(const CString& sPath, CString* oldPath = nullptr, int* bIsDirectory = nullptr);
89 /**
90 * Set the path as UNICODE with backslashes
92 void SetFromWin(LPCWSTR pPath);
93 void SetFromWin(const CString& sPath);
94 void SetFromWin(LPCWSTR pPath, bool bIsDirectory);
95 void SetFromWin(const CString& sPath, bool bIsDirectory);
96 /**
97 * Set the path from an unknown source.
99 void SetFromUnknown(const CString& sPath);
101 * Returns the path in Windows format, i.e. with backslashes
103 LPCWSTR GetWinPath() const;
105 * Returns the path in Windows format, i.e. with backslashes
107 const CString& GetWinPathString() const;
109 * Returns the path with forward slashes.
111 const CString& GetGitPathString() const;
113 const CString& GetGitOldPathString() const;
116 * Returns the path for showing in an UI.
118 * URL's are returned with forward slashes, unescaped if necessary
119 * Paths are returned with backward slashes
121 const CString& GetUIPathString() const;
123 * Returns true if the path points to a directory
125 bool IsDirectory() const;
127 CTGitPath GetSubPath(const CTGitPath &root) const;
130 * Returns the directory. If the path points to a directory, then the path
131 * is returned unchanged. If the path points to a file, the path to the
132 * parent directory is returned.
134 CTGitPath GetDirectory() const;
136 * Returns the directory which contains the item the path refers to.
137 * If the path is a directory, then this returns the directory above it.
138 * If the path is to a file, then this returns the directory which contains the path
139 * parent directory is returned.
141 CTGitPath GetContainingDirectory() const;
143 * Get the 'root path' (e.g. "c:\") - Used to pass to GetDriveType
145 CString GetRootPathString() const;
147 * Returns the filename part of the full path.
148 * \remark don't call this for directories.
150 CString GetFilename() const;
151 CString GetBaseFilename() const;
153 * Returns the item's name without the full path.
155 CString GetFileOrDirectoryName() const;
157 * Returns the item's name without the full path, unescaped if necessary.
159 CString GetUIFileOrDirectoryName() const;
161 * Returns the file extension, including the dot.
162 * \remark Returns an empty string for directories
164 CString GetFileExtension() const;
166 void UpdateCase();
168 bool IsEmpty() const;
169 void Reset();
171 * Checks if two paths are equal. The slashes are taken care of.
173 bool IsEquivalentTo(const CTGitPath& rhs) const;
174 bool IsEquivalentToWithoutCase(const CTGitPath& rhs) const;
175 bool operator==(const CTGitPath& x) const {return IsEquivalentTo(x);}
178 * Checks if \c possibleDescendant is a child of this path.
180 bool IsAncestorOf(const CTGitPath& possibleDescendant) const;
182 * Get a string representing the file path, optionally with a base
183 * section stripped off the front
184 * Returns a string with fwdslash paths
186 CString GetDisplayString(const CTGitPath* pOptionalBasePath = nullptr) const;
188 * Compares two paths. Slash format is irrelevant.
190 static int Compare(const CTGitPath& left, const CTGitPath& right);
192 /** As PredLeftLessThanRight, but for checking if paths are equivalent
194 static bool PredLeftEquivalentToRight(const CTGitPath& left, const CTGitPath& right);
196 /** Checks if the left path is pointing to the same working copy path as the right.
197 * The same wc path means the paths are equivalent once all the admin dir path parts
198 * are removed. This is used in the TGitCache crawler to filter out all the 'duplicate'
199 * paths to crawl.
201 static bool PredLeftSameWCPathAsRight(const CTGitPath& left, const CTGitPath& right);
203 static bool CheckChild(const CTGitPath &parent, const CTGitPath& child);
206 * appends a string to this path.
207 *\remark - missing slashes are not added - this is just a string concatenation, but with
208 * preservation of the proper caching behavior.
209 * If you want to join a file- or directory-name onto the path, you should use AppendPathString
211 void AppendRawString(const CString& sAppend);
214 * appends a part of a path to this path.
215 *\remark - missing slashes are dealt with properly. Don't use this to append a file extension, for example
218 void AppendPathString(const CString& sAppend);
221 * Get the file modification time - returns zero for files which don't exist
223 __int64 GetLastWriteTime(bool force = false) const;
226 * Get the file size. Returns zero for directories or files that don't exist.
228 __int64 GetFileSize() const;
230 bool IsReadOnly() const;
233 * Checks if the path really exists.
235 bool Exists() const;
238 * Deletes the file/folder
239 * \param bTrash if true, uses the Windows trash bin when deleting.
241 bool Delete(bool bTrash, bool bShowErrorUI) const;
244 * Checks if a git admin directory is present. For files, the check
245 * is done in the same directory. For folders, it checks if the folder itself
246 * contains an admin directory.
248 bool HasAdminDir(CString* projectTopDir = nullptr, bool force = false) const;
249 bool HasSubmodules() const;
250 bool HasGitSVNDir() const;
251 bool IsBisectActive() const;
252 bool IsRebaseActive() const;
253 bool IsCherryPickActive() const;
254 bool IsMergeActive() const;
255 bool HasStashDir() const;
256 bool HasRebaseApply() const;
257 bool HasLFS() const;
259 bool IsWCRoot() const;
261 int GetAdminDirMask() const;
263 bool IsRegisteredSubmoduleOfParentProject(CString* parentProjectRoot = nullptr) const;
266 * Checks if the path point to or below a git admin directory (.Git).
268 bool IsAdminDir() const;
271 * Checks if the path or URL is valid on Windows.
272 * A path is valid if conforms to the specs in the windows API.
273 * An URL is valid if the path checked out from it is valid
274 * on windows. That means an URL which is valid according to the WWW specs
275 * isn't necessarily valid as a windows path (e.g. http://myserver.com/repos/file:name
276 * is a valid URL, but the path is illegal on windows ("file:name" is illegal), so
277 * this function would return \c false for that URL).
279 bool IsValidOnWindows() const;
281 CString GetAbbreviatedRename() const;
283 private:
284 // All these functions are const, and all the data
285 // is mutable, in order that the hidden caching operations
286 // can be carried out on a const CTGitPath object, which is what's
287 // likely to be passed between functions
288 // The public 'SetFromxxx' functions are not const, and so the proper
289 // const-correctness semantics are preserved
290 void SetFwdslashPath(const CString& sPath) const;
291 void SetBackslashPath(const CString& sPath) const;
292 void EnsureBackslashPathSet() const;
293 void EnsureFwdslashPathSet() const;
295 public:
297 * Marks a path as a file by unsetting the cached IsDirectory status
298 * Used while diffing commits where a submodule changed to a file
300 void UnsetDirectoryStatus() { m_bIsDirectory = false; }
302 * Marks a path as a directory by setting the cached IsDirectory status
303 * Used while diffing commits where a file changed to a submodule
305 void SetDirectoryStatus() { m_bIsDirectory = true; }
307 private:
309 * Adds the required trailing slash to local root paths such as 'C:'
311 void SanitizeRootPath(CString& sPath, bool bIsForwardPath) const;
313 #ifdef GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_H_
314 protected:
315 virtual void UpdateAttributes() const;
316 private:
317 #else
318 void UpdateAttributes() const;
319 #endif
321 bool HasStashDir(const CString& adminDirPath) const;
323 private:
324 mutable CString m_sBackslashPath;
325 mutable CString m_sLongBackslashPath;
326 mutable CString m_sFwdslashPath;
327 mutable CString m_sUIPath;
328 mutable CString m_sProjectRoot;
330 //used for rename case
331 mutable CString m_sOldFwdslashPath;
333 // Have we yet determined if this is a directory or not?
334 mutable bool m_bDirectoryKnown = false;
335 mutable bool m_bIsDirectory = false;
336 mutable bool m_bLastWriteTimeKnown = false;
337 mutable __int64 m_lastWriteTime = 0;
338 mutable __int64 m_fileSize = 0;
339 mutable bool m_bIsReadOnly = false;
340 mutable bool m_bHasAdminDirKnown = false;
341 mutable bool m_bHasAdminDir = false;
342 mutable bool m_bIsValidOnWindowsKnown = false;
343 mutable bool m_bIsValidOnWindows = false;
344 mutable bool m_bIsAdminDirKnown = false;
345 mutable bool m_bIsAdminDir = false;
346 mutable bool m_bIsWCRootKnown = false;
347 mutable bool m_bIsWCRoot = false;
348 mutable bool m_bExists = false;
349 mutable bool m_bExistsKnown = false;
351 friend bool operator<(const CTGitPath& left, const CTGitPath& right);
354 * Compares two paths and return true if left is earlier in sort order than right
355 * (Uses CTGitPath::Compare logic, but is suitable for std::sort and similar)
357 bool operator<(const CTGitPath& left, const CTGitPath& right);
360 //////////////////////////////////////////////////////////////////////////
363 * \ingroup Utils
364 * This class represents a list of paths
366 class CTGitPathList
368 public:
369 CTGitPathList();
370 // A constructor which allows a path list to be easily built with one initial entry in
371 explicit CTGitPathList(const CTGitPath& firstEntry);
372 unsigned int m_Action = 0;
374 public:
375 void AddPath(const CTGitPath& newPath);
376 bool LoadFromFile(const CTGitPath& filename);
377 bool WriteToFile(const CString& sFilename, bool bUTF8 = false) const;
378 bool WriteToPathSpecFile(const CString& sFilename) const;
379 const CTGitPath* LookForGitPath(const CString& path) const;
380 int ParserFromLog(BYTE_VECTOR& log);
381 int ParserFromLsFileSimple(BYTE_VECTOR& out, unsigned int action, bool clear = true);
382 int ParserFromLsFile(BYTE_VECTOR& out);
383 void UpdateStagingStatusFromPath(const CString& path, CTGitPath::StagingStatus status);
384 int FillUnRev(unsigned int Action, const CTGitPathList* filterlist = nullptr, CString* err = nullptr);
385 #ifdef TGIT_LFS
386 int FillLFSLocks(unsigned int action, CString* err = nullptr);
387 #ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_H_
388 private:
389 #endif
390 int ParserFromLFSLocks(unsigned int action, const CString& output, CString* err = nullptr);
391 #endif
392 public:
393 int FillBasedOnIndexFlags(unsigned short flag, unsigned short flagextended, const CTGitPathList* filterlist = nullptr);
394 unsigned int GetAction();
396 * Load from the path argument string, when the 'path' parameter is used
397 * This is a list of paths, with '*' between them
399 void LoadFromAsteriskSeparatedString(const CString& sPathString);
400 CString CreateAsteriskSeparatedString() const;
402 int GetCount() const;
403 bool IsEmpty() const;
404 void Clear();
405 const CTGitPath& operator[](INT_PTR index) const;
406 bool AreAllPathsFiles() const;
407 bool AreAllPathsDirectories() const;
408 bool AreAllPathsFilesInOneDirectory() const;
409 bool IsAnyAncestorOf(const CTGitPath& possibleDescendant) const;
412 * returns the directory which all items have in common.
413 * if not all paths are in the same directory, then
414 * an empty path is returned
416 CTGitPath GetCommonDirectory() const;
418 * returns the root path of all paths in the list.
419 * only returns an empty path if not all paths are on
420 * the same drive/root.
422 CTGitPath GetCommonRoot() const;
423 void SortByPathname(bool bReverse = false);
425 * Delete all the files in the list, then clear the list.
426 * \param bTrash if true, the items are deleted using the Windows trash bin
427 * \param bShowErrorUI if true, show error dialog box when error occurs.
429 void DeleteAllFiles(bool bTrash, bool bFilesOnly = true, bool bShowErrorUI = false);
430 static bool DeleteViaShell(LPCWSTR path, bool useTrashbin, bool bShowErrorUI);
431 /** Remove duplicate entries from the list (sorts the list as a side-effect */
432 void RemoveDuplicates();
433 /** Removes all paths which are on or in a git admin directory */
434 void RemoveAdminPaths();
435 void RemovePath(const CTGitPath& path);
436 void RemoveItem(const CTGitPath& path);
438 * Removes all child items and leaves only the top folders. Useful if you
439 * create the list to remove them (i.e. if you remove a parent folder, the
440 * child files and folders don't have to be deleted anymore)
442 void RemoveChildren();
444 /** Checks if two CTGitPathLists are the same */
445 bool IsEqual(const CTGitPathList& list);
447 using PathVector = std::vector<CTGitPath>;
448 PathVector m_paths;
449 // If the list contains just files in one directory, then
450 // this contains the directory name
451 mutable CTGitPath m_commonBaseDirectory;
453 auto begin() noexcept { return m_paths.begin(); }
454 auto begin() const noexcept { return m_paths.cbegin(); }
455 auto cbegin() const noexcept { return m_paths.cbegin(); }
456 auto end() noexcept { return m_paths.end(); }
457 auto end() const noexcept { return m_paths.cend(); }
458 auto cend() const noexcept { return m_paths.cend(); }