void CGitStatusCache::RemoveCacheForPath(const CTGitPath& path) { // Stop the crawler starting on a new folder CCrawlInhibitor crawlInhibit(&m_folderCrawler); CCachedDirectory::ItDir itMap; CCachedDirectory * dirtoremove = NULL; itMap = m_directoryCache.find(path); if ((itMap != m_directoryCache.end())&&(itMap->second)) dirtoremove = itMap->second; if (dirtoremove == NULL) return; ATLASSERT(path.IsEquivalentToWithoutCase(dirtoremove->m_directoryPath)); RemoveCacheForDirectory(dirtoremove); }
CStatusCacheEntry CCachedDirectory::GetStatusForMember(const CTGitPath& path, bool bRecursive, bool bFetch /* = true */) { CString sProjectRoot; bool bIsVersionedPath; bool bRequestForSelf = false; if(path.IsEquivalentToWithoutCase(m_directoryPath)) { bRequestForSelf = true; AutoLocker lock(m_critSec); // HasAdminDir might modify m_directoryPath, so we need to do it synchronized bIsVersionedPath = m_directoryPath.HasAdminDir(&sProjectRoot); } else bIsVersionedPath = path.HasAdminDir(&sProjectRoot); // In all most circumstances, we ask for the status of a member of this directory. ATLASSERT(m_directoryPath.IsEquivalentToWithoutCase(path.GetContainingDirectory()) || bRequestForSelf); //If is not version control path if( !bIsVersionedPath) { CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": %s is not underversion control\n"), path.GetWinPath()); return CStatusCacheEntry(); } // We've not got this item in the cache - let's add it // We never bother asking SVN for the status of just one file, always for its containing directory if (GitAdminDir::IsAdminDirPath(path.GetWinPathString())) { // We're being asked for the status of an .git directory // It's not worth asking for this return CStatusCacheEntry(); } if(bFetch) { return GetStatusFromGit(path, sProjectRoot); } else { return GetStatusFromCache(path, bRecursive); } }
CStatusCacheEntry CCachedDirectory::GetStatusForMember(const CTGitPath& path, bool bRecursive, bool bFetch /* = true */) { CString strCacheKey; bool bRequestForSelf = false; if(path.IsEquivalentToWithoutCase(m_directoryPath)) { 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); CString sProjectRoot; const BOOL bIsVersionedPath = path.HasAdminDir(&sProjectRoot); //If is not version control path if( !bIsVersionedPath) { ATLTRACE(_T("%s is not underversion control\n"), path.GetWinPath()); return CStatusCacheEntry(); } // We've not got this item in the cache - let's add it // We never bother asking SVN for the status of just one file, always for its containing directory if (g_GitAdminDir.IsAdminDirPath(path.GetWinPathString())) { // We're being asked for the status of an .git directory // It's not worth asking for this return CStatusCacheEntry(); } if(bFetch) { return GetStatusFromGit(path, sProjectRoot); } else { return GetStatusFromCache(path, bRecursive); } }
/* Fetch is false, means fetch status from cache */ CStatusCacheEntry CGitStatusCache::GetStatusForPath(const CTGitPath& path, DWORD flags, bool bFetch /* = true */) { bool bRecursive = !!(flags & TGITCACHE_FLAGS_RECUSIVE_STATUS); // Check a very short-lived 'mini-cache' of the last thing we were asked for. long now = (long)GetTickCount(); if(now-m_mostRecentExpiresAt < 0) { if(path.IsEquivalentToWithoutCase(m_mostRecentPath)) { return m_mostRecentStatus; } } m_mostRecentPath = path; m_mostRecentExpiresAt = now+1000; if (IsPathGood(path)) { // Stop the crawler starting on a new folder while we're doing this much more important task... // Please note, that this may be a second "lock" used concurrently to the one in RemoveCacheForPath(). CCrawlInhibitor crawlInhibit(&m_folderCrawler); CTGitPath dirpath = path.GetContainingDirectory(); if ((dirpath.IsEmpty()) || (!m_shellCache.IsPathAllowed(dirpath.GetWinPath()))) dirpath = path.GetDirectory(); CCachedDirectory * cachedDir = GetDirectoryCacheEntry(dirpath); if (cachedDir != NULL) { //ATLTRACE(_T("GetStatusForMember %d\n"), bFetch); m_mostRecentStatus = cachedDir->GetStatusForMember(path, bRecursive, bFetch); return m_mostRecentStatus; } } ATLTRACE(_T("ignored no good path %s\n"), path.GetWinPath()); m_mostRecentStatus = CStatusCacheEntry(); if (m_shellCache.ShowExcludedAsNormal() && path.IsDirectory() && m_shellCache.HasGITAdminDir(path.GetWinPath(), true)) { ATLTRACE(_T("force status %s\n"), path.GetWinPath()); m_mostRecentStatus.ForceStatus(git_wc_status_normal); } return m_mostRecentStatus; }
/* Fetch is false, means fetch status from cache */ CStatusCacheEntry CGitStatusCache::GetStatusForPath(const CTGitPath& path, DWORD flags, bool bFetch /* = true */) { bool bRecursive = !!(flags & TGITCACHE_FLAGS_RECUSIVE_STATUS); // Check a very short-lived 'mini-cache' of the last thing we were asked for. long now = (long)GetTickCount(); if(now-m_mostRecentExpiresAt < 0) { if(path.IsEquivalentToWithoutCase(m_mostRecentPath)) { return m_mostRecentStatus; } } { AutoLocker lock(m_critSec); m_mostRecentPath = path; m_mostRecentExpiresAt = now + 1000; } if (IsPathGood(path)) { // Stop the crawler starting on a new folder while we're doing this much more important task... // Please note, that this may be a second "lock" used concurrently to the one in RemoveCacheForPath(). CCrawlInhibitor crawlInhibit(&m_folderCrawler); CTGitPath dirpath = path.GetContainingDirectory(); if ((dirpath.IsEmpty()) || (!m_shellCache.IsPathAllowed(dirpath.GetWinPath()))) dirpath = path.GetDirectory(); CCachedDirectory * cachedDir = GetDirectoryCacheEntry(dirpath); if (cachedDir != NULL) { //ATLTRACE(_T("GetStatusForMember %d\n"), bFetch); CStatusCacheEntry entry = cachedDir->GetStatusForMember(path, bRecursive, bFetch); { AutoLocker lock(m_critSec); m_mostRecentStatus = entry; return m_mostRecentStatus; } } } else { // path is blocked for some reason: return the cached status if we have one // we do here only a cache search, absolutely no disk access is allowed! CCachedDirectory::ItDir itMap = m_directoryCache.find(path.GetDirectory()); if ((itMap != m_directoryCache.end())&&(itMap->second)) { if (path.IsDirectory()) { CStatusCacheEntry entry = itMap->second->GetOwnStatus(false); AutoLocker lock(m_critSec); m_mostRecentStatus = entry; return m_mostRecentStatus; } else { // We've found this directory in the cache CCachedDirectory * cachedDir = itMap->second; CStatusCacheEntry entry = cachedDir->GetCacheStatusForMember(path); { AutoLocker lock(m_critSec); m_mostRecentStatus = entry; return m_mostRecentStatus; } } } } AutoLocker lock(m_critSec); ATLTRACE(_T("ignored no good path %s\n"), path.GetWinPath()); m_mostRecentStatus = CStatusCacheEntry(); if (m_shellCache.ShowExcludedAsNormal() && path.IsDirectory() && m_shellCache.HasGITAdminDir(path.GetWinPath(), true)) { ATLTRACE(_T("force status %s\n"), path.GetWinPath()); m_mostRecentStatus.ForceStatus(git_wc_status_normal); } return m_mostRecentStatus; }
void CGitStatusCache::UpdateShell(const CTGitPath& path) { if (path.IsEquivalentToWithoutCase(m_mostRecentPath)) m_mostRecentExpiresAt = 0; m_shellUpdater.AddPathForUpdate(path); }
git_error_t * CCachedDirectory::GetStatusCallback(void *baton, const char *path, git_wc_status2_t *status) { CCachedDirectory* pThis = (CCachedDirectory*)baton; if (path == NULL) return 0; CTGitPath svnPath; if(status->entry) { if ((status->text_status != git_wc_status_none)&&(status->text_status != git_wc_status_missing)) svnPath.SetFromSVN(path, (status->entry->kind == svn_node_dir)); else svnPath.SetFromSVN(path); if(svnPath.IsDirectory()) { 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 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); } } } else { svnPath.SetFromSVN(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); } } } pThis->AddEntry(svnPath, status); return 0; }