int CCachedDirectory::EnumFiles(const CTGitPath &path , bool IsFull) { CString sProjectRoot; path.HasAdminDir(&sProjectRoot); CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": EnumFiles %s\n"), path.GetWinPath()); ATLASSERT( !m_directoryPath.IsEmpty() ); CString sSubPath; CString s = path.GetWinPath(); if (s.GetLength() > sProjectRoot.GetLength()) { // skip initial slash if necessary if(s[sProjectRoot.GetLength()] == _T('\\')) sSubPath = s.Right(s.GetLength() - sProjectRoot.GetLength() -1); else sSubPath = s.Right(s.GetLength() - sProjectRoot.GetLength() ); } // strip "\" at the end, otherwise cache lookups for drives do not work correctly sProjectRoot.TrimRight(_T("\\")); GitStatus *pStatus = &CGitStatusCache::Instance().m_GitStatus; UNREFERENCED_PARAMETER(pStatus); git_wc_status_kind status = git_wc_status_none; if (!path.IsDirectory()) { bool assumeValid = false; bool skipWorktree = false; pStatus->GetFileStatus(sProjectRoot, sSubPath, &status, IsFull, false, true, GetStatusCallback, this, &assumeValid, &skipWorktree); if (status < m_mostImportantFileStatus) RefreshMostImportant(); } else { bool isSelf = path == m_directoryPath; if (isSelf) { AutoLocker lock(m_critSec); // clear subdirectory status cache m_childDirectories.clear(); // build new files status cache m_entryCache_tmp.clear(); } m_mostImportantFileStatus = git_wc_status_none; pStatus->EnumDirStatus(sProjectRoot, sSubPath, &status, IsFull, false, true, GetStatusCallback,this); m_mostImportantFileStatus = GitStatus::GetMoreImportant(m_mostImportantFileStatus, status); if (isSelf) { AutoLocker lock(m_critSec); // use a tmp files status cache so that we can still use the old cached values // for deciding whether we have to issue a shell notify m_entryCache = m_entryCache_tmp; m_entryCache_tmp.clear(); } // need to set/construct m_ownStatus (only unversioned and normal are valid values) m_ownStatus = git_wc_status_unversioned; m_ownStatus.SetKind(git_node_dir); if (m_mostImportantFileStatus > git_wc_status_unversioned) { git_wc_status2_t status2; status2.text_status = status2.prop_status = git_wc_status_normal; m_ownStatus.SetStatus(&status2); } else { if (::PathFileExists(m_directoryPath.GetWinPathString() + _T("\\.git"))) { git_wc_status2_t status2; status2.text_status = status2.prop_status = git_wc_status_normal; m_ownStatus.SetStatus(&status2); } else { git_wc_status2_t status2; status2.text_status = status2.prop_status = CalculateRecursiveStatus(); m_ownStatus.SetStatus(&status2); } } } return 0; }
bool CCachedDirectory::SvnUpdateMembersStatus() { if (InterlockedExchange(&m_FetchingStatus, TRUE)) return false; svn_opt_revision_t revision; revision.kind = svn_opt_revision_unspecified; SVNPool subPool(CSVNStatusCache::Instance().m_svnHelp.Pool()); CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": stat for %s\n"), m_directoryPath.GetWinPath()); const char * svnapipath = m_directoryPath.GetSVNApiPath(subPool); if ((svnapipath == 0)||(svnapipath[0] == 0)) { InterlockedExchange(&m_FetchingStatus, FALSE); m_currentFullStatus = m_mostImportantFileStatus = svn_wc_status_none; CSVNStatusCache::Instance().BlockPath(m_directoryPath, true, 5); return false; } m_pCtx = CSVNStatusCache::Instance().m_svnHelp.ClientContext(subPool); svn_error_t * pErr = nullptr; if (m_pCtx) { pErr = svn_client_status5 ( NULL, m_pCtx, svnapipath, &revision, svn_depth_immediates, TRUE, // get all FALSE, // update TRUE, // no ignores FALSE, // ignore externals TRUE, // depth as sticky NULL, // changelists GetStatusCallback, this, subPool ); svn_wc_context_destroy(m_pCtx->wc_ctx); m_pCtx->wc_ctx = NULL; m_pCtx = NULL; } else { CTraceToOutputDebugString::Instance()(__FUNCTION__ ": error creating client context!\n"); m_currentFullStatus = m_mostImportantFileStatus = svn_wc_status_none; // Since we only assume a none status here due to the fact that we couldn't get a client context, // make sure that this status times out soon. CSVNStatusCache::Instance().m_folderCrawler.BlockPath(m_directoryPath, 20); CSVNStatusCache::Instance().AddFolderForCrawling(m_directoryPath); } InterlockedExchange(&m_FetchingStatus, FALSE); if (pErr) { // Handle an error // The most likely error on a folder is that it's not part of a WC // In most circumstances, this will have been caught earlier, // but in some situations, we'll get this error. // 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 CTraceToOutputDebugString::Instance()(__FUNCTION__ ": svn_cli_stat error '%s'\n", pErr->message); // No assert here! Since we _can_ get here, an assertion is not an option! // Reasons to get here: // - renaming a folder with many sub folders --> results in "not a working copy" if the revert // happens between our checks and the svn_client_status() call. // - reverting a move/copy --> results in "not a working copy" (as above) switch (pErr->apr_err) { case SVN_ERR_WC_NOT_WORKING_COPY: { m_currentFullStatus = m_mostImportantFileStatus = svn_wc_status_none; CSVNStatusCache::Instance().BlockPath(m_directoryPath, true); } break; case SVN_ERR_WC_PATH_NOT_FOUND: case SVN_ERR_WC_NOT_FILE: case SVN_ERR_WC_CORRUPT: case SVN_ERR_WC_CORRUPT_TEXT_BASE: case SVN_ERR_WC_UNSUPPORTED_FORMAT: case SVN_ERR_WC_DB_ERROR: case SVN_ERR_WC_MISSING: case SVN_ERR_WC_PATH_UNEXPECTED_STATUS: case SVN_ERR_WC_UPGRADE_REQUIRED: case SVN_ERR_WC_CLEANUP_REQUIRED: { m_currentFullStatus = m_mostImportantFileStatus = svn_wc_status_none; } break; default: { // Since we only assume a none status here due to svn_client_status() // returning an error, make sure that this status times out soon. CSVNStatusCache::Instance().m_folderCrawler.BlockPath(m_directoryPath, 20); CSVNStatusCache::Instance().AddFolderForCrawling(m_directoryPath); } break; } svn_error_clear(pErr); return false; } RefreshMostImportant(false); return true; }