From 42a9ad78cae0927c584faed0cabc6feb1fbbde6c Mon Sep 17 00:00:00 2001 From: Myagi Date: Mon, 16 Feb 2009 19:46:51 +0100 Subject: [PATCH] initial TGitCache support added --- src/Git/GitFolderStatus.cpp | 3 +- src/Git/GitFolderStatus.h | 2 +- src/Git/GitStatus.h | 11 ++ src/TGitCache/CacheInterface.h | 2 +- src/TGitCache/CachedDirectory.cpp | 238 +++++++++++++++++++++++++++------ src/TGitCache/CachedDirectory.h | 9 +- src/TGitCache/FolderCrawler.cpp | 12 +- src/TGitCache/StatusCacheEntry.cpp | 28 ++-- src/TortoiseShell/ColumnProvider.cpp | 16 +-- src/TortoiseShell/IconOverlay.cpp | 15 +-- src/TortoiseShell/RemoteCacheLink.cpp | 12 +- src/TortoiseShell/ShellCache.h | 6 +- src/TortoiseShell/ShellExt.cpp | 2 +- src/TortoiseShell/ShellExt.h | 2 +- src/TortoiseShell/TortoiseShell.vcproj | 4 + 15 files changed, 271 insertions(+), 91 deletions(-) diff --git a/src/Git/GitFolderStatus.cpp b/src/Git/GitFolderStatus.cpp index d56ec30..507070b 100644 --- a/src/Git/GitFolderStatus.cpp +++ b/src/Git/GitFolderStatus.cpp @@ -429,7 +429,8 @@ BOOL GitFolderStatus::fillstatusmap(const struct wgFile_s *pFile, void *pUserDat s.author = Stat->authors.GetString(NULL); s.url = Stat->urls.GetString(NULL); -// s.rev = -1; + if (pFile->sha1) + s.rev = ConvertHashToRevnum(pFile->sha1); s.owner = Stat->owners.GetString(NULL); s.status = git_wc_status_none; diff --git a/src/Git/GitFolderStatus.h b/src/Git/GitFolderStatus.h index d2febc5..646d7f3 100644 --- a/src/Git/GitFolderStatus.h +++ b/src/Git/GitFolderStatus.h @@ -78,7 +78,7 @@ typedef struct FileStatusCacheEntry const char* url; ///< points to a (possibly) shared value const char* owner; ///< points to a (possible) lock owner bool needslock; - //git_revnum_t rev; + git_revnum_t rev; int askedcounter; //git_lock_t * lock; bool tree_conflict; diff --git a/src/Git/GitStatus.h b/src/Git/GitStatus.h index 2370184..aa21fa3 100644 --- a/src/Git/GitStatus.h +++ b/src/Git/GitStatus.h @@ -50,6 +50,15 @@ typedef enum typedef CString git_revnum_t; typedef int git_error_t; +typedef struct git_wc_entry_t +{ + // url in repository + const char *url; + + TCHAR cmt_rev[41]; +} git_wc_entry_t; + + typedef struct git_wc_status2_t { /** The status of the entries text. */ @@ -57,6 +66,8 @@ typedef struct git_wc_status2_t /** The status of the entries properties. */ git_wc_status_kind prop_status; + + //git_wc_entry_t *entry; }git_wc_status2; #define MAX_STATUS_STRING_LENGTH 256 diff --git a/src/TGitCache/CacheInterface.h b/src/TGitCache/CacheInterface.h index 4a28d78..705e3d5 100644 --- a/src/TGitCache/CacheInterface.h +++ b/src/TGitCache/CacheInterface.h @@ -72,7 +72,7 @@ struct TSVNCacheRequest struct TSVNCacheResponse { git_wc_status2_t m_status; -// svn_wc_entry_t m_entry; + git_wc_entry_t m_entry; git_node_kind_t m_kind; char m_url[INTERNET_MAX_URL_LENGTH+1]; char m_owner[255]; ///< owner of the lock diff --git a/src/TGitCache/CachedDirectory.cpp b/src/TGitCache/CachedDirectory.cpp index b77f0ad..3edd90b 100644 --- a/src/TGitCache/CachedDirectory.cpp +++ b/src/TGitCache/CachedDirectory.cpp @@ -25,8 +25,8 @@ CCachedDirectory::CCachedDirectory(void) { - m_entriesFileTime = 0; - m_propsFileTime = 0; + m_indexFileTime = 0; +// m_propsFileTime = 0; m_currentStatusFetchingPathTicks = 0; m_bCurrentFullStatusValid = false; m_currentFullStatus = m_mostImportantFileStatus = git_wc_status_none; @@ -42,8 +42,8 @@ CCachedDirectory::CCachedDirectory(const CTGitPath& directoryPath) ATLASSERT(directoryPath.IsDirectory() || !PathFileExists(directoryPath.GetWinPath())); m_directoryPath = directoryPath; - m_entriesFileTime = 0; - m_propsFileTime = 0; + m_indexFileTime = 0; +// m_propsFileTime = 0; m_currentStatusFetchingPathTicks = 0; m_bCurrentFullStatusValid = false; m_currentFullStatus = m_mostImportantFileStatus = git_wc_status_none; @@ -88,8 +88,8 @@ BOOL CCachedDirectory::SaveToDisk(FILE * pFile) WRITEVALUETOFILE(status); } } - WRITEVALUETOFILE(m_entriesFileTime); - WRITEVALUETOFILE(m_propsFileTime); + WRITEVALUETOFILE(m_indexFileTime); +// WRITEVALUETOFILE(m_propsFileTime); value = m_directoryPath.GetWinPathString().GetLength(); WRITEVALUETOFILE(value); if (value) @@ -156,8 +156,8 @@ BOOL CCachedDirectory::LoadFromDisk(FILE * pFile) m_childDirectories[CTGitPath(sPath)] = status; } } - LOADVALUEFROMFILE(m_entriesFileTime); - LOADVALUEFROMFILE(m_propsFileTime); + LOADVALUEFROMFILE(m_indexFileTime); +// LOADVALUEFROMFILE(m_propsFileTime); LOADVALUEFROMFILE(value); if (value > MAX_PATH) return false; @@ -195,43 +195,48 @@ CStatusCacheEntry CCachedDirectory::GetStatusForMember(const CTGitPath& path, bo { bRequestForSelf = true; } - +//OutputDebugStringA("GetStatusForMember: ");OutputDebugStringW(path.GetWinPathString());OutputDebugStringA("\r\n"); // In all most circumstances, we ask for the status of a member of this directory. ATLASSERT(m_directoryPath.IsEquivalentToWithoutCase(path.GetContainingDirectory()) || bRequestForSelf); - // Check if the entries file has been changed - CTGitPath entriesFilePath(m_directoryPath); - CTGitPath propsDirPath(m_directoryPath); + CString sProjectRoot; + const BOOL bIsVersionedPath = m_directoryPath.HasAdminDir(&sProjectRoot); + + // Check if the index file has been changed + CTGitPath indexFilePath(bIsVersionedPath ? sProjectRoot : m_directoryPath); +// CTGitPath propsDirPath(m_directoryPath); if (g_GitAdminDir.IsVSNETHackActive()) { - entriesFilePath.AppendPathString(g_GitAdminDir.GetVSNETAdminDirName() + _T("\\entries")); - propsDirPath.AppendPathString(g_GitAdminDir.GetVSNETAdminDirName() + _T("\\dir-props")); + indexFilePath.AppendPathString(g_GitAdminDir.GetVSNETAdminDirName() + _T("\\index")); +// propsDirPath.AppendPathString(g_GitAdminDir.GetVSNETAdminDirName() + _T("\\dir-props")); } else { - entriesFilePath.AppendPathString(g_GitAdminDir.GetAdminDirName() + _T("\\entries")); - propsDirPath.AppendPathString(g_GitAdminDir.GetAdminDirName() + _T("\\dir-props")); + indexFilePath.AppendPathString(g_GitAdminDir.GetAdminDirName() + _T("\\index")); +// propsDirPath.AppendPathString(g_GitAdminDir.GetAdminDirName() + _T("\\dir-props")); } - if ( (m_entriesFileTime == entriesFilePath.GetLastWriteTime()) && ((entriesFilePath.GetLastWriteTime() == 0) || (m_propsFileTime == propsDirPath.GetLastWriteTime())) ) + if ( (m_indexFileTime == indexFilePath.GetLastWriteTime()) /*&& ((indexFilePath.GetLastWriteTime() == 0) || (m_propsFileTime == propsDirPath.GetLastWriteTime()))*/ ) { - m_entriesFileTime = entriesFilePath.GetLastWriteTime(); - if (m_entriesFileTime) - m_propsFileTime = propsDirPath.GetLastWriteTime(); +// m_indexFileTime = indexFilePath.GetLastWriteTime(); +// if (m_indexFileTime) +// m_propsFileTime = propsDirPath.GetLastWriteTime(); - if(m_entriesFileTime == 0) + //if(m_indexFileTime == 0) + // a newly created project (without commits) has no index file but we still want it to count as versioned + if(m_indexFileTime == 0 && !bIsVersionedPath) { // We are a folder which is not in a working copy bThisDirectoryIsUnversioned = true; m_ownStatus.SetStatus(NULL); - // If a user removes the .svn directory, we get here with m_entryCache + // If a user removes the .git directory, we get here with m_entryCache // not being empty, but still us being unversioned if (!m_entryCache.empty()) { m_entryCache.clear(); } ATLASSERT(m_entryCache.empty()); - + // However, a member *DIRECTORY* might be the top of WC // so we need to ask them to get their own status if(!path.IsDirectory()) @@ -245,6 +250,7 @@ CStatusCacheEntry CCachedDirectory::GetStatusForMember(const CTGitPath& path, bo // So mark it for crawling, and let the crawler remove it // later CGitStatusCache::Instance().AddFolderForCrawling(path.GetContainingDirectory()); + return CStatusCacheEntry(); } else @@ -252,9 +258,7 @@ CStatusCacheEntry CCachedDirectory::GetStatusForMember(const CTGitPath& path, bo // If we're in the special case of a directory being asked for its own status // and this directory is unversioned, then we should just return that here if(bRequestForSelf) - { return CStatusCacheEntry(); - } } } @@ -276,7 +280,6 @@ CStatusCacheEntry CCachedDirectory::GetStatusForMember(const CTGitPath& path, bo CGitStatusCache::Instance().AddFolderForCrawling(it->first); } } - return dirEntry->GetOwnStatus(bRecursive); } } @@ -341,14 +344,14 @@ CStatusCacheEntry CCachedDirectory::GetStatusForMember(const CTGitPath& path, bo // we already have (to save time and make the explorer // more responsive in stress conditions). // We leave the refreshing to the crawler. - if ((!bFetch)&&(m_entriesFileTime)) + if ((!bFetch)&&(m_indexFileTime)) { CGitStatusCache::Instance().AddFolderForCrawling(path.GetDirectory()); return CStatusCacheEntry(); } AutoLocker lock(m_critSec); - m_entriesFileTime = entriesFilePath.GetLastWriteTime(); - m_propsFileTime = propsDirPath.GetLastWriteTime(); + m_indexFileTime = indexFilePath.GetLastWriteTime(); +// m_propsFileTime = propsDirPath.GetLastWriteTime(); m_entryCache.clear(); strCacheKey = GetCacheKey(path); } @@ -361,7 +364,7 @@ CStatusCacheEntry CCachedDirectory::GetStatusForMember(const CTGitPath& path, bo if (g_GitAdminDir.IsAdminDirPath(path.GetWinPathString())) { - // We're being asked for the status of an .SVN directory + // We're being asked for the status of an .git directory // It's not worth asking for this return CStatusCacheEntry(); } @@ -395,9 +398,23 @@ CStatusCacheEntry CCachedDirectory::GetStatusForMember(const CTGitPath& path, bo m_currentStatusFetchingPath = m_directoryPath; m_currentStatusFetchingPathTicks = GetTickCount(); } - ATLTRACE(_T("svn_cli_stat for '%s' (req %s)\n"), m_directoryPath.GetWinPath(), path.GetWinPath()); + ATLTRACE(_T("git_enum_files for '%s' (req %s)\n"), m_directoryPath.GetWinPath(), path.GetWinPath()); - BOOL pErr = 0;//!wgEnumFiles(CStringA(sProjectRoot), lpszSubPath, WGEFF_NoRecurse|WGEFF_FullPath|WGEFF_DirStatusAll, &fillstatusmap, this); + CString sProjectRoot; + m_directoryPath.HasAdminDir(&sProjectRoot); + ATLASSERT( !m_directoryPath.IsEmpty() ); + + LPCSTR lpszSubPath = NULL; + CStringA sSubPath; + CString s = m_directoryPath.GetDirectory().GetWinPathString(); + if (s.GetLength() > sProjectRoot.GetLength()) + { + sSubPath = CStringA(s.Right(s.GetLength() - sProjectRoot.GetLength() - 1/*otherwise it gets initial slash*/)); + lpszSubPath = sSubPath; + } +//MessageBoxA(NULL, CStringA(sProjectRoot), sSubPath, MB_OK); +//OutputDebugStringA("###");OutputDebugStringW(sProjectRoot);OutputDebugStringA(" - ");OutputDebugStringA(sSubPath);OutputDebugStringA("\r\n"); + BOOL pErr = !wgEnumFiles(CStringA(sProjectRoot), lpszSubPath, WGEFF_NoRecurse|WGEFF_FullPath, &GetStatusCallback, this); /*git_error_t* pErr = svn_client_status4 ( NULL, @@ -418,7 +435,7 @@ CStatusCacheEntry CCachedDirectory::GetStatusForMember(const CTGitPath& path, bo AutoLocker pathlock(m_critSecPath); m_currentStatusFetchingPath.Reset(); } - ATLTRACE(_T("svn_cli_stat finished for '%s'\n"), m_directoryPath.GetWinPath(), path.GetWinPath()); + ATLTRACE(_T("git_enum_files finished for '%s'\n"), m_directoryPath.GetWinPath(), path.GetWinPath()); if(pErr) { // Handle an error @@ -428,7 +445,7 @@ CStatusCacheEntry CCachedDirectory::GetStatusForMember(const CTGitPath& path, bo // If we allow ourselves to fall on through, then folders will be asked // for their own status, and will set themselves as unversioned, for the // benefit of future requests -// ATLTRACE("svn_cli_stat err: '%s'\n", pErr->message); +// ATLTRACE("git_enum_files err: '%s'\n", pErr->message); // svn_error_clear(pErr); // No assert here! Since we _can_ get here, an assertion is not an option! // Reasons to get here: @@ -442,7 +459,7 @@ CStatusCacheEntry CCachedDirectory::GetStatusForMember(const CTGitPath& path, bo } else { - ATLTRACE("svn_cli_stat error, assume none status\n"); + ATLTRACE("git_enum_files error, assume none status\n"); // Since we only assume a none status here due to svn_client_status() // returning an error, make sure that this status times out soon. CGitStatusCache::Instance().m_folderCrawler.BlockPath(m_directoryPath, 2000); @@ -453,7 +470,7 @@ CStatusCacheEntry CCachedDirectory::GetStatusForMember(const CTGitPath& path, bo } else { - ATLTRACE("Skipped SVN status for unversioned folder\n"); + ATLTRACE("Skipped git status for unversioned folder\n"); } } // Now that we've refreshed our SVN status, we can see if it's @@ -501,7 +518,7 @@ CCachedDirectory::AddEntry(const CTGitPath& path, const git_wc_status2_t* pGitSt { if ((childDir->GetCurrentFullStatus() != git_wc_status_missing)||(pGitStatus==NULL)||(pGitStatus->text_status != git_wc_status_unversioned)) childDir->m_ownStatus.SetStatus(pGitStatus); -// childDir->m_ownStatus.SetKind(svn_node_dir); + childDir->m_ownStatus.SetKind(git_node_dir); } } else @@ -525,6 +542,8 @@ CCachedDirectory::AddEntry(const CTGitPath& path, const git_wc_status2_t* pGitSt entry_it = m_entryCache.insert(entry_it, std::make_pair(cachekey, CStatusCacheEntry())); } entry_it->second = CStatusCacheEntry(pGitStatus, path.GetLastWriteTime(), path.IsReadOnly(), validuntil); + // TEMP(?): git status doesn't not have "entry" that contains node type, so manually set as file + entry_it->second.SetKind(git_node_file); } } @@ -543,6 +562,147 @@ CCachedDirectory::GetFullPathString(const CString& cacheKey) return m_directoryPath.GetWinPathString() + _T("\\") + cacheKey; } +BOOL CCachedDirectory::GetStatusCallback(const struct wgFile_s *pFile, void *pUserData) +{ + CCachedDirectory* pThis = (CCachedDirectory*)pUserData; + + const char *path = pFile->sFileName; + + if (path == NULL) + return FALSE; + + git_wc_status2_t _status; + git_wc_status2_t *status = &_status; + + if ((pFile->nFlags & WGFF_Directory) && pFile->nStatus == WGFS_Unknown) + status->prop_status = status->text_status = git_wc_status_incomplete; + else + status->prop_status = status->text_status = GitStatusFromWingit(pFile->nStatus); +//if (pFile->nStatus > WGFS_Normal) {CStringA s; s.Format("==>%s %d\r\n",pFile->sFileName,pFile->nStatus); OutputDebugStringA(s);} + CTGitPath svnPath; + +// if(status->entry) + { + //if ((status->text_status != git_wc_status_none)&&(status->text_status != git_wc_status_missing)) + svnPath.SetFromGit(path, pFile->nFlags & WGFF_Directory); + /*else + svnPath.SetFromGit(path);*/ + + if (pFile->nFlags & WGFF_Directory) + { + if ( !svnPath.IsEquivalentToWithoutCase(pThis->m_directoryPath) ) + { + if (pThis->m_bRecursive) + { + // Add any versioned directory, which is not our 'self' entry, to the list for having its status updated +//OutputDebugStringA("AddFolderCrawl: ");OutputDebugStringW(svnPath.GetWinPathString());OutputDebugStringA("\r\n"); + CGitStatusCache::Instance().AddFolderForCrawling(svnPath); + } + + // Make sure we know about this child directory + // This initial status value is likely to be overwritten from below at some point + git_wc_status_kind s = GitStatus::GetMoreImportant(status->text_status, status->prop_status); + CCachedDirectory * cdir = CGitStatusCache::Instance().GetDirectoryCacheEntryNoCreate(svnPath); + if (cdir) + { + // This child directory is already in our cache! + // So ask this dir about its recursive status + git_wc_status_kind st = GitStatus::GetMoreImportant(s, cdir->GetCurrentFullStatus()); + AutoLocker lock(pThis->m_critSec); + pThis->m_childDirectories[svnPath] = st; + } + else + { + // the child directory is not in the cache. Create a new entry for it in the cache which is + // initially 'unversioned'. But we added that directory to the crawling list above, which + // means the cache will be updated soon. + CGitStatusCache::Instance().GetDirectoryCacheEntry(svnPath); + AutoLocker lock(pThis->m_critSec); + pThis->m_childDirectories[svnPath] = s; + } + } + } + else + { + // Keep track of the most important status of all the files in this directory + // Don't include subdirectories in this figure, because they need to provide their + // own 'most important' value + pThis->m_mostImportantFileStatus = GitStatus::GetMoreImportant(pThis->m_mostImportantFileStatus, status->text_status); + pThis->m_mostImportantFileStatus = GitStatus::GetMoreImportant(pThis->m_mostImportantFileStatus, status->prop_status); + if (((status->text_status == git_wc_status_unversioned)||(status->text_status == git_wc_status_none)) + &&(CGitStatusCache::Instance().IsUnversionedAsModified())) + { + // treat unversioned files as modified + if (pThis->m_mostImportantFileStatus != git_wc_status_added) + pThis->m_mostImportantFileStatus = GitStatus::GetMoreImportant(pThis->m_mostImportantFileStatus, git_wc_status_modified); + } + } + } +#if 0 + else + { + svnPath.SetFromGit(path); + // Subversion returns no 'entry' field for versioned folders if they're + // part of another working copy (nested layouts). + // So we have to make sure that such an 'unversioned' folder really + // is unversioned. + if (((status->text_status == git_wc_status_unversioned)||(status->text_status == git_wc_status_missing))&&(!svnPath.IsEquivalentToWithoutCase(pThis->m_directoryPath))&&(svnPath.IsDirectory())) + { + if (svnPath.HasAdminDir()) + { + CGitStatusCache::Instance().AddFolderForCrawling(svnPath); + // Mark the directory as 'versioned' (status 'normal' for now). + // This initial value will be overwritten from below some time later + { + AutoLocker lock(pThis->m_critSec); + pThis->m_childDirectories[svnPath] = git_wc_status_normal; + } + // Make sure the entry is also in the cache + CGitStatusCache::Instance().GetDirectoryCacheEntry(svnPath); + // also mark the status in the status object as normal + status->text_status = git_wc_status_normal; + } + } + else if (status->text_status == git_wc_status_external) + { + CGitStatusCache::Instance().AddFolderForCrawling(svnPath); + // Mark the directory as 'versioned' (status 'normal' for now). + // This initial value will be overwritten from below some time later + { + AutoLocker lock(pThis->m_critSec); + pThis->m_childDirectories[svnPath] = git_wc_status_normal; + } + // we have added a directory to the child-directory list of this + // directory. We now must make sure that this directory also has + // an entry in the cache. + CGitStatusCache::Instance().GetDirectoryCacheEntry(svnPath); + // also mark the status in the status object as normal + status->text_status = git_wc_status_normal; + } + else + { + if (svnPath.IsDirectory()) + { + AutoLocker lock(pThis->m_critSec); + pThis->m_childDirectories[svnPath] = GitStatus::GetMoreImportant(status->text_status, status->prop_status); + } + else if ((CGitStatusCache::Instance().IsUnversionedAsModified())&&(status->text_status != git_wc_status_missing)) + { + // make this unversioned item change the most important status of this + // folder to modified if it doesn't already have another status + if (pThis->m_mostImportantFileStatus != git_wc_status_added) + pThis->m_mostImportantFileStatus = GitStatus::GetMoreImportant(pThis->m_mostImportantFileStatus, git_wc_status_modified); + } + } + } +#endif + + pThis->AddEntry(svnPath, status); + + return FALSE; +} + +#if 0 git_error_t * CCachedDirectory::GetStatusCallback(void *baton, const char *path, git_wc_status2_t *status) { CCachedDirectory* pThis = (CCachedDirectory*)baton; @@ -552,7 +712,6 @@ git_error_t * CCachedDirectory::GetStatusCallback(void *baton, const char *path, CTGitPath svnPath; -#if 0 if(status->entry) { if ((status->text_status != git_wc_status_none)&&(status->text_status != git_wc_status_missing)) @@ -665,11 +824,12 @@ git_error_t * CCachedDirectory::GetStatusCallback(void *baton, const char *path, } } } -#endif + pThis->AddEntry(svnPath, status); return 0; } +#endif bool CCachedDirectory::IsOwnStatusValid() const diff --git a/src/TGitCache/CachedDirectory.h b/src/TGitCache/CachedDirectory.h index 987c0d0..4d32ec0 100644 --- a/src/TGitCache/CachedDirectory.h +++ b/src/TGitCache/CachedDirectory.h @@ -48,7 +48,8 @@ public: /// Get the current full status of this folder git_wc_status_kind GetCurrentFullStatus() {return m_currentFullStatus;} private: - static git_error_t* GetStatusCallback(void *baton, const char *path, git_wc_status2_t *status); +// static git_error_t* GetStatusCallback(void *baton, const char *path, git_wc_status2_t *status); + static BOOL GetStatusCallback(const struct wgFile_s *pFile, void *pUserData); void AddEntry(const CTGitPath& path, const git_wc_status2_t* pGitStatus, DWORD validuntil = 0); CString GetCacheKey(const CTGitPath& path); CString GetFullPathString(const CString& cacheKey); @@ -76,10 +77,10 @@ private: typedef std::map ChildDirStatus; ChildDirStatus m_childDirectories; - // The timestamp of the .SVN\entries file. For an unversioned directory, this will be zero - __int64 m_entriesFileTime; + // The timestamp of the .git\index file. For an unversioned directory, this will be zero + __int64 m_indexFileTime; // The timestamp of the .SVN\props dir. For an unversioned directory, this will be zero - __int64 m_propsFileTime; +// __int64 m_propsFileTime; // The path of the directory with this object looks after CTGitPath m_directoryPath; diff --git a/src/TGitCache/FolderCrawler.cpp b/src/TGitCache/FolderCrawler.cpp index bab47be..ca92ee8 100644 --- a/src/TGitCache/FolderCrawler.cpp +++ b/src/TGitCache/FolderCrawler.cpp @@ -240,23 +240,25 @@ void CFolderCrawler::WorkerThread() // don't crawl paths that are excluded if (!CGitStatusCache::Instance().IsPathAllowed(workingPath)) continue; - // check if the changed path is inside an .svn folder - if ((workingPath.HasAdminDir()&&workingPath.IsDirectory())||workingPath.IsAdminDir()) + // check if the changed path is inside an .git folder + if ((workingPath.HasAdminDir()&&workingPath.IsDirectory()) || workingPath.IsAdminDir()) { - // we don't crawl for paths changed in a tmp folder inside an .svn folder. + // we don't crawl for paths changed in a tmp folder inside an .git folder. // Because we also get notifications for those even if we just ask for the status! // And changes there don't affect the file status at all, so it's safe // to ignore notifications on those paths. if (workingPath.IsAdminDir()) { - CString lowerpath = workingPath.GetWinPathString(); + // TODO: add git specific filters here. is there really any change besides index file in .git + // that is relevant for overlays? + /*CString lowerpath = workingPath.GetWinPathString(); lowerpath.MakeLower(); if (lowerpath.Find(_T("\\tmp\\"))>0) continue; if (lowerpath.Find(_T("\\tmp")) == (lowerpath.GetLength()-4)) continue; if (lowerpath.Find(_T("\\log"))>0) - continue; + continue;*/ // Here's a little problem: // the lock file is also created for fetching the status // and not just when committing. diff --git a/src/TGitCache/StatusCacheEntry.cpp b/src/TGitCache/StatusCacheEntry.cpp index 7556094..5bedb4e 100644 --- a/src/TGitCache/StatusCacheEntry.cpp +++ b/src/TGitCache/StatusCacheEntry.cpp @@ -61,7 +61,7 @@ bool CStatusCacheEntry::SaveToDisk(FILE * pFile) WRITEVALUETOFILE(m_lastWriteTime); WRITEVALUETOFILE(m_bSet); WRITEVALUETOFILE(m_bSVNEntryFieldSet); - WRITEVALUETOFILE(m_commitRevision); + CStringA srev(m_commitRevision); WRITESTRINGTOFILE(srev); WRITESTRINGTOFILE(m_sUrl); WRITESTRINGTOFILE(m_sOwner); WRITESTRINGTOFILE(m_sAuthor); @@ -92,7 +92,19 @@ bool CStatusCacheEntry::LoadFromDisk(FILE * pFile) LOADVALUEFROMFILE(m_lastWriteTime); LOADVALUEFROMFILE(m_bSet); LOADVALUEFROMFILE(m_bSVNEntryFieldSet); - LOADVALUEFROMFILE(m_commitRevision); + LOADVALUEFROMFILE(value); + if (value != 0) + { + CStringA s; + if (fread(s.GetBuffer(value+1), sizeof(char), value, pFile)!=value) + { + s.ReleaseBuffer(0); + m_commitRevision.Empty(); + return false; + } + s.ReleaseBuffer(value); + m_commitRevision = s; + } LOADVALUEFROMFILE(value); if (value != 0) { @@ -167,8 +179,7 @@ void CStatusCacheEntry::SetStatus(const git_wc_status2_t* pGitStatus) m_GitStatus = *pGitStatus; // Currently we don't deep-copy the whole entry value, but we do take a few members -#if 0 - if(pGitStatus->entry != NULL) +/* if(pGitStatus->entry != NULL) { m_sUrl = pGitStatus->entry->url; m_commitRevision = pGitStatus->entry->cmt_rev; @@ -179,14 +190,13 @@ void CStatusCacheEntry::SetStatus(const git_wc_status2_t* pGitStatus) if (pGitStatus->entry->present_props) m_sPresentProps = pGitStatus->entry->present_props; } - else + else*/ { m_sUrl.Empty(); - m_commitRevision = 0; + m_commitRevision = GIT_INVALID_REVNUM; m_bSVNEntryFieldSet = false; } - m_GitStatus.entry = NULL; -#endif +// m_GitStatus.entry = NULL; } m_discardAtTime = GetTickCount()+cachetimeout; m_bSet = true; @@ -219,7 +229,7 @@ void CStatusCacheEntry::BuildCacheResponse(TSVNCacheResponse& response, DWORD& r if(m_bSVNEntryFieldSet) { response.m_status = m_GitStatus; -// response.m_entry.cmt_rev = m_commitRevision; + wcscpy_s(response.m_entry.cmt_rev, 41, m_commitRevision.GetString()); // There is no point trying to set these pointers here, because this is not // the process which will be using the data. diff --git a/src/TortoiseShell/ColumnProvider.cpp b/src/TortoiseShell/ColumnProvider.cpp index e0b7463..6140362 100644 --- a/src/TortoiseShell/ColumnProvider.cpp +++ b/src/TortoiseShell/ColumnProvider.cpp @@ -24,7 +24,7 @@ #include "UnicodeUtils.h" #include "GitStatus.h" #include "PathUtils.h" -//#include "..\TSVNCache\CacheInterface.h" +#include "..\TGitCache\CacheInterface.h" const static int ColumnFlags = SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT; @@ -342,15 +342,15 @@ void CShellExt::GetColumnStatus(const TCHAR * path, BOOL bIsDir) case ShellCache::exe: { SecureZeroMemory(&itemStatus, sizeof(itemStatus)); - if(m_remoteCacheLink.GetStatusFromRemoteCache(CTSVNPath(path), &itemStatus, true)) + if(m_remoteCacheLink.GetStatusFromRemoteCache(CTGitPath(path), &itemStatus, true)) { - filestatus = SVNStatus::GetMoreImportant(itemStatus.m_status.text_status, itemStatus.m_status.prop_status); + filestatus = GitStatus::GetMoreImportant(itemStatus.m_status.text_status, itemStatus.m_status.prop_status); } else { filestatus = git_wc_status_none; columnauthor.clear(); - columnrev = 0; + columnrev = GIT_INVALID_REVNUM; itemurl.clear(); itemshorturl.clear(); owner.clear(); @@ -361,7 +361,7 @@ void CShellExt::GetColumnStatus(const TCHAR * path, BOOL bIsDir) case ShellCache::dll: case ShellCache::dllFull: { - status = m_CachedStatus.GetFullStatus(CTSVNPath(path), bIsDir, TRUE); + status = m_CachedStatus.GetFullStatus(CTGitPath(path), bIsDir, TRUE); filestatus = status->status; } break; @@ -373,7 +373,7 @@ void CShellExt::GetColumnStatus(const TCHAR * path, BOOL bIsDir) else filestatus = git_wc_status_none; columnauthor.clear(); - columnrev = 0; + columnrev = GIT_INVALID_REVNUM; itemurl.clear(); itemshorturl.clear(); owner.clear(); @@ -423,7 +423,7 @@ void CShellExt::GetColumnStatus(const TCHAR * path, BOOL bIsDir) // Note: this will strip too much if such a folder is *below* the repository // root - but it's called 'short url' and we're free to shorten it the way we // like :) - ptr = _tcsstr(urlComponents.lpszUrlPath, _T("/trunk")); + /*ptr = _tcsstr(urlComponents.lpszUrlPath, _T("/trunk")); if (ptr == NULL) ptr = _tcsstr(urlComponents.lpszUrlPath, _T("\\trunk")); if ((ptr == NULL)||((*(ptr+6) != 0)&&(*(ptr+6) != '/')&&(*(ptr+6) != '\\'))) @@ -442,7 +442,7 @@ void CShellExt::GetColumnStatus(const TCHAR * path, BOOL bIsDir) } if (ptr) itemshorturl = ptr; - else + else*/ itemshorturl = urlComponents.lpszUrlPath; } else diff --git a/src/TortoiseShell/IconOverlay.cpp b/src/TortoiseShell/IconOverlay.cpp index 791ca32..bca63c6 100644 --- a/src/TortoiseShell/IconOverlay.cpp +++ b/src/TortoiseShell/IconOverlay.cpp @@ -137,18 +137,16 @@ STDMETHODIMP CShellExt::IsMemberOf(LPCWSTR pwszPath, DWORD /*dwAttrib*/) { case ShellCache::exe: { -#if 0 TSVNCacheResponse itemStatus; SecureZeroMemory(&itemStatus, sizeof(itemStatus)); if (m_remoteCacheLink.GetStatusFromRemoteCache(CTGitPath(pPath), &itemStatus, true)) { status = GitStatus::GetMoreImportant(itemStatus.m_status.text_status, itemStatus.m_status.prop_status); - if ((itemStatus.m_kind == git_node_file)&&(status == git_wc_status_normal)&&((itemStatus.m_needslock && itemStatus.m_owner[0]==0)||(itemStatus.m_readonly))) +/* if ((itemStatus.m_kind == git_node_file)&&(status == git_wc_status_normal)&&((itemStatus.m_needslock && itemStatus.m_owner[0]==0)||(itemStatus.m_readonly))) readonlyoverlay = true; if (itemStatus.m_owner[0]!=0) - lockedoverlay = true; + lockedoverlay = true;*/ } -#endif } break; case ShellCache::dll: @@ -207,6 +205,10 @@ STDMETHODIMP CShellExt::IsMemberOf(LPCWSTR pwszPath, DWORD /*dwAttrib*/) lockedoverlay = true; } + // index based version does not enumerate unversioned files, so default to unversioned + if (g_ShellCache.GetCacheType() == ShellCache::dll + && status == git_wc_status_none && g_ShellCache.HasSVNAdminDir(pPath, true)) + status = git_wc_status_unversioned; break; default: case ShellCache::none: @@ -244,11 +246,6 @@ STDMETHODIMP CShellExt::IsMemberOf(LPCWSTR pwszPath, DWORD /*dwAttrib*/) //if other handlers would return S_OK too (they're never called on my machine!) //So we return S_OK for ONLY ONE handler! - // TODO: not sure this should be here. if anywhere it should be in case 'dll' above - // because if overlay type 'none' is selected we don't want this to change status to unversioned (which may have overlay) - if(g_ShellCache.HasSVNAdminDir(pPath, true) && status == git_wc_status_none) - status = git_wc_status_unversioned; - switch (status) { // note: we can show other overlays if due to lack of enough free overlay diff --git a/src/TortoiseShell/RemoteCacheLink.cpp b/src/TortoiseShell/RemoteCacheLink.cpp index a56d2e2..2e21500 100644 --- a/src/TortoiseShell/RemoteCacheLink.cpp +++ b/src/TortoiseShell/RemoteCacheLink.cpp @@ -21,8 +21,6 @@ #include "ShellExt.h" #include "..\TGitCache\CacheInterface.h" #include "TGitPath.h" -#define GetCachePipeName() _T("HH") -#define GetCacheCommandPipeName() _T("CC") CRemoteCacheLink::CRemoteCacheLink(void) : m_hPipe(INVALID_HANDLE_VALUE) @@ -307,17 +305,17 @@ bool CRemoteCacheLink::GetStatusFromRemoteCache(const CTGitPath& Path, TSVNCache if (fSuccess) { -/* if(nBytesRead == sizeof(TSVNCacheResponse)) + if(nBytesRead == sizeof(TSVNCacheResponse)) { // This is a full response - we need to fix-up some pointers - pReturnedStatus->m_status.entry = &pReturnedStatus->m_entry; - pReturnedStatus->m_entry.url = pReturnedStatus->m_url; +// pReturnedStatus->m_status.entry = &pReturnedStatus->m_entry; +// pReturnedStatus->m_entry.url = pReturnedStatus->m_url; } else { - pReturnedStatus->m_status.entry = NULL; +// pReturnedStatus->m_status.entry = NULL; } -*/ + return true; } ClosePipe(); diff --git a/src/TortoiseShell/ShellCache.h b/src/TortoiseShell/ShellCache.h index b97284a..bfeb944 100644 --- a/src/TortoiseShell/ShellCache.h +++ b/src/TortoiseShell/ShellCache.h @@ -153,11 +153,7 @@ public: cachetypeticker = GetTickCount(); cachetype.read(); } - //return CacheType(DWORD((cachetype))); - /*TEMP: until TGitCache done*/ -// if(CGit::IsVista()) -// return none; - return CacheType(DWORD((cachetype))) == exe ? dll : CacheType(DWORD((cachetype))); + return CacheType(DWORD((cachetype))); } DWORD BlockStatus() { diff --git a/src/TortoiseShell/ShellExt.cpp b/src/TortoiseShell/ShellExt.cpp index 7b89c23..60537b3 100644 --- a/src/TortoiseShell/ShellExt.cpp +++ b/src/TortoiseShell/ShellExt.cpp @@ -282,7 +282,7 @@ UINT __stdcall CShellExt::CopyCallback(HWND /*hWnd*/, UINT wFunc, UINT /*wFlags* if (wFunc == FO_COPY) return IDYES; // copying is not a problem for us -// m_remoteCacheLink.ReleaseLockForPath(CTSVNPath(pszSrcFile)); + m_remoteCacheLink.ReleaseLockForPath(CTGitPath(pszSrcFile)); // we could now wait a little bit to give the cache time to release the handles. // but the explorer/shell already retries any action for about two seconds // if it first fails. So if the cache hasn't released the handle yet, the explorer diff --git a/src/TortoiseShell/ShellExt.h b/src/TortoiseShell/ShellExt.h index fe69901..e87abfb 100644 --- a/src/TortoiseShell/ShellExt.h +++ b/src/TortoiseShell/ShellExt.h @@ -204,7 +204,7 @@ protected: stdstring itemshorturl; stdstring ignoredprops; stdstring owner; -// git_revnum_t columnrev; ///< holds the corresponding revision to the file/dir above + git_revnum_t columnrev; ///< holds the corresponding revision to the file/dir above git_wc_status_kind filestatus; std::map bitmaps; diff --git a/src/TortoiseShell/TortoiseShell.vcproj b/src/TortoiseShell/TortoiseShell.vcproj index 1805c66..e345be0 100644 --- a/src/TortoiseShell/TortoiseShell.vcproj +++ b/src/TortoiseShell/TortoiseShell.vcproj @@ -453,6 +453,10 @@ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm" > + + -- 2.11.0