--- /dev/null
+// TortoiseGit - a Windows shell extension for easy version control\r
+\r
+// Copyright (C) 2003-2008 - TortoiseGit\r
+\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+// GNU General Public License for more details.\r
+\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software Foundation,\r
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+#include "StdAfx.h"\r
+#include "UnicodeUtils.h"\r
+#include "GitAdminDir.h"\r
+\r
+GitAdminDir g_GitAdminDir;\r
+\r
+GitAdminDir::GitAdminDir()\r
+ : m_nInit(0)\r
+// , m_bVSNETHack(false)\r
+// , m_pool(NULL)\r
+{\r
+}\r
+\r
+GitAdminDir::~GitAdminDir()\r
+{\r
+// if (m_nInit)\r
+// (m_pool);\r
+}\r
+\r
+bool GitAdminDir::Init()\r
+{\r
+ if (m_nInit==0)\r
+ {\r
+#if 0 \r
+ m_bVSNETHack = false;\r
+ m_pool = svn_pool_create(NULL);\r
+ size_t ret = 0;\r
+ getenv_s(&ret, NULL, 0, "GIT_ASP_DOT_NET_HACK");\r
+ if (ret)\r
+ {\r
+ svn_error_clear(svn_wc_set_adm_dir("_git", m_pool));\r
+ m_bVSNETHack = true;\r
+ }\r
+#endif\r
+ }\r
+ m_nInit++;\r
+ return true;\r
+}\r
+\r
+bool GitAdminDir::Close()\r
+{\r
+ m_nInit--;\r
+ if (m_nInit>0)\r
+ return false;\r
+#if 0\r
+ svn_pool_destroy(m_pool);\r
+#endif\r
+ return true;\r
+}\r
+\r
+bool GitAdminDir::IsAdminDirName(const CString& name) const\r
+{\r
+#if 0\r
+ CStringA nameA = CUnicodeUtils::GetUTF8(name).MakeLower();\r
+ return !!svn_wc_is_adm_dir(nameA, m_pool);\r
+#endif\r
+ return name == ".git";\r
+}\r
+\r
+bool GitAdminDir::HasAdminDir(const CString& path) const\r
+{\r
+ return HasAdminDir(path, !!PathIsDirectory(path));\r
+}\r
+\r
+bool GitAdminDir::HasAdminDir(const CString& path, bool bDir) const\r
+{\r
+ if (path.IsEmpty())\r
+ return false;\r
+ bool bHasAdminDir = false;\r
+ CString sDirName = path;\r
+ if (!bDir)\r
+ {\r
+ sDirName = path.Left(path.ReverseFind('\\'));\r
+ }\r
+ \r
+ do\r
+ {\r
+ if(PathFileExists(sDirName + _T("\\.git")))\r
+ return true;\r
+ sDirName = sDirName.Left(sDirName.ReverseFind('\\'));\r
+\r
+ }while(sDirName.ReverseFind('\\')>0);\r
+\r
+ return false;\r
+ \r
+}\r
+\r
+bool GitAdminDir::IsAdminDirPath(const CString& path) const\r
+{\r
+ if (path.IsEmpty())\r
+ return false;\r
+ bool bIsAdminDir = false;\r
+ CString lowerpath = path;\r
+ lowerpath.MakeLower();\r
+ int ind = -1;\r
+ int ind1 = 0;\r
+ while ((ind1 = lowerpath.Find(_T("\\.git"), ind1))>=0)\r
+ {\r
+ ind = ind1++;\r
+ if (ind == (lowerpath.GetLength() - 5))\r
+ {\r
+ bIsAdminDir = true;\r
+ break;\r
+ }\r
+ else if (lowerpath.Find(_T("\\.git\\"), ind)>=0)\r
+ {\r
+ bIsAdminDir = true;\r
+ break;\r
+ }\r
+ }\r
+\r
+ return bIsAdminDir;\r
+}\r
+\r
--- /dev/null
+#pragma once\r
+\r
+class GitAdminDir\r
+{\r
+public:\r
+ GitAdminDir(void);\r
+ ~GitAdminDir(void);\r
+ /**\r
+ * Initializes the global object. Call this after apr is initialized but\r
+ * before using any other methods of this class.\r
+ */\r
+ bool Init();\r
+ /**\r
+ * Clears the memory pool. Call this before you clear *all* pools\r
+ * with apr_pool_terminate(). If you don't use apr_pool_terminate(), then\r
+ * this method doesn't need to be called, because the deconstructor will\r
+ * do the same too.\r
+ */\r
+ bool Close();\r
+ \r
+ /// Returns true if \a name is the admin dir name\r
+ bool IsAdminDirName(const CString& name) const;\r
+ \r
+ /// Returns true if the path points to or below an admin directory\r
+ bool IsAdminDirPath(const CString& path) const;\r
+ \r
+ /// Returns true if the path (file or folder) has an admin directory \r
+ /// associated, i.e. if the path is in a working copy.\r
+ bool HasAdminDir(const CString& path) const;\r
+ bool HasAdminDir(const CString& path, bool bDir) const;\r
+ \r
+ /// Returns true if the admin dir name is set to "_svn".\r
+ bool IsVSNETHackActive() const {return m_bVSNETHack;}\r
+ \r
+ CString GetAdminDirName() const {return _T(".git");}\r
+ CString GetVSNETAdminDirName() const {return _T("_git");}\r
+private:\r
+ bool m_bVSNETHack;\r
+ int m_nInit;\r
+\r
+};\r
+\r
+extern GitAdminDir g_GitAdminDir;
\ No newline at end of file
--- /dev/null
+// TortoiseGit - a Windows shell extension for easy version control\r
+\r
+// Copyright (C) 2003-2008 - TortoiseGit\r
+\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+// GNU General Public License for more details.\r
+\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software Foundation,\r
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+//\r
+\r
+#include "stdafx.h"\r
+#include "resource.h"\r
+#include "..\TortoiseShell\resource.h"\r
+//#include "git_config.h"\r
+#include "GitStatus.h"\r
+#include "UnicodeUtils.h"\r
+//#include "GitGlobal.h"\r
+//#include "GitHelpers.h"\r
+#ifdef _MFC_VER\r
+# include "Git.h"\r
+# include "MessageBox.h"\r
+# include "registry.h"\r
+# include "TGitPath.h"\r
+# include "PathUtils.h"\r
+#endif\r
+\r
+GitStatus::GitStatus(bool * pbCanceled)\r
+ : status(NULL)\r
+{\r
+#if 0\r
+ m_pool = git_pool_create (NULL);\r
+ \r
+ git_error_clear(git_client_create_context(&ctx, m_pool));\r
+ \r
+ if (pbCanceled)\r
+ {\r
+ ctx->cancel_func = cancel;\r
+ ctx->cancel_baton = pbCanceled;\r
+ }\r
+\r
+#ifdef _MFC_VER\r
+ git_error_clear(git_config_ensure(NULL, m_pool));\r
+ \r
+ // set up authentication\r
+ m_prompt.Init(m_pool, ctx);\r
+\r
+ // set up the configuration\r
+ m_err = git_config_get_config (&(ctx->config), g_pConfigDir, m_pool);\r
+\r
+ if (m_err)\r
+ {\r
+ ::MessageBox(NULL, this->GetLastErrorMsg(), _T("TortoiseGit"), MB_ICONERROR);\r
+ git_error_clear(m_err);\r
+ git_pool_destroy (m_pool); // free the allocated memory\r
+ exit(-1);\r
+ }\r
+\r
+ // set up the Git_SSH param\r
+ CString tgit_ssh = CRegString(_T("Software\\TortoiseGit\\SSH"));\r
+ if (tgit_ssh.IsEmpty())\r
+ tgit_ssh = CPathUtils::GetAppDirectory() + _T("TortoisePlink.exe");\r
+ tgit_ssh.Replace('\\', '/');\r
+ if (!tgit_ssh.IsEmpty())\r
+ {\r
+ git_config_t * cfg = (git_config_t *)apr_hash_get ((apr_hash_t *)ctx->config, Git_CONFIG_CATEGORY_CONFIG,\r
+ APR_HASH_KEY_STRING);\r
+ git_config_set(cfg, Git_CONFIG_SECTION_TUNNELS, "ssh", CUnicodeUtils::GetUTF8(tgit_ssh));\r
+ }\r
+#else\r
+ git_error_clear(git_config_ensure(NULL, m_pool));\r
+\r
+ // set up the configuration\r
+ m_err = git_config_get_config (&(ctx->config), g_pConfigDir, m_pool);\r
+\r
+#endif\r
+#endif\r
+}\r
+\r
+GitStatus::~GitStatus(void)\r
+{\r
+#if 0\r
+ git_error_clear(m_err);\r
+ git_pool_destroy (m_pool); // free the allocated memory\r
+#endif\r
+}\r
+\r
+void GitStatus::ClearPool()\r
+{\r
+#if 0\r
+ git_pool_clear(m_pool);\r
+#endif\r
+}\r
+\r
+#ifdef _MFC_VER\r
+CString GitStatus::GetLastErrorMsg() const\r
+{\r
+ return Git::GetErrorString(m_err);\r
+}\r
+#else\r
+stdstring GitStatus::GetLastErrorMsg() const\r
+{\r
+\r
+ stdstring msg;\r
+#if 0\r
+ char errbuf[256];\r
+\r
+ if (m_err != NULL)\r
+ {\r
+ git_error_t * ErrPtr = m_err;\r
+ if (ErrPtr->message)\r
+ {\r
+ msg = CUnicodeUtils::StdGetUnicode(ErrPtr->message);\r
+ }\r
+ else\r
+ {\r
+ /* Is this a Subversion-specific error code? */\r
+ if ((ErrPtr->apr_err > APR_OS_START_USEERR)\r
+ && (ErrPtr->apr_err <= APR_OS_START_CANONERR))\r
+ msg = CUnicodeUtils::StdGetUnicode(git_strerror (ErrPtr->apr_err, errbuf, sizeof (errbuf)));\r
+ /* Otherwise, this must be an APR error code. */\r
+ else\r
+ {\r
+ git_error_t *temp_err = NULL;\r
+ const char * err_string = NULL;\r
+ temp_err = git_utf_cstring_to_utf8(&err_string, apr_strerror (ErrPtr->apr_err, errbuf, sizeof (errbuf)-1), ErrPtr->pool);\r
+ if (temp_err)\r
+ {\r
+ git_error_clear (temp_err);\r
+ msg = _T("Can't recode error string from APR");\r
+ }\r
+ else\r
+ {\r
+ msg = CUnicodeUtils::StdGetUnicode(err_string);\r
+ }\r
+ }\r
+\r
+ }\r
+\r
+ while (ErrPtr->child)\r
+ {\r
+ ErrPtr = ErrPtr->child;\r
+ msg += _T("\n");\r
+ if (ErrPtr->message)\r
+ {\r
+ msg += CUnicodeUtils::StdGetUnicode(ErrPtr->message);\r
+ }\r
+ else\r
+ {\r
+ /* Is this a Subversion-specific error code? */\r
+ if ((ErrPtr->apr_err > APR_OS_START_USEERR)\r
+ && (ErrPtr->apr_err <= APR_OS_START_CANONERR))\r
+ msg += CUnicodeUtils::StdGetUnicode(git_strerror (ErrPtr->apr_err, errbuf, sizeof (errbuf)));\r
+ /* Otherwise, this must be an APR error code. */\r
+ else\r
+ {\r
+ git_error_t *temp_err = NULL;\r
+ const char * err_string = NULL;\r
+ temp_err = git_utf_cstring_to_utf8(&err_string, apr_strerror (ErrPtr->apr_err, errbuf, sizeof (errbuf)-1), ErrPtr->pool);\r
+ if (temp_err)\r
+ {\r
+ git_error_clear (temp_err);\r
+ msg += _T("Can't recode error string from APR");\r
+ }\r
+ else\r
+ {\r
+ msg += CUnicodeUtils::StdGetUnicode(err_string);\r
+ }\r
+ }\r
+\r
+ }\r
+ }\r
+ return msg;\r
+ } // if (m_err != NULL)\r
+#endif\r
+ return msg;\r
+}\r
+#endif\r
+\r
+// static method\r
+git_wc_status_kind GitStatus::GetAllStatus(const CTGitPath& path, git_depth_t depth)\r
+{\r
+ git_wc_status_kind statuskind;\r
+#if 0\r
+ git_client_ctx_t * ctx;\r
+ \r
+ apr_pool_t * pool;\r
+ git_error_t * err;\r
+ BOOL isDir;\r
+\r
+ isDir = path.IsDirectory();\r
+ if (!path.HasAdminDir())\r
+ return git_wc_status_none;\r
+\r
+ pool = git_pool_create (NULL); // create the memory pool\r
+\r
+ git_error_clear(git_client_create_context(&ctx, pool));\r
+\r
+ git_revnum_t youngest = Git_INVALID_REVNUM;\r
+ git_opt_revision_t rev;\r
+ rev.kind = git_opt_revision_unspecified;\r
+ statuskind = git_wc_status_none;\r
+ err = git_client_status4 (&youngest,\r
+ path.GetGitApiPath(pool),\r
+ &rev,\r
+ getallstatus,\r
+ &statuskind,\r
+ depth,\r
+ TRUE, //getall\r
+ FALSE, //update\r
+ TRUE, //noignore\r
+ FALSE, //ignore externals\r
+ NULL,\r
+ ctx,\r
+ pool);\r
+\r
+ // Error present\r
+ if (err != NULL)\r
+ {\r
+ git_error_clear(err);\r
+ git_pool_destroy (pool); //free allocated memory\r
+ return git_wc_status_none; \r
+ }\r
+\r
+ git_pool_destroy (pool); //free allocated memory\r
+#endif\r
+ return statuskind;\r
+}\r
+\r
+// static method\r
+git_wc_status_kind GitStatus::GetAllStatusRecursive(const CTGitPath& path)\r
+{\r
+ return GetAllStatus(path, git_depth_infinity);\r
+}\r
+\r
+// static method\r
+git_wc_status_kind GitStatus::GetMoreImportant(git_wc_status_kind status1, git_wc_status_kind status2)\r
+{\r
+ if (GetStatusRanking(status1) >= GetStatusRanking(status2))\r
+ return status1;\r
+ return status2;\r
+}\r
+// static private method\r
+int GitStatus::GetStatusRanking(git_wc_status_kind status)\r
+{\r
+ switch (status)\r
+ {\r
+ case git_wc_status_none:\r
+ return 0;\r
+ case git_wc_status_unversioned:\r
+ return 1;\r
+ case git_wc_status_ignored:\r
+ return 2;\r
+ case git_wc_status_incomplete:\r
+ return 4;\r
+ case git_wc_status_normal:\r
+ case git_wc_status_external:\r
+ return 5;\r
+ case git_wc_status_added:\r
+ return 6;\r
+ case git_wc_status_missing:\r
+ return 7;\r
+ case git_wc_status_deleted:\r
+ return 8;\r
+ case git_wc_status_replaced:\r
+ return 9;\r
+ case git_wc_status_modified:\r
+ return 10;\r
+ case git_wc_status_merged:\r
+ return 11;\r
+ case git_wc_status_conflicted:\r
+ return 12;\r
+ case git_wc_status_obstructed:\r
+ return 13;\r
+ }\r
+ return 0;\r
+}\r
+\r
+git_revnum_t GitStatus::GetStatus(const CTGitPath& path, bool update /* = false */, bool noignore /* = false */, bool noexternals /* = false */)\r
+{\r
+#if 0\r
+ apr_hash_t * statushash;\r
+ apr_hash_t * exthash;\r
+ apr_array_header_t * statusarray;\r
+ const sort_item* item;\r
+ \r
+ git_error_clear(m_err);\r
+ statushash = apr_hash_make(m_pool);\r
+ exthash = apr_hash_make(m_pool);\r
+ git_revnum_t youngest = Git_INVALID_REVNUM;\r
+ git_opt_revision_t rev;\r
+ rev.kind = git_opt_revision_unspecified;\r
+ struct hashbaton_t hashbaton;\r
+ hashbaton.hash = statushash;\r
+ hashbaton.exthash = exthash;\r
+ hashbaton.pThis = this;\r
+ m_err = git_client_status4 (&youngest,\r
+ path.GetGitApiPath(m_pool),\r
+ &rev,\r
+ getstatushash,\r
+ &hashbaton,\r
+ git_depth_empty, //depth\r
+ TRUE, //getall\r
+ update, //update\r
+ noignore, //noignore\r
+ noexternals,\r
+ NULL,\r
+ ctx,\r
+ m_pool);\r
+\r
+\r
+ // Error present if function is not under version control\r
+ if ((m_err != NULL) || (apr_hash_count(statushash) == 0))\r
+ {\r
+ status = NULL;\r
+ return -2; \r
+ }\r
+\r
+ // Convert the unordered hash to an ordered, sorted array\r
+ statusarray = sort_hash (statushash,\r
+ sort_compare_items_as_paths,\r
+ m_pool);\r
+\r
+ // only the first entry is needed (no recurse)\r
+ item = &APR_ARRAY_IDX (statusarray, 0, const sort_item);\r
+ \r
+ status = (git_wc_status2_t *) item->value;\r
+ \r
+ return youngest;\r
+#endif\r
+ return "";\r
+}\r
+git_wc_status2_t * GitStatus::GetFirstFileStatus(const CTGitPath& path, CTGitPath& retPath, bool update, git_depth_t depth, bool bNoIgnore /* = true */, bool bNoExternals /* = false */)\r
+{\r
+#if 0\r
+ const sort_item* item;\r
+\r
+ git_error_clear(m_err);\r
+ m_statushash = apr_hash_make(m_pool);\r
+ m_externalhash = apr_hash_make(m_pool);\r
+ headrev = Git_INVALID_REVNUM;\r
+ git_opt_revision_t rev;\r
+ rev.kind = git_opt_revision_unspecified;\r
+ struct hashbaton_t hashbaton;\r
+ hashbaton.hash = m_statushash;\r
+ hashbaton.exthash = m_externalhash;\r
+ hashbaton.pThis = this;\r
+ m_statushashindex = 0;\r
+ m_err = git_client_status4 (&headrev,\r
+ path.GetGitApiPath(m_pool),\r
+ &rev,\r
+ getstatushash,\r
+ &hashbaton,\r
+ depth,\r
+ TRUE, //getall\r
+ update, //update\r
+ bNoIgnore, //noignore\r
+ bNoExternals, //noexternals\r
+ NULL,\r
+ ctx,\r
+ m_pool);\r
+\r
+\r
+ // Error present if function is not under version control\r
+ if ((m_err != NULL) || (apr_hash_count(m_statushash) == 0))\r
+ {\r
+ return NULL; \r
+ }\r
+\r
+ // Convert the unordered hash to an ordered, sorted array\r
+ m_statusarray = sort_hash (m_statushash,\r
+ sort_compare_items_as_paths,\r
+ m_pool);\r
+\r
+ // only the first entry is needed (no recurse)\r
+ m_statushashindex = 0;\r
+ item = &APR_ARRAY_IDX (m_statusarray, m_statushashindex, const sort_item);\r
+ retPath.SetFromGit((const char*)item->key);\r
+ return (git_wc_status2_t *) item->value;\r
+#endif\r
+\r
+ return 0;\r
+}\r
+\r
+unsigned int GitStatus::GetVersionedCount() const\r
+{\r
+\r
+ unsigned int count = 0;\r
+#if 0\r
+ const sort_item* item;\r
+ for (unsigned int i=0; i<apr_hash_count(m_statushash); ++i)\r
+ {\r
+ item = &APR_ARRAY_IDX(m_statusarray, i, const sort_item);\r
+ if (item)\r
+ {\r
+ if (GitStatus::GetMoreImportant(((git_wc_status_t *)item->value)->text_status, git_wc_status_ignored)!=git_wc_status_ignored)\r
+ count++; \r
+ }\r
+ }\r
+#endif\r
+ return count;\r
+}\r
+\r
+git_wc_status2_t * GitStatus::GetNextFileStatus(CTGitPath& retPath)\r
+{\r
+#if 0\r
+ const sort_item* item;\r
+\r
+ if ((m_statushashindex+1) >= apr_hash_count(m_statushash))\r
+ return NULL;\r
+ m_statushashindex++;\r
+\r
+ item = &APR_ARRAY_IDX (m_statusarray, m_statushashindex, const sort_item);\r
+ retPath.SetFromGit((const char*)item->key);\r
+ return (git_wc_status2_t *) item->value;\r
+#endif\r
+ return 0;\r
+}\r
+\r
+bool GitStatus::IsExternal(const CTGitPath& path) const\r
+{\r
+#if 0\r
+ if (apr_hash_get(m_externalhash, path.GetGitApiPath(m_pool), APR_HASH_KEY_STRING))\r
+ return true;\r
+#endif\r
+ return false;\r
+}\r
+\r
+bool GitStatus::IsInExternal(const CTGitPath& path) const\r
+{\r
+#if 0\r
+ if (apr_hash_count(m_statushash) == 0)\r
+ return false;\r
+\r
+ GitPool localpool(m_pool);\r
+ apr_hash_index_t *hi;\r
+ const char* key;\r
+ for (hi = apr_hash_first(localpool, m_externalhash); hi; hi = apr_hash_next(hi)) \r
+ {\r
+ apr_hash_this(hi, (const void**)&key, NULL, NULL);\r
+ if (key)\r
+ {\r
+ if (CTGitPath(CUnicodeUtils::GetUnicode(key)).IsAncestorOf(path))\r
+ return true;\r
+ }\r
+ }\r
+#endif\r
+ return false;\r
+}\r
+\r
+\r
+void GitStatus::GetStatusString(git_wc_status_kind status, size_t buflen, TCHAR * string)\r
+{\r
+ TCHAR * buf;\r
+ switch (status)\r
+ {\r
+ case git_wc_status_none:\r
+ buf = _T("none\0");\r
+ break;\r
+ case git_wc_status_unversioned:\r
+ buf = _T("unversioned\0");\r
+ break;\r
+ case git_wc_status_normal:\r
+ buf = _T("normal\0");\r
+ break;\r
+ case git_wc_status_added:\r
+ buf = _T("added\0");\r
+ break;\r
+ case git_wc_status_missing:\r
+ buf = _T("missing\0");\r
+ break;\r
+ case git_wc_status_deleted:\r
+ buf = _T("deleted\0");\r
+ break;\r
+ case git_wc_status_replaced:\r
+ buf = _T("replaced\0");\r
+ break;\r
+ case git_wc_status_modified:\r
+ buf = _T("modified\0");\r
+ break;\r
+ case git_wc_status_merged:\r
+ buf = _T("merged\0");\r
+ break;\r
+ case git_wc_status_conflicted:\r
+ buf = _T("conflicted\0");\r
+ break;\r
+ case git_wc_status_obstructed:\r
+ buf = _T("obstructed\0");\r
+ break;\r
+ case git_wc_status_ignored:\r
+ buf = _T("ignored");\r
+ break;\r
+ case git_wc_status_external:\r
+ buf = _T("external");\r
+ break;\r
+ case git_wc_status_incomplete:\r
+ buf = _T("incomplete\0");\r
+ break;\r
+ default:\r
+ buf = _T("\0");\r
+ break;\r
+ }\r
+ _stprintf_s(string, buflen, _T("%s"), buf);\r
+}\r
+\r
+void GitStatus::GetStatusString(HINSTANCE hInst, git_wc_status_kind status, TCHAR * string, int size, WORD lang)\r
+{\r
+ switch (status)\r
+ {\r
+ case git_wc_status_none:\r
+ LoadStringEx(hInst, IDS_STATUSNONE, string, size, lang);\r
+ break;\r
+ case git_wc_status_unversioned:\r
+ LoadStringEx(hInst, IDS_STATUSUNVERSIONED, string, size, lang);\r
+ break;\r
+ case git_wc_status_normal:\r
+ LoadStringEx(hInst, IDS_STATUSNORMAL, string, size, lang);\r
+ break;\r
+ case git_wc_status_added:\r
+ LoadStringEx(hInst, IDS_STATUSADDED, string, size, lang);\r
+ break;\r
+ case git_wc_status_missing:\r
+ LoadStringEx(hInst, IDS_STATUSABSENT, string, size, lang);\r
+ break;\r
+ case git_wc_status_deleted:\r
+ LoadStringEx(hInst, IDS_STATUSDELETED, string, size, lang);\r
+ break;\r
+ case git_wc_status_replaced:\r
+ LoadStringEx(hInst, IDS_STATUSREPLACED, string, size, lang);\r
+ break;\r
+ case git_wc_status_modified:\r
+ LoadStringEx(hInst, IDS_STATUSMODIFIED, string, size, lang);\r
+ break;\r
+ case git_wc_status_merged:\r
+ LoadStringEx(hInst, IDS_STATUSMERGED, string, size, lang);\r
+ break;\r
+ case git_wc_status_conflicted:\r
+ LoadStringEx(hInst, IDS_STATUSCONFLICTED, string, size, lang);\r
+ break;\r
+ case git_wc_status_ignored:\r
+ LoadStringEx(hInst, IDS_STATUSIGNORED, string, size, lang);\r
+ break;\r
+ case git_wc_status_obstructed:\r
+ LoadStringEx(hInst, IDS_STATUSOBSTRUCTED, string, size, lang);\r
+ break;\r
+ case git_wc_status_external:\r
+ LoadStringEx(hInst, IDS_STATUSEXTERNAL, string, size, lang);\r
+ break;\r
+ case git_wc_status_incomplete:\r
+ LoadStringEx(hInst, IDS_STATUSINCOMPLETE, string, size, lang);\r
+ break;\r
+ default:\r
+ LoadStringEx(hInst, IDS_STATUSNONE, string, size, lang);\r
+ break;\r
+ }\r
+}\r
+\r
+#ifdef _MFC_VER\r
+CString GitStatus::GetDepthString(git_depth_t depth)\r
+{\r
+ CString sDepth;\r
+ switch (depth)\r
+ {\r
+ case git_depth_unknown:\r
+ sDepth.LoadString(IDS_Git_DEPTH_UNKNOWN);\r
+ break;\r
+ case git_depth_empty:\r
+ sDepth.LoadString(IDS_Git_DEPTH_EMPTY);\r
+ break;\r
+ case git_depth_files:\r
+ sDepth.LoadString(IDS_Git_DEPTH_FILES);\r
+ break;\r
+ case git_depth_immediates:\r
+ sDepth.LoadString(IDS_Git_DEPTH_IMMEDIATE);\r
+ break;\r
+ case git_depth_infinity:\r
+ sDepth.LoadString(IDS_Git_DEPTH_INFINITE);\r
+ break;\r
+ }\r
+ return sDepth;\r
+}\r
+#endif\r
+\r
+void GitStatus::GetDepthString(HINSTANCE hInst, git_depth_t depth, TCHAR * string, int size, WORD lang)\r
+{\r
+#if 0\r
+ switch (depth)\r
+ {\r
+ case git_depth_unknown:\r
+ LoadStringEx(hInst, IDS_SVN_DEPTH_UNKNOWN, string, size, lang);\r
+ break;\r
+ case git_depth_empty:\r
+ LoadStringEx(hInst, IDS_SVN_DEPTH_EMPTY, string, size, lang);\r
+ break;\r
+ case git_depth_files:\r
+ LoadStringEx(hInst, IDS_SVN_DEPTH_FILES, string, size, lang);\r
+ break;\r
+ case git_depth_immediates:\r
+ LoadStringEx(hInst, IDS_SVN_DEPTH_IMMEDIATE, string, size, lang);\r
+ break;\r
+ case git_depth_infinity:\r
+ LoadStringEx(hInst, IDS_SVN_DEPTH_INFINITE, string, size, lang);\r
+ break;\r
+ }\r
+#endif\r
+}\r
+\r
+\r
+int GitStatus::LoadStringEx(HINSTANCE hInstance, UINT uID, LPTSTR lpBuffer, int nBufferMax, WORD wLanguage)\r
+{\r
+ const STRINGRESOURCEIMAGE* pImage;\r
+ const STRINGRESOURCEIMAGE* pImageEnd;\r
+ ULONG nResourceSize;\r
+ HGLOBAL hGlobal;\r
+ UINT iIndex;\r
+ int ret;\r
+\r
+ HRSRC hResource = FindResourceEx(hInstance, RT_STRING, MAKEINTRESOURCE(((uID>>4)+1)), wLanguage);\r
+ if (!hResource)\r
+ {\r
+ // try the default language before giving up!\r
+ hResource = FindResource(hInstance, MAKEINTRESOURCE(((uID>>4)+1)), RT_STRING);\r
+ if (!hResource)\r
+ return 0;\r
+ }\r
+ hGlobal = LoadResource(hInstance, hResource);\r
+ if (!hGlobal)\r
+ return 0;\r
+ pImage = (const STRINGRESOURCEIMAGE*)::LockResource(hGlobal);\r
+ if(!pImage)\r
+ return 0;\r
+\r
+ nResourceSize = ::SizeofResource(hInstance, hResource);\r
+ pImageEnd = (const STRINGRESOURCEIMAGE*)(LPBYTE(pImage)+nResourceSize);\r
+ iIndex = uID&0x000f;\r
+\r
+ while ((iIndex > 0) && (pImage < pImageEnd))\r
+ {\r
+ pImage = (const STRINGRESOURCEIMAGE*)(LPBYTE(pImage)+(sizeof(STRINGRESOURCEIMAGE)+(pImage->nLength*sizeof(WCHAR))));\r
+ iIndex--;\r
+ }\r
+ if (pImage >= pImageEnd)\r
+ return 0;\r
+ if (pImage->nLength == 0)\r
+ return 0;\r
+\r
+ ret = pImage->nLength;\r
+ if (pImage->nLength > nBufferMax)\r
+ {\r
+ wcsncpy_s(lpBuffer, nBufferMax, pImage->achString, pImage->nLength-1);\r
+ lpBuffer[nBufferMax-1] = 0;\r
+ }\r
+ else\r
+ {\r
+ wcsncpy_s(lpBuffer, nBufferMax, pImage->achString, pImage->nLength);\r
+ lpBuffer[ret] = 0;\r
+ }\r
+ return ret;\r
+}\r
+\r
+#if 0\r
+git_error_t * GitStatus::getallstatus(void * baton, const char * /*path*/, git_wc_status2_t * status, apr_pool_t * /*pool*/)\r
+{\r
+ git_wc_status_kind * s = (git_wc_status_kind *)baton;\r
+ *s = GitStatus::GetMoreImportant(*s, status->text_status);\r
+ *s = GitStatus::GetMoreImportant(*s, status->prop_status);\r
+ return Git_NO_ERROR;\r
+}\r
+#endif\r
+\r
+#if 0\r
+git_error_t * GitStatus::getstatushash(void * baton, const char * path, git_wc_status2_t * status, apr_pool_t * /*pool*/)\r
+{\r
+ hashbaton_t * hash = (hashbaton_t *)baton;\r
+ const StdStrAVector& filterList = hash->pThis->m_filterFileList;\r
+ if (status->text_status == git_wc_status_external)\r
+ {\r
+ apr_hash_set (hash->exthash, apr_pstrdup(hash->pThis->m_pool, path), APR_HASH_KEY_STRING, (const void*)1);\r
+ return Git_NO_ERROR;\r
+ }\r
+ if(filterList.size() > 0)\r
+ {\r
+ // We have a filter active - we're only interested in files which are in \r
+ // the filter \r
+ if(!binary_search(filterList.begin(), filterList.end(), path))\r
+ {\r
+ // This item is not in the filter - don't store it\r
+ return Git_NO_ERROR;\r
+ }\r
+ }\r
+ git_wc_status2_t * statuscopy = git_wc_dup_status2 (status, hash->pThis->m_pool);\r
+ apr_hash_set (hash->hash, apr_pstrdup(hash->pThis->m_pool, path), APR_HASH_KEY_STRING, statuscopy);\r
+ return Git_NO_ERROR;\r
+}\r
+\r
+apr_array_header_t * GitStatus::sort_hash (apr_hash_t *ht,\r
+ int (*comparison_func) (const GitStatus::sort_item *, const GitStatus::sort_item *),\r
+ apr_pool_t *pool)\r
+{\r
+ apr_hash_index_t *hi;\r
+ apr_array_header_t *ary;\r
+\r
+ /* allocate an array with only one element to begin with. */\r
+ ary = apr_array_make (pool, 1, sizeof(sort_item));\r
+\r
+ /* loop over hash table and push all keys into the array */\r
+ for (hi = apr_hash_first (pool, ht); hi; hi = apr_hash_next (hi))\r
+ {\r
+ sort_item *item = (sort_item*)apr_array_push (ary);\r
+\r
+ apr_hash_this (hi, &item->key, &item->klen, &item->value);\r
+ }\r
+\r
+ /* now quick sort the array. */\r
+ qsort (ary->elts, ary->nelts, ary->elt_size,\r
+ (int (*)(const void *, const void *))comparison_func);\r
+\r
+ return ary;\r
+}\r
+\r
+int GitStatus::sort_compare_items_as_paths (const sort_item *a, const sort_item *b)\r
+{\r
+ const char *astr, *bstr;\r
+\r
+ astr = (const char*)a->key;\r
+ bstr = (const char*)b->key;\r
+ return git_path_compare_paths (astr, bstr);\r
+}\r
+#endif\r
+\r
+git_error_t* GitStatus::cancel(void *baton)\r
+{\r
+#if 0\r
+ volatile bool * canceled = (bool *)baton;\r
+ if (*canceled)\r
+ {\r
+ CString temp;\r
+ temp.LoadString(IDS_Git_USERCANCELLED);\r
+ return git_error_create(Git_ERR_CANCELLED, NULL, CUnicodeUtils::GetUTF8(temp));\r
+ }\r
+ return Git_NO_ERROR;\r
+#endif \r
+ return 0;\r
+}\r
+\r
+#ifdef _MFC_VER\r
+\r
+// Set-up a filter to restrict the files which will have their status stored by a get-status\r
+void GitStatus::SetFilter(const CTGitPathList& fileList)\r
+{\r
+ m_filterFileList.clear();\r
+ for(int fileIndex = 0; fileIndex < fileList.GetCount(); fileIndex++)\r
+ {\r
+ m_filterFileList.push_back(fileList[fileIndex].GetGitApiPath(m_pool));\r
+ }\r
+ // Sort the list so that we can do binary searches\r
+ std::sort(m_filterFileList.begin(), m_filterFileList.end());\r
+}\r
+\r
+void GitStatus::ClearFilter()\r
+{\r
+ m_filterFileList.clear();\r
+}\r
+\r
+#endif // _MFC_VER\r
+\r
--- /dev/null
+#pragma once\r
+\r
+#ifdef _MFC_VER\r
+# include "SVNPrompt.h"\r
+#endif\r
+#include "TGitPath.h"\r
+\r
+#pragma warning (push,1)\r
+typedef std::basic_string<wchar_t> wide_string;\r
+#ifdef UNICODE\r
+# define stdstring wide_string\r
+#else\r
+# define stdstring std::string\r
+#endif\r
+#pragma warning (pop)\r
+\r
+#include "TGitPath.h"\r
+\r
+typedef enum type_git_wc_status_kind\r
+{\r
+ git_wc_status_none,\r
+ git_wc_status_unversioned,\r
+ git_wc_status_ignored,\r
+ git_wc_status_normal,\r
+ git_wc_status_external,\r
+ git_wc_status_incomplete,\r
+ git_wc_status_missing,\r
+ git_wc_status_deleted,\r
+ git_wc_status_replaced,\r
+ git_wc_status_modified,\r
+ git_wc_status_merged,\r
+ git_wc_status_added,\r
+ git_wc_status_conflicted,\r
+ git_wc_status_obstructed,\r
+\r
+}git_wc_status_kind;\r
+\r
+typedef enum\r
+{\r
+ git_depth_empty,\r
+ git_depth_infinity,\r
+ git_depth_unknown,\r
+ git_depth_files,\r
+ git_depth_immediates,\r
+}git_depth_t;\r
+\r
+\r
+\r
+typedef CString git_revnum_t;\r
+typedef int git_wc_status2_t;\r
+typedef int git_error_t;\r
+\r
+#define MAX_STATUS_STRING_LENGTH 256\r
+\r
+/**\r
+ * \ingroup Git\r
+ * Handles Subversion status of working copies.\r
+ */\r
+class GitStatus\r
+{\r
+public:\r
+ GitStatus(bool * pbCanceled = NULL);\r
+ ~GitStatus(void);\r
+\r
+\r
+ /**\r
+ * Reads the Subversion status of the working copy entry. No\r
+ * recurse is done, even if the entry is a directory.\r
+ * If the status of the text and property part are different\r
+ * then the more important status is returned.\r
+ */\r
+ static git_wc_status_kind GetAllStatus(const CTGitPath& path, git_depth_t depth = git_depth_empty);\r
+\r
+ /**\r
+ * Reads the Subversion status of the working copy entry and all its\r
+ * subitems. The resulting status is determined by using priorities for\r
+ * each status. The status with the highest priority is then returned.\r
+ * If the status of the text and property part are different then\r
+ * the more important status is returned.\r
+ */\r
+ static git_wc_status_kind GetAllStatusRecursive(const CTGitPath& path);\r
+\r
+ /**\r
+ * Returns the status which is more "important" of the two statuses specified.\r
+ * This is used for the "recursive" status functions on folders - i.e. which status\r
+ * should be returned for a folder which has several files with different statuses\r
+ * in it.\r
+ */ \r
+ static git_wc_status_kind GetMoreImportant(git_wc_status_kind status1, git_wc_status_kind status2);\r
+ \r
+ /**\r
+ * Checks if a status is "important", i.e. if the status indicates that the user should know about it.\r
+ * E.g. a "normal" status is not important, but "modified" is.\r
+ * \param status the status to check\r
+ */\r
+ static BOOL IsImportant(git_wc_status_kind status) {return (GetMoreImportant(git_wc_status_added, status)==status);}\r
+\r
+ /**\r
+ * Reads the Subversion text status of the working copy entry. No\r
+ * recurse is done, even if the entry is a directory.\r
+ * The result is stored in the public member variable status.\r
+ * Use this method if you need detailed information about a file/folder, not just the raw status (like "normal", "modified").\r
+ * \r
+ * \param path the pathname of the entry\r
+ * \param update true if the status should be updated with the repository. Default is false.\r
+ * \return If update is set to true the HEAD revision of the repository is returned. If update is false then -1 is returned.\r
+ * \remark If the return value is -2 then the status could not be obtained.\r
+ */\r
+ git_revnum_t GetStatus(const CTGitPath& path, bool update = false, bool noignore = false, bool noexternals = false);\r
+\r
+ /**\r
+ * Returns a string representation of a Subversion status.\r
+ * \param status the status enum\r
+ * \param string a string representation\r
+ */\r
+ static void GetStatusString(git_wc_status_kind status, size_t buflen, TCHAR * string);\r
+ static void GetStatusString(HINSTANCE hInst, git_wc_status_kind status, TCHAR * string, int size, WORD lang);\r
+\r
+ /**\r
+ * Returns the string representation of a depth.\r
+ */\r
+#ifdef _MFC_VER\r
+ static CString GetDepthString(Git_depth_t depth);\r
+#endif\r
+ static void GetDepthString(HINSTANCE hInst, git_depth_t depth, TCHAR * string, int size, WORD lang);\r
+\r
+ /**\r
+ * Returns the status of the first file of the given path. Use GetNextFileStatus() to obtain\r
+ * the status of the next file in the list.\r
+ * \param path the path of the folder from where the status list should be obtained\r
+ * \param retPath the path of the file for which the status was returned\r
+ * \param update set this to true if you want the status to be updated with the repository (needs network access)\r
+ * \param recurse true to fetch the status recursively\r
+ * \param bNoIgnore true to not fetch the ignored files\r
+ * \param bNoExternals true to not fetch the status of included Git:externals\r
+ * \return the status\r
+ */\r
+ git_wc_status2_t * GetFirstFileStatus(const CTGitPath& path, CTGitPath& retPath, bool update = false, git_depth_t depth = git_depth_infinity, bool bNoIgnore = true, bool bNoExternals = false);\r
+ unsigned int GetFileCount() const {return /*apr_hash_count(m_statushash);*/0;}\r
+ unsigned int GetVersionedCount() const;\r
+ /**\r
+ * Returns the status of the next file in the file list. If no more files are in the list then NULL is returned.\r
+ * See GetFirstFileStatus() for details.\r
+ */\r
+ git_wc_status2_t * GetNextFileStatus(CTGitPath& retPath);\r
+ /**\r
+ * Checks if a path is an external folder.\r
+ * This is necessary since Subversion returns two entries for external folders: one with the status Git_wc_status_external\r
+ * and one with the 'real' status of that folder. GetFirstFileStatus() and GetNextFileStatus() only return the 'real'\r
+ * status, so with this method it's possible to check if the status also is Git_wc_status_external.\r
+ */\r
+ bool IsExternal(const CTGitPath& path) const;\r
+ /**\r
+ * Checks if a path is in an external folder.\r
+ */\r
+ bool IsInExternal(const CTGitPath& path) const;\r
+\r
+ /**\r
+ * Clears the memory pool.\r
+ */\r
+ void ClearPool();\r
+\r
+ /**\r
+ * This member variable hold the status of the last call to GetStatus().\r
+ */\r
+ git_wc_status2_t * status; ///< the status result of GetStatus()\r
+\r
+ git_revnum_t headrev; ///< the head revision fetched with GetFirstStatus()\r
+\r
+ bool * m_pbCanceled;\r
+#ifdef _MFC_VER\r
+friend class Git; // So that Git can get to our m_err\r
+ /**\r
+ * Returns the last error message as a CString object.\r
+ */\r
+ CString GetLastErrorMsg() const;\r
+\r
+ /** \r
+ * Set a list of paths which will be considered when calling GetFirstFileStatus.\r
+ * If a filter is set, then GetFirstFileStatus/GetNextFileStatus will only return items which are in the filter list\r
+ */\r
+ void SetFilter(const CTGitPathList& fileList);\r
+ void ClearFilter();\r
+\r
+#else\r
+ /**\r
+ * Returns the last error message as a CString object.\r
+ */\r
+ stdstring GetLastErrorMsg() const;\r
+#endif\r
+\r
+\r
+protected:\r
+// apr_pool_t * m_pool; ///< the memory pool\r
+private:\r
+ typedef struct sort_item\r
+ {\r
+ const void *key;\r
+// apr_ssize_t klen;\r
+ void *value;\r
+ } sort_item;\r
+\r
+ typedef struct hashbaton_t\r
+ {\r
+ GitStatus* pThis;\r
+// apr_hash_t * hash;\r
+// apr_hash_t * exthash;\r
+ } hash_baton_t;\r
+\r
+// git_client_ctx_t * ctx;\r
+ git_wc_status_kind m_allstatus; ///< used by GetAllStatus and GetAllStatusRecursive\r
+ git_error_t * m_err; ///< Subversion error baton\r
+\r
+#ifdef _MFC_VER\r
+ GitPrompt m_prompt;\r
+#endif\r
+\r
+ /**\r
+ * Returns a numeric value indicating the importance of a status. \r
+ * A higher number indicates a more important status.\r
+ */\r
+ static int GetStatusRanking(git_wc_status_kind status);\r
+\r
+ /**\r
+ * Callback function which collects the raw status from a Git_client_status() function call\r
+ */\r
+// static git_error_t * getallstatus (void *baton, const char *path, git_wc_status2_t *status, apr_pool_t *pool);\r
+\r
+ /**\r
+ * Callback function which stores the raw status from a Git_client_status() function call\r
+ * in a hash table.\r
+ */\r
+// static git_error_t * getstatushash (void *baton, const char *path, git_wc_status2_t *status, apr_pool_t *pool);\r
+\r
+ /**\r
+ * helper function to sort a hash to an array\r
+ */\r
+// static apr_array_header_t * sort_hash (apr_hash_t *ht, int (*comparison_func) (const sort_item *,\r
+// const sort_item *), apr_pool_t *pool);\r
+\r
+ /**\r
+ * Callback function used by qsort() which does the comparison of two elements\r
+ */\r
+ static int __cdecl sort_compare_items_as_paths (const sort_item *a, const sort_item *b);\r
+\r
+ //for GetFirstFileStatus and GetNextFileStatus\r
+// apr_hash_t * m_statushash;\r
+// apr_array_header_t * m_statusarray;\r
+ unsigned int m_statushashindex;\r
+// apr_hash_t * m_externalhash;\r
+\r
+#pragma warning(push)\r
+#pragma warning(disable: 4200)\r
+ struct STRINGRESOURCEIMAGE\r
+ {\r
+ WORD nLength;\r
+ WCHAR achString[];\r
+ };\r
+#pragma warning(pop) // C4200\r
+\r
+ static int LoadStringEx(HINSTANCE hInstance, UINT uID, LPTSTR lpBuffer, int nBufferMax, WORD wLanguage);\r
+ static git_error_t* cancel(void *baton);\r
+\r
+ // A sorted list of filenames (in Git format, in lowercase) \r
+ // when this list is set, we only pick-up files during a GetStatus which are found in this list\r
+ typedef std::vector<std::string> StdStrAVector;\r
+ StdStrAVector m_filterFileList;\r
+};\r
+\r
+\r
+
\ No newline at end of file
--- /dev/null
+#include "StdAfx.h"\r
+#include "TGitPath.h"\r
+\r
+CTGitPath::CTGitPath(void)\r
+{\r
+}\r
+\r
+CTGitPath::~CTGitPath(void)\r
+{\r
+}\r
--- /dev/null
+#pragma once\r
+\r
+class CTGitPath\r
+{\r
+public:\r
+ CTGitPath(void);\r
+ ~CTGitPath(void);\r
+ public:\r
+ /**\r
+ * Set the path as an UTF8 string with forward slashes\r
+ */\r
+ void SetFromGit(const char* pPath);\r
+ void SetFromGit(const char* pPath, bool bIsDirectory);\r
+ void SetFromGit(const CString& sPath);\r
+ /**\r
+ * Set the path as UNICODE with backslashes\r
+ */\r
+ void SetFromWin(LPCTSTR pPath);\r
+ void SetFromWin(const CString& sPath);\r
+ void SetFromWin(const CString& sPath, bool bIsDirectory);\r
+ /**\r
+ * Set the path from an unknown source.\r
+ */\r
+ void SetFromUnknown(const CString& sPath);\r
+ /**\r
+ * Returns the path in Windows format, i.e. with backslashes\r
+ */\r
+ LPCTSTR GetWinPath() const;\r
+ /**\r
+ * Returns the path in Windows format, i.e. with backslashes\r
+ */\r
+ const CString& GetWinPathString() const;\r
+ /**\r
+ * Returns the path with forward slashes.\r
+ */\r
+ const CString& GetGitPathString() const;\r
+ /**\r
+ * Returns the path completely prepared to be fed the the Git APIs\r
+ * It will be in UTF8, with URLs escaped, if necessary\r
+ */\r
+// const char* GetGitApiPath(apr_pool_t *pool) const;\r
+ /**\r
+ * Returns the path for showing in an UI.\r
+ *\r
+ * URL's are returned with forward slashes, unescaped if necessary\r
+ * Paths are returned with backward slashes\r
+ */\r
+ const CString& GetUIPathString() const;\r
+ /**\r
+ * Checks if the path is an URL.\r
+ */\r
+ bool IsUrl() const;\r
+ /**\r
+ * Returns true if the path points to a directory\r
+ */\r
+ bool IsDirectory() const;\r
+ /**\r
+ * Returns the directory. If the path points to a directory, then the path\r
+ * is returned unchanged. If the path points to a file, the path to the \r
+ * parent directory is returned.\r
+ */\r
+ CTGitPath GetDirectory() const;\r
+ /**\r
+ * Returns the the directory which contains the item the path refers to.\r
+ * If the path is a directory, then this returns the directory above it.\r
+ * If the path is to a file, then this returns the directory which contains the path\r
+ * parent directory is returned.\r
+ */\r
+ CTGitPath GetContainingDirectory() const;\r
+ /**\r
+ * Get the 'root path' (e.g. "c:\") - Used to pass to GetDriveType \r
+ */\r
+ CString GetRootPathString() const;\r
+ /**\r
+ * Returns the filename part of the full path.\r
+ * \remark don't call this for directories.\r
+ */\r
+ CString GetFilename() const;\r
+ /**\r
+ * Returns the item's name without the full path.\r
+ */\r
+ CString GetFileOrDirectoryName() const;\r
+ /**\r
+ * Returns the item's name without the full path, unescaped if necessary.\r
+ */\r
+ CString GetUIFileOrDirectoryName() const;\r
+ /**\r
+ * Returns the file extension, including the dot.\r
+ * \remark Returns an empty string for directories\r
+ */\r
+ CString GetFileExtension() const;\r
+\r
+ bool IsEmpty() const;\r
+ void Reset();\r
+ /**\r
+ * Checks if two paths are equal. The slashes are taken care of.\r
+ */\r
+ bool IsEquivalentTo(const CTGitPath& rhs) const;\r
+ bool IsEquivalentToWithoutCase(const CTGitPath& rhs) const;\r
+ bool operator==(const CTGitPath& x) const {return IsEquivalentTo(x);}\r
+ \r
+ /**\r
+ * Checks if \c possibleDescendant is a child of this path.\r
+ */\r
+ bool IsAncestorOf(const CTGitPath& possibleDescendant) const;\r
+ /**\r
+ * Get a string representing the file path, optionally with a base \r
+ * section stripped off the front\r
+ * Returns a string with fwdslash paths \r
+ */\r
+ CString GetDisplayString(const CTGitPath* pOptionalBasePath = NULL) const;\r
+ /**\r
+ * Compares two paths. Slash format is irrelevant.\r
+ */\r
+ static int Compare(const CTGitPath& left, const CTGitPath& right);\r
+\r
+ /** As PredLeftLessThanRight, but for checking if paths are equivalent \r
+ */\r
+ static bool PredLeftEquivalentToRight(const CTGitPath& left, const CTGitPath& right);\r
+\r
+ /** Checks if the left path is pointing to the same working copy path as the right.\r
+ * The same wc path means the paths are equivalent once all the admin dir path parts\r
+ * are removed. This is used in the TGitCache crawler to filter out all the 'duplicate'\r
+ * paths to crawl.\r
+ */\r
+ static bool PredLeftSameWCPathAsRight(const CTGitPath& left, const CTGitPath& right);\r
+ \r
+ static bool CheckChild(const CTGitPath &parent, const CTGitPath& child);\r
+\r
+ /**\r
+ * appends a string to this path. \r
+ *\remark - missing slashes are not added - this is just a string concatenation, but with\r
+ * preservation of the proper caching behavior.\r
+ * If you want to join a file- or directory-name onto the path, you should use AppendPathString\r
+ */\r
+ void AppendRawString(const CString& sAppend);\r
+\r
+ /**\r
+ * appends a part of a path to this path. \r
+ *\remark - missing slashes are dealt with properly. Don't use this to append a file extension, for example\r
+ * \r
+ */\r
+ void AppendPathString(const CString& sAppend);\r
+\r
+ /**\r
+ * Get the file modification time - returns zero for files which don't exist\r
+ * Returns a FILETIME structure cast to an __int64, for easy comparisons\r
+ */\r
+ __int64 GetLastWriteTime() const;\r
+ \r
+ bool IsReadOnly() const;\r
+ \r
+ /**\r
+ * Checks if the path really exists.\r
+ */\r
+ bool Exists() const;\r
+ \r
+ /**\r
+ * Deletes the file/folder\r
+ * \param bTrash if true, uses the Windows trash bin when deleting.\r
+ */\r
+ bool Delete(bool bTrash) const;\r
+\r
+ /**\r
+ * Checks if a Subversion admin directory is present. For files, the check\r
+ * is done in the same directory. For folders, it checks if the folder itself\r
+ * contains an admin directory.\r
+ */\r
+ bool HasAdminDir() const;\r
+ \r
+ /**\r
+ * Checks if the path point to or below a Subversion admin directory (.Git).\r
+ */\r
+ bool IsAdminDir() const;\r
+\r
+ void SetCustomData(LPARAM lp) {m_customData = lp;}\r
+ LPARAM GetCustomData() {return m_customData;}\r
+\r
+ /**\r
+ * Checks if the path or URL is valid on Windows.\r
+ * A path is valid if conforms to the specs in the windows API.\r
+ * An URL is valid if the path checked out from it is valid\r
+ * on windows. That means an URL which is valid according to the WWW specs\r
+ * isn't necessarily valid as a windows path (e.g. http://myserver.com/repos/file:name \r
+ * is a valid URL, but the path is illegal on windows ("file:name" is illegal), so\r
+ * this function would return \c false for that URL).\r
+ */\r
+ bool IsValidOnWindows() const;\r
+\r
+ /**\r
+ * Checks to see if the path or URL represents one of the special directories\r
+ * (branches, tags, or trunk).\r
+ */\r
+ bool IsSpecialDirectory() const;\r
+private:\r
+ // All these functions are const, and all the data\r
+ // is mutable, in order that the hidden caching operations\r
+ // can be carried out on a const CTGitPath object, which is what's \r
+ // likely to be passed between functions\r
+ // The public 'SetFromxxx' functions are not const, and so the proper \r
+ // const-correctness semantics are preserved\r
+ void SetFwdslashPath(const CString& sPath) const;\r
+ void SetBackslashPath(const CString& sPath) const;\r
+ void SetUTF8FwdslashPath(const CString& sPath) const;\r
+ void EnsureBackslashPathSet() const;\r
+ void EnsureFwdslashPathSet() const;\r
+ /**\r
+ * Checks if two path strings are equal. No conversion of slashes is done!\r
+ * \remark for slash-independent comparison, use IsEquivalentTo()\r
+ */\r
+ static bool ArePathStringsEqual(const CString& sP1, const CString& sP2);\r
+ static bool ArePathStringsEqualWithCase(const CString& sP1, const CString& sP2);\r
+ \r
+ /**\r
+ * Adds the required trailing slash to local root paths such as 'C:'\r
+ */\r
+ void SanitizeRootPath(CString& sPath, bool bIsForwardPath) const;\r
+\r
+ void UpdateAttributes() const;\r
+\r
+private:\r
+ mutable CString m_sBackslashPath;\r
+ mutable CString m_sFwdslashPath;\r
+ mutable CString m_sUIPath;\r
+ mutable CStringA m_sUTF8FwdslashPath;\r
+ mutable CStringA m_sUTF8FwdslashPathEscaped;\r
+ // Have we yet determined if this is a directory or not?\r
+ mutable bool m_bDirectoryKnown;\r
+ mutable bool m_bIsDirectory;\r
+ mutable bool m_bLastWriteTimeKnown;\r
+ mutable bool m_bURLKnown;\r
+ mutable bool m_bIsURL;\r
+ mutable __int64 m_lastWriteTime;\r
+ mutable bool m_bIsReadOnly;\r
+ mutable bool m_bHasAdminDirKnown;\r
+ mutable bool m_bHasAdminDir;\r
+ mutable bool m_bIsValidOnWindowsKnown;\r
+ mutable bool m_bIsValidOnWindows;\r
+ mutable bool m_bIsAdminDirKnown;\r
+ mutable bool m_bIsAdminDir;\r
+ mutable bool m_bExists;\r
+ mutable bool m_bExistsKnown;\r
+ mutable LPARAM m_customData;\r
+ mutable bool m_bIsSpecialDirectoryKnown;\r
+ mutable bool m_bIsSpecialDirectory;\r
+\r
+ friend bool operator<(const CTGitPath& left, const CTGitPath& right);\r
+};\r
+/**\r
+ * Compares two paths and return true if left is earlier in sort order than right\r
+ * (Uses CTGitPath::Compare logic, but is suitable for std::sort and similar)\r
+ */\r
+ bool operator<(const CTGitPath& left, const CTGitPath& right);\r
+\r
+\r
+//////////////////////////////////////////////////////////////////////////\r
+\r
+/**\r
+ * \ingroup Utils\r
+ * This class represents a list of paths\r
+ */\r
+class CTGitPathList \r
+{\r
+public:\r
+ CTGitPathList();\r
+ // A constructor which allows a path list to be easily built with one initial entry in\r
+ explicit CTGitPathList(const CTGitPath& firstEntry);\r
+\r
+public:\r
+ void AddPath(const CTGitPath& newPath);\r
+ bool LoadFromFile(const CTGitPath& filename);\r
+ bool WriteToFile(const CString& sFilename, bool bANSI = false) const;\r
+\r
+ /**\r
+ * Load from the path argument string, when the 'path' parameter is used\r
+ * This is a list of paths, with '*' between them\r
+ */\r
+ void LoadFromAsteriskSeparatedString(const CString& sPathString);\r
+ CString CreateAsteriskSeparatedString() const;\r
+\r
+ int GetCount() const;\r
+ void Clear();\r
+ const CTGitPath& operator[](INT_PTR index) const;\r
+ bool AreAllPathsFiles() const;\r
+ bool AreAllPathsFilesInOneDirectory() const;\r
+ CTGitPath GetCommonDirectory() const;\r
+ CTGitPath GetCommonRoot() const;\r
+ void SortByPathname(bool bReverse = false);\r
+ /** \r
+ * Delete all the files in the list, then clear the list.\r
+ * \param bTrash if true, the items are deleted using the Windows trash bin\r
+ */\r
+ void DeleteAllFiles(bool bTrash);\r
+ /** Remove duplicate entries from the list (sorts the list as a side-effect */\r
+ void RemoveDuplicates();\r
+ /** Removes all paths which are on or in a Subversion admin directory */\r
+ void RemoveAdminPaths();\r
+ void RemovePath(const CTGitPath& path);\r
+ /** \r
+ * Removes all child items and leaves only the top folders. Useful if you\r
+ * create the list to remove them (i.e. if you remove a parent folder, the\r
+ * child files and folders don't have to be deleted anymore)\r
+ */\r
+ void RemoveChildren();\r
+\r
+ /** Checks if two CTGitPathLists are the same */\r
+ bool IsEqual(const CTGitPathList& list);\r
+\r
+ /** Convert into the Git API parameter format */\r
+// apr_array_header_t * MakePathArray (apr_pool_t *pool) const;\r
+\r
+private:\r
+ typedef std::vector<CTGitPath> PathVector;\r
+ PathVector m_paths;\r
+ // If the list contains just files in one directory, then\r
+ // this contains the directory name\r
+ mutable CTGitPath m_commonBaseDirectory;\r
+};\r