#ifndef _WINGIT_H_\r
#define _WINGIT_H_\r
\r
-#define WG_VERSION "0.1.3"\r
+#define WG_VERSION "0.1.6"\r
\r
\r
#define DLLIMPORT __declspec(dllimport) __stdcall\r
{\r
WGEFF_NoRecurse = (1<<0), // only enumerate files directly in the specified path\r
WGEFF_FullPath = (1<<1), // enumerated filenames are specified with full path (instead of relative to proj root)\r
- WGEFF_DirStatusDelta= (1<<2), // include directories, in enumeration, that have a recursive status != WGFS_Normal\r
- WGEFF_DirStatusAll = (1<<3) // include directories, in enumeration, with recursive status\r
+ WGEFF_DirStatusDelta= (1<<2), // include directories, in enumeration, that have a recursive status != WGFS_Normal (may have a slightly better performance than WGEFF_DirStatusAll)\r
+ WGEFF_DirStatusAll = (1<<3), // include directories, in enumeration, with recursive status\r
+ WGEFF_EmptyAsNormal = (1<<4), // report sub-directories, with no versioned files, as WGFS_Normal instead of WGFS_Empty\r
+ WGEFF_SingleFile = (1<<5) // indicates that the status of a single file or dir, specified by pszSubPath, is wanted\r
};\r
\r
+// NOTE: Special behavior for directories when specifying WGEFF_SingleFile:\r
+//\r
+// * when combined with WGEFF_SingleFile the returned status will only reflect the immediate files in the dir,\r
+// NOT the recusrive status of immediate sub-dirs\r
+// * unlike a normal enumeration where the project root dir always is returned as WGFS_Normal regardless\r
+// of WGEFF_EmptyAsNormal, the project root will return WGFS_Empty if no immediate versioned files\r
+// unless WGEFF_EmptyAsNormal is specified\r
+// * WGEFF_DirStatusDelta and WGEFF_DirStatusAll are ignored and can be omitted even for dirs\r
+\r
\r
// File status\r
enum WGFILESTATUS\r
WGFS_Modified,\r
WGFS_Deleted,\r
\r
- WGFS_Unknown = -1\r
+ WGFS_Unknown = -1,\r
+ WGFS_Empty = -2\r
};\r
\r
\r
int nStatus; // the WGFILESTATUS of the file\r
int nStage; // the stage number of the file (0 if unstaged)\r
int nFlags; // a combination of WGFILEFLAGS\r
+\r
+ const BYTE* sha1; // points to the BYTE[20] sha1 (NULL for directories, WGFF_Directory)\r
};\r
\r
\r
// Application-defined callback function for wgEnumFiles, returns TRUE to abort enumeration\r
+// NOTE: do NOT store the pFile pointer or any pointers in wgFile_s for later use, the data is only valid for a single callback call\r
typedef BOOL (__cdecl WGENUMFILECB)(const struct wgFile_s *pFile, void *pUserData);\r
\r
\r
// Ex: wgEnumFiles("C:\\Projects\\MyProject", "src/core", WGEFF_NoRecurse, MyEnumFunc, NULL)\r
BOOL WINGIT_API wgEnumFiles(const char *pszProjectPath, const char *pszSubPath, unsigned int nFlags, WGENUMFILECB *pEnumCb, void *pUserData);\r
\r
+// Get the SHA1 of pszName (NULL is same as "HEAD", "HEAD^" etc. expression allowed), returns NULL on failure\r
+// NOTE: do not store returned pointer for later used, data must be used/copied right away before further wg calls\r
+LPBYTE WINGIT_API wgGetRevisionID(const char *pszProjectPath, const char *pszName);\r
+\r
\r
#ifdef __cplusplus\r
}\r
// rev.kind = git_opt_revision_unspecified;\r
statuskind = git_wc_status_none;\r
\r
- // TODO: not sure what to do with recursivenes, it's very unclear exactly what svn does, wingit will however return\r
- // the correct (recursive) status for folders, so WGEFF_NoRecurse can be specified to avoid unecessary processing\r
- //const BOOL bIsRecursive = (depth == git_depth_infinity || depth == git_depth_unknown); // taken from SVN source\r
- UINT nFlags = WGEFF_DirStatusAll;\r
- //if (!bIsRecursive)\r
- nFlags |= WGEFF_NoRecurse;\r
+ const BOOL bIsRecursive = (depth == git_depth_infinity || depth == git_depth_unknown); // taken from SVN source\r
\r
LPCSTR lpszSubPath = NULL;\r
CStringA sSubPath;\r
lpszSubPath = sSubPath;\r
}\r
\r
+#if 1\r
+ // when recursion enabled, let wingit determine the recursive status for folders instead of enumerating all files here\r
+ UINT nFlags = WGEFF_SingleFile;\r
+ if (!bIsRecursive)\r
+ nFlags |= WGEFF_NoRecurse;\r
+ if (!lpszSubPath)\r
+ // report root dir as normal (otherwise it could be considered git_wc_status_unversioned, which would be wrong?)\r
+ nFlags |= WGEFF_EmptyAsNormal;\r
+#else\r
+ // enumerate all files, recursively if requested\r
+ UINT nFlags = 0;\r
+ if (!bIsRecursive)\r
+ nFlags |= WGEFF_NoRecurse;\r
+#endif\r
+\r
err = !wgEnumFiles(CStringA(sProjectRoot), lpszSubPath, nFlags, &getallstatus, &statuskind);\r
\r
/*err = git_client_status4 (&youngest,\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
+ // NOTE: unlike the SVN version this one does not cache the enumerated files, because in practice no code in all of\r
+ // Tortoise uses this, all places that call GetStatus create a temp GitStatus object which gets destroyed right\r
+ // after the call again\r
+\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
+// 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
+\r
+ CString sProjectRoot;\r
+ if ( !path.HasAdminDir(&sProjectRoot) )\r
+ return youngest;\r
+\r
struct hashbaton_t hashbaton;\r
- hashbaton.hash = statushash;\r
- hashbaton.exthash = exthash;\r
+// hashbaton.hash = statushash;\r
+// hashbaton.exthash = exthash;\r
hashbaton.pThis = this;\r
- m_err = git_client_status4 (&youngest,\r
+\r
+ LPCSTR lpszSubPath = NULL;\r
+ CStringA sSubPath;\r
+ CString s = path.GetDirectory().GetWinPathString();\r
+ if (s.GetLength() > sProjectRoot.GetLength())\r
+ {\r
+ sSubPath = CStringA(s.Right(s.GetLength() - sProjectRoot.GetLength() - 1/*otherwise it gets initial slash*/));\r
+ lpszSubPath = sSubPath;\r
+ }\r
+\r
+ // when recursion enabled, let wingit determine the recursive status for folders instead of enumerating all files here\r
+ UINT nFlags = WGEFF_SingleFile | WGEFF_NoRecurse;\r
+ if (!lpszSubPath)\r
+ // report root dir as normal (otherwise it could be considered git_wc_status_unversioned, which would be wrong?)\r
+ nFlags |= WGEFF_EmptyAsNormal;\r
+\r
+ m_status.prop_status = m_status.text_status = git_wc_status_none;\r
+\r
+ m_err = !wgEnumFiles(CStringA(sProjectRoot), lpszSubPath, nFlags, &getstatus, &m_status);\r
+\r
+ /*m_err = git_client_status4 (&youngest,\r
path.GetGitApiPath(m_pool),\r
&rev,\r
getstatushash,\r
noexternals,\r
NULL,\r
ctx,\r
- m_pool);\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
+ if ((m_err != NULL) || /*(apr_hash_count(statushash) == 0)*/m_status.prop_status == git_wc_status_none)\r
{\r
status = NULL;\r
- return -2; \r
+// return -2; \r
+ return GIT_INVALID_REVNUM;\r
}\r
\r
// Convert the unordered hash to an ordered, sorted array\r
- statusarray = sort_hash (statushash,\r
+ /*statusarray = sort_hash (statushash,\r
sort_compare_items_as_paths,\r
- m_pool);\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
+// item = &APR_ARRAY_IDX (statusarray, 0, const sort_item);\r
\r
+// status = (git_wc_status2_t *) item->value;\r
+ status = &m_status;\r
+\r
+ if (update)\r
+ {\r
+ const BYTE *sha1 = wgGetRevisionID(CStringA(sProjectRoot), NULL);\r
+ if (sha1)\r
+ youngest = ConvertHashToRevnum(sha1);\r
+ }\r
+\r
return youngest;\r
-#endif\r
- return CString("");\r
}\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
return FALSE;\r
}\r
\r
+BOOL GitStatus::getstatus(const struct wgFile_s *pFile, void *pUserData)\r
+{\r
+ git_wc_status2_t * s = (git_wc_status2_t*)pUserData;\r
+ s->prop_status = s->text_status = GitStatus::GetMoreImportant(s->prop_status, GitStatusFromWingit(pFile->nStatus));\r
+ return FALSE;\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
\r
\r
#define GIT_REV_ZERO _T("0000000000000000000000000000000000000000")\r
+#define GIT_INVALID_REVNUM _T("")\r
typedef CString git_revnum_t;\r
typedef int git_error_t;\r
\r
case WGFS_Normal: return git_wc_status_normal;\r
case WGFS_Modified: return git_wc_status_modified;\r
case WGFS_Deleted: return git_wc_status_deleted;\r
+\r
+ case WGFS_Empty: return git_wc_status_unversioned;\r
}\r
\r
return git_wc_status_none;\r
}\r
\r
+// convert 20 byte sha1 hash to the git_revnum_t type\r
+inline static git_revnum_t ConvertHashToRevnum(const BYTE *sha1)\r
+{\r
+ if (!sha1)\r
+ return GIT_INVALID_REVNUM;\r
+\r
+ char s[41];\r
+ char *p = s;\r
+ for (int i=0; i<20; i++)\r
+ {\r
+#pragma warning(push)\r
+#pragma warning(disable: 4996)\r
+ sprintf(p, "%02x", (UINT)*sha1);\r
+#pragma warning(pop)\r
+ p += 2;\r
+ sha1++;\r
+ }\r
+\r
+ return CString(s);\r
+}\r
+\r
\r
/**\r
* \ingroup Git\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
+// git_error_t * m_err; ///< Subversion error baton\r
+ BOOL m_err;\r
+\r
+ git_wc_status2_t m_status; // used for GetStatus\r
\r
#ifdef _MFC_VER\r
// GitPrompt m_prompt;\r
*/\r
//static git_error_t * getallstatus (void *baton, const char *path, git_wc_status2_t *status, apr_pool_t *pool);\r
static BOOL getallstatus(const struct wgFile_s *pFile, void *pUserData);\r
+ static BOOL getstatus(const struct wgFile_s *pFile, void *pUserData);\r
\r
/**\r
* Callback function which stores the raw status from a Git_client_status() function call\r