Example #1
0
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);
	}
}
Example #2
0
CStatusCacheEntry CSVNStatusCache::GetStatusForPath(const CTSVNPath& path, DWORD flags,  bool bFetch /* = true */)
{
	bool bRecursive = !!(flags & TSVNCACHE_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_mostRecentAskedPath))
		{
			return m_mostRecentStatus;
		}
	}
	{
		AutoLocker lock(m_critSec);
		m_mostRecentAskedPath = path;
		m_mostRecentExpiresAt = now+1000;
	}

	if (IsPathGood(path) && m_shellCache.IsPathAllowed(path.GetWinPath()))
	{
		// 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);

		CTSVNPath dirpath = path.GetContainingDirectory();
		if (dirpath.IsEmpty())
			dirpath = path.GetDirectory();
		CCachedDirectory * cachedDir = GetDirectoryCacheEntry(dirpath);
		if (cachedDir != NULL)
		{
			CStatusCacheEntry entry = cachedDir->GetStatusForMember(path, bRecursive, bFetch);
			{
				AutoLocker lock(m_critSec);
				m_mostRecentStatus = entry;
				return m_mostRecentStatus;
			}
		}
		cachedDir = GetDirectoryCacheEntry(path.GetDirectory());
		if (cachedDir != NULL)
		{
			CStatusCacheEntry entry = cachedDir->GetStatusForMember(path, bRecursive, bFetch);
			{
				AutoLocker lock(m_critSec);
				m_mostRecentStatus = entry;
				return m_mostRecentStatus;
			}
		}

	}
	AutoLocker lock(m_critSec);
	m_mostRecentStatus = CStatusCacheEntry();
	if (m_shellCache.ShowExcludedAsNormal() && path.IsDirectory() && m_shellCache.HasSVNAdminDir(path.GetWinPath(), true))
	{
		m_mostRecentStatus.ForceStatus(svn_wc_status_normal);
	}
	return m_mostRecentStatus;
}
Example #3
0
CStatusCacheEntry CCachedDirectory::GetCacheStatusForMember(const CTGitPath& path)
{
	// no disk access!
	AutoLocker lock(m_critSec);
	CacheEntryMap::iterator itMap = m_entryCache.find(GetCacheKey(path));
	if(itMap != m_entryCache.end())
		return itMap->second;

	return CStatusCacheEntry();
}
Example #4
0
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);
	}
}
Example #5
0
CStatusCacheEntry CCachedDirectory::GetCacheStatusForMember( const CTSVNPath& path )
{
    AutoLocker lock(m_critSec);
    CStringA strCacheKey = GetCacheKey(path);
    CacheEntryMap::iterator itMap = m_entryCache.find(strCacheKey);
    if(itMap != m_entryCache.end())
    {
        return itMap->second;
    }
    return CStatusCacheEntry();
}
Example #6
0
void
CCachedDirectory::AddEntry(const CTSVNPath& path, const svn_client_status_t* pSVNStatus, bool needsLock, bool forceNormal)
{
    svn_wc_status_kind nodestatus = forceNormal ? svn_wc_status_normal : (pSVNStatus ? pSVNStatus->node_status : svn_wc_status_none);
    if(path.IsDirectory())
    {
        // no lock here:
        // AutoLocker lock(m_critSec);
        // because GetDirectoryCacheEntry() can try to obtain a write lock
        CCachedDirectory * childDir = CSVNStatusCache::Instance().GetDirectoryCacheEntry(path);
        if (childDir)
        {
            if ((childDir->GetCurrentFullStatus() != svn_wc_status_ignored)||(pSVNStatus==NULL)||(nodestatus != svn_wc_status_unversioned))
                childDir->m_ownStatus.SetStatus(pSVNStatus, needsLock, forceNormal);
            childDir->m_ownStatus.SetKind(svn_node_dir);
        }
    }
    else
    {
        AutoLocker lock(m_critSec);
        CStringA cachekey = GetCacheKey(path);
        CacheEntryMap::iterator entry_it = m_entryCache.lower_bound(cachekey);
        if (entry_it != m_entryCache.end() && entry_it->first == cachekey)
        {
            if (pSVNStatus)
            {
                if (entry_it->second.GetEffectiveStatus() > svn_wc_status_none &&
                    entry_it->second.GetEffectiveStatus() != nodestatus)
                {
                    CSVNStatusCache::Instance().UpdateShell(path);
                    CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": shell update for %s\n"), path.GetWinPath());
                }
            }
        }
        else
        {
            entry_it = m_entryCache.insert(entry_it, std::make_pair(cachekey, CStatusCacheEntry()));
        }
        entry_it->second = CStatusCacheEntry(pSVNStatus, needsLock, path.GetLastWriteTime(), forceNormal);
    }
}
Example #7
0
/* 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;
}
Example #8
0
void
CCachedDirectory::AddEntry(const CTGitPath& path, const git_wc_status2_t* pGitStatus, DWORD validuntil /* = 0*/)
{
	AutoLocker lock(m_critSec);
	if(path.IsDirectory())
	{
		CCachedDirectory * childDir = CGitStatusCache::Instance().GetDirectoryCacheEntry(path);
		if (childDir)
		{
			if ((childDir->GetCurrentFullStatus() != git_wc_status_missing)||(pGitStatus==NULL)||(pGitStatus->text_status != git_wc_status_unversioned))
			{
				if(pGitStatus)
				{
					if(childDir->GetCurrentFullStatus() != GitStatus::GetMoreImportant(pGitStatus->prop_status, pGitStatus->text_status))
					{
						CGitStatusCache::Instance().UpdateShell(path);
						//CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": shell update for %s\n"), path.GetWinPath());
						childDir->m_ownStatus.SetKind(git_node_dir);
						childDir->m_ownStatus.SetStatus(pGitStatus);
					}
				}
			}
			childDir->m_ownStatus.SetKind(git_node_dir);


		}
	}
	else
	{
		CCachedDirectory * childDir = CGitStatusCache::Instance().GetDirectoryCacheEntry(path.GetContainingDirectory());
		bool bNotified = false;

		if(!childDir)
			return ;

		AutoLocker lock2(childDir->m_critSec);
		CString cachekey = GetCacheKey(path);
		CacheEntryMap::iterator entry_it = childDir->m_entryCache.lower_bound(cachekey);
		if (entry_it != childDir->m_entryCache.end() && entry_it->first == cachekey)
		{
			if (pGitStatus)
			{
				if (entry_it->second.GetEffectiveStatus() > git_wc_status_none &&
					entry_it->second.GetEffectiveStatus() != GitStatus::GetMoreImportant(pGitStatus->prop_status, pGitStatus->text_status)
				)
				{
					bNotified =true;
				}
			}

		}
		else
		{
			entry_it = childDir->m_entryCache.insert(entry_it, std::make_pair(cachekey, CStatusCacheEntry()));
			bNotified = true;

		}
		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);

		childDir->m_entryCache_tmp[cachekey] = entry_it->second;

		if(bNotified)
		{
			CGitStatusCache::Instance().UpdateShell(path);
			//CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": shell update for %s\n"), path.GetWinPath());
		}

		//CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": Path Entry Add %s %s %s %d\n"), path.GetWinPath(), cachekey, m_directoryPath.GetWinPath(), pGitStatus->text_status);
	}
}
Example #9
0
CStatusCacheEntry CCachedDirectory::GetStatusFromGit(const CTGitPath &path, CString sProjectRoot)
{
	CString subpaths = path.GetGitPathString();
	if(subpaths.GetLength() >= sProjectRoot.GetLength())
	{
		if(subpaths[sProjectRoot.GetLength()] == _T('/'))
			subpaths=subpaths.Right(subpaths.GetLength() - sProjectRoot.GetLength()-1);
		else
			subpaths=subpaths.Right(subpaths.GetLength() - sProjectRoot.GetLength());
	}

	GitStatus *pGitStatus = &CGitStatusCache::Instance().m_GitStatus;
	UNREFERENCED_PARAMETER(pGitStatus);

	bool isVersion =true;
	pGitStatus->IsUnderVersionControl(sProjectRoot, subpaths, path.IsDirectory(), &isVersion);
	if(!isVersion)
	{	//untracked file
		bool isDir = path.IsDirectory();
		bool isIgnoreFileChanged = pGitStatus->HasIgnoreFilesChanged(sProjectRoot, subpaths, isDir);

		if( isIgnoreFileChanged)
		{
			pGitStatus->LoadIgnoreFile(sProjectRoot, subpaths, isDir);
		}

		if (isDir)
		{

			CCachedDirectory * dirEntry = CGitStatusCache::Instance().GetDirectoryCacheEntry(path,
											false); /* we needn't watch untracked directory*/

			if(dirEntry)
			{
				AutoLocker lock(dirEntry->m_critSec);

				git_wc_status_kind dirstatus = dirEntry->GetCurrentFullStatus() ;
				if (CGitStatusCache::Instance().IsUnversionedAsModified() || dirstatus == git_wc_status_none || dirstatus >= git_wc_status_normal || isIgnoreFileChanged)
				{/* status have not initialized*/
					bool isignore = false;
					pGitStatus->IsIgnore(sProjectRoot, subpaths, &isignore, isDir);

					if (!isignore && CGitStatusCache::Instance().IsUnversionedAsModified())
					{
						dirEntry->EnumFiles(path, TRUE);
						dirEntry->UpdateCurrentStatus();
						return CStatusCacheEntry(dirEntry->GetCurrentFullStatus());
					}

					git_wc_status2_t status2;
					status2.text_status = status2.prop_status =
						(isignore? git_wc_status_ignored:git_wc_status_unversioned);

					// we do not know anything about files here, all we know is that there are not versioned files in this dir
					dirEntry->m_mostImportantFileStatus = git_wc_status_none;
					dirEntry->m_ownStatus.SetKind(git_node_dir);
					dirEntry->m_ownStatus.SetStatus(&status2);
					dirEntry->m_currentFullStatus = status2.text_status;
				}
				return dirEntry->m_ownStatus;
			}

		}
		else /* path is file */
		{
			AutoLocker lock(m_critSec);
			CString strCacheKey = GetCacheKey(path);

			if (strCacheKey.IsEmpty())
				return CStatusCacheEntry();

			CacheEntryMap::iterator itMap = m_entryCache.find(strCacheKey);
			if(itMap == m_entryCache.end() || isIgnoreFileChanged)
			{
				git_wc_status2_t status2;
				bool isignore = false;
				pGitStatus->IsIgnore(sProjectRoot, subpaths, &isignore, isDir);
				status2.text_status = status2.prop_status =
					(isignore? git_wc_status_ignored:git_wc_status_unversioned);
				AddEntry(path, &status2);
				return m_entryCache[strCacheKey];
			}
			else
			{
				return itMap->second;
			}
		}
		return CStatusCacheEntry();

	}
	else
	{
		EnumFiles(path, TRUE);
		UpdateCurrentStatus();
		if (!path.IsDirectory())
			return GetCacheStatusForMember(path);
		return CStatusCacheEntry(m_ownStatus);
	}

}
Example #10
0
CStatusCacheEntry CCachedDirectory::GetStatusFromCache(const CTGitPath& path, bool bRecursive)
{
	if(path.IsDirectory())
	{
		// We don't have directory status in our cache
		// Ask the directory if it knows its own status
		CCachedDirectory * dirEntry = CGitStatusCache::Instance().GetDirectoryCacheEntry(path);
		if( dirEntry)
		{
			if (dirEntry->IsOwnStatusValid())
				return dirEntry->GetOwnStatus(bRecursive);
			else
			{
				/* cache have outof date, need crawl again*/

				/*AutoLocker lock(dirEntry->m_critSec);
				ChildDirStatus::const_iterator it;
				for(it = dirEntry->m_childDirectories.begin(); it != dirEntry->m_childDirectories.end(); ++it)
				{
					CGitStatusCache::Instance().AddFolderForCrawling(it->first);
				}*/

				CGitStatusCache::Instance().AddFolderForCrawling(path);

				/*Return old status during crawling*/
				return dirEntry->GetOwnStatus(bRecursive);
			}
		}
		else
		{
			CGitStatusCache::Instance().AddFolderForCrawling(path);
		}
		return CStatusCacheEntry();
	}
	else
	{
		//All file ignored if under ignore directory
		if (m_ownStatus.GetEffectiveStatus() == git_wc_status_ignored)
			return CStatusCacheEntry(git_wc_status_ignored);
		if (m_ownStatus.GetEffectiveStatus() == git_wc_status_unversioned)
			return CStatusCacheEntry(git_wc_status_unversioned);

		// Look up a file in our own cache
		AutoLocker lock(m_critSec);
		CString strCacheKey = GetCacheKey(path);
		CacheEntryMap::iterator itMap = m_entryCache.find(strCacheKey);
		if(itMap != m_entryCache.end())
		{
			// We've hit the cache - check for timeout
			if(!itMap->second.HasExpired((long)GetTickCount()))
			{
				if(itMap->second.DoesFileTimeMatch(path.GetLastWriteTime()))
				{
					if ((itMap->second.GetEffectiveStatus()!=git_wc_status_missing)||(!PathFileExists(path.GetWinPath())))
					{
						// Note: the filetime matches after a modified has been committed too.
						// So in that case, we would return a wrong status (e.g. 'modified' instead
						// of 'normal') here.
						return itMap->second;
					}
				}
			}
		}

		CGitStatusCache::Instance().AddFolderForCrawling(path.GetContainingDirectory());
		return CStatusCacheEntry();
	}

}
Example #11
0
CStatusCacheEntry CCachedDirectory::GetStatusForMember(const CTSVNPath& path, bool bRecursive,  bool bFetch /* = true */)
{
    CStringA strCacheKey;
    bool bThisDirectoryIsUnversioned = false;
    bool bRequestForSelf = false;
    if(path.IsEquivalentToWithoutCase(m_directoryPath))
    {
        bRequestForSelf = true;
    }

    // In all most circumstances, we ask for the status of a member of this directory.
    ATLASSERT(m_directoryPath.IsEquivalentToWithoutCase(path.GetContainingDirectory()) || bRequestForSelf);

    long long dbFileTime = CSVNStatusCache::Instance().WCRoots()->GetDBFileTime(m_directoryPath);
    bool wcDbFileTimeChanged = (m_wcDbFileTime != dbFileTime);

    if ( !wcDbFileTimeChanged )
    {
        if(m_wcDbFileTime == 0)
        {
            // We are a folder which is not in a working copy
            bThisDirectoryIsUnversioned = true;
            m_ownStatus.SetStatus(NULL, false, false);

            // If a user removes the .svn 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())
            {
                if ((PathFileExists(path.GetWinPath()))||(bRequestForSelf))
                    return CStatusCacheEntry();
                // the entry doesn't exist anymore!
                // but we can't remove it from the cache here:
                // the GetStatusForMember() method is called only with a read
                // lock and not a write lock!
                // So mark it for crawling, and let the crawler remove it
                // later
                CSVNStatusCache::Instance().AddFolderForCrawling(path.GetContainingDirectory());
                return CStatusCacheEntry();
            }
            else
            {
                // 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();
                }
            }
        }

        if (CSVNStatusCache::Instance().GetDirectoryCacheEntryNoCreate(path) != NULL)
        {
            // We don't have directory status in our cache
            // Ask the directory if it knows its own status
            CCachedDirectory * dirEntry = CSVNStatusCache::Instance().GetDirectoryCacheEntry(path);
            if ((dirEntry)&&(dirEntry->IsOwnStatusValid()))
            {
                // To keep recursive status up to date, we'll request that children are all crawled again
                // We have to do this because the directory watcher isn't very reliable (especially under heavy load)
                // and also has problems with SUBSTed drives.
                // If nothing has changed in those directories, this crawling is fast and only
                // accesses two files for each directory.
                if (bRecursive)
                {
                    AutoLocker lock(dirEntry->m_critSec);
                    ChildDirStatus::const_iterator it;
                    for(it = dirEntry->m_childDirectories.begin(); it != dirEntry->m_childDirectories.end(); ++it)
                    {
                        CTSVNPath newpath;
                        CString winPath = CUnicodeUtils::GetUnicode (it->first);
                        newpath.SetFromWin(winPath, true);

                        CSVNStatusCache::Instance().AddFolderForCrawling(newpath);
                    }
                }

                return dirEntry->GetOwnStatus(bRecursive);
            }
        }
        else
        {
            {
                // if we currently are fetching the status of the directory
                // we want the status for, we just return an empty entry here
                // and don't wait for that fetching to finish.
                // That's because fetching the status can take a *really* long
                // time (e.g. if a commit is also in progress on that same
                // directory), and we don't want to make the explorer appear
                // to hang.
                if ((!bFetch)&&(m_FetchingStatus))
                {
                    if (m_directoryPath.IsAncestorOf(path))
                    {
                        m_currentFullStatus = m_mostImportantFileStatus = svn_wc_status_none;
                        return GetCacheStatusForMember(path);
                    }
                }
            }
            // Look up a file in our own cache
            AutoLocker lock(m_critSec);
            strCacheKey = GetCacheKey(path);
            CacheEntryMap::iterator itMap = m_entryCache.find(strCacheKey);
            if(itMap != m_entryCache.end())
            {
                // We've hit the cache - check for timeout
                if(!itMap->second.HasExpired((long)GetTickCount()))
                {
                    if(itMap->second.DoesFileTimeMatch(path.GetLastWriteTime()))
                    {
                        if ((itMap->second.GetEffectiveStatus()!=svn_wc_status_missing)||(!PathFileExists(path.GetWinPath())))
                        {
                            // Note: the filetime matches after a modified has been committed too.
                            // So in that case, we would return a wrong status (e.g. 'modified' instead
                            // of 'normal') here.
                            return itMap->second;
                        }
                    }
                }
            }
        }
    }
    else
    {
        if ((!bFetch)&&(m_FetchingStatus))
        {
            if (m_directoryPath.IsAncestorOf(path))
            {
                // returning empty status (status fetch in progress)
                // also set the status to 'none' to have the status change and
                // the shell updater invoked in the crawler
                m_currentFullStatus = m_mostImportantFileStatus = svn_wc_status_none;
                CSVNStatusCache::Instance().AddFolderForCrawling(m_directoryPath.GetDirectory());
                return GetCacheStatusForMember(path);
            }
        }
        // if we're fetching the status for the explorer,
        // we don't refresh the status but use the one
        // 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_wcDbFileTime))
        {
            CSVNStatusCache::Instance().AddFolderForCrawling(m_directoryPath.GetDirectory());
            return GetCacheStatusForMember(path);
        }
        AutoLocker lock(m_critSec);
        m_entryCache.clear();
        strCacheKey = GetCacheKey(path);
    }

    // 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_SVNAdminDir.IsAdminDirPath(path.GetWinPathString()))
    {
        // We're being asked for the status of an .SVN directory
        // It's not worth asking for this
        return CStatusCacheEntry();
    }

    {
        if ((!bFetch)&&(m_FetchingStatus))
        {
            if (m_directoryPath.IsAncestorOf(path))
            {
                m_currentFullStatus = m_mostImportantFileStatus = svn_wc_status_none;
                return GetCacheStatusForMember(path);
            }
        }
    }

    {
        AutoLocker lock(m_critSec);
        m_mostImportantFileStatus = svn_wc_status_none;
        m_childDirectories.clear();
        m_entryCache.clear();
        m_ownStatus.SetStatus(NULL, false, false);
    }
    if(!bThisDirectoryIsUnversioned)
    {
        if (!SvnUpdateMembersStatus())
        {
            m_wcDbFileTime = 0;
            return CStatusCacheEntry();
        }
    }
    // Now that we've refreshed our SVN status, we can see if it's
    // changed the 'most important' status value for this directory.
    // If it has, then we should tell our parent
    UpdateCurrentStatus();

    m_wcDbFileTime = dbFileTime;
    if (path.IsDirectory())
    {
        CCachedDirectory * dirEntry = CSVNStatusCache::Instance().GetDirectoryCacheEntry(path);
        if ((dirEntry)&&(dirEntry->IsOwnStatusValid()))
        {
            //CSVNStatusCache::Instance().AddFolderForCrawling(path);
            return dirEntry->GetOwnStatus(bRecursive);
        }

        // If the status *still* isn't valid here, it means that
        // the current directory is unversioned, and we shall need to ask its children for info about themselves
        if ((dirEntry)&&(dirEntry != this))
            return dirEntry->GetStatusForMember(path,bRecursive);
        // add the path for crawling: if it's really unversioned, the crawler will
        // only check for the admin dir and do nothing more. But if it is
        // versioned (could happen in a nested layout) the crawler will update its
        // status correctly
        CSVNStatusCache::Instance().AddFolderForCrawling(path);
        return CStatusCacheEntry();
    }
    else
    {
        CacheEntryMap::iterator itMap = m_entryCache.find(strCacheKey);
        if(itMap != m_entryCache.end())
        {
            return itMap->second;
        }
    }

    AddEntry(path, NULL, false, false);
    return CStatusCacheEntry();
}
Example #12
0
CStatusCacheEntry CCachedDirectory::GetStatusFromGit(const CTGitPath &path, CString sProjectRoot)
{
	CString subpaths = path.GetGitPathString();
	if(subpaths.GetLength() >= sProjectRoot.GetLength())
	{
		if(subpaths[sProjectRoot.GetLength()] == _T('/'))
			subpaths=subpaths.Right(subpaths.GetLength() - sProjectRoot.GetLength()-1);
		else
			subpaths=subpaths.Right(subpaths.GetLength() - sProjectRoot.GetLength());
	}

	GitStatus *pGitStatus = &CGitStatusCache::Instance().m_GitStatus;

	CGitHash head;

	pGitStatus->GetHeadHash(sProjectRoot,head);

	bool isVersion =true;
	pGitStatus->IsUnderVersionControl(sProjectRoot, subpaths, path.IsDirectory(), &isVersion);
	if(!isVersion)
	{	//untracked file
		bool isIgnoreFileChanged=false;

		isIgnoreFileChanged = pGitStatus->IsGitReposChanged(sProjectRoot, subpaths, GIT_MODE_IGNORE);

		if( isIgnoreFileChanged)
		{
			pGitStatus->LoadIgnoreFile(sProjectRoot, subpaths);
		}

		if(path.IsDirectory())
		{

			CCachedDirectory * dirEntry = CGitStatusCache::Instance().GetDirectoryCacheEntry(path,
											false); /* we needn't watch untracked directory*/

			if(dirEntry)
			{
				AutoLocker lock(dirEntry->m_critSec);

				git_wc_status_kind dirstatus = dirEntry->GetCurrentFullStatus() ;
				if( dirstatus == git_wc_status_none || dirstatus >= git_wc_status_normal || isIgnoreFileChanged )
				{/* status have not initialized*/
					git_wc_status2_t status2;
					bool isignore = false;
					pGitStatus->IsIgnore(sProjectRoot,subpaths,&isignore);
					status2.text_status = status2.prop_status =
						(isignore? git_wc_status_ignored:git_wc_status_unversioned);

					dirEntry->m_ownStatus.SetStatus(&status2);
					dirEntry->m_ownStatus.SetKind(git_node_dir);

				}
				return dirEntry->m_ownStatus;
			}

		}
		else /* path is file */
		{
			AutoLocker lock(m_critSec);
			CString strCacheKey = GetCacheKey(path);

			CacheEntryMap::iterator itMap = m_entryCache.find(strCacheKey);
			if(itMap == m_entryCache.end() || isIgnoreFileChanged)
			{
				git_wc_status2_t status2;
				bool isignore = false;
				pGitStatus->IsIgnore(sProjectRoot,subpaths,&isignore);
				status2.text_status = status2.prop_status =
					(isignore? git_wc_status_ignored:git_wc_status_unversioned);
				AddEntry(path, &status2);
				return m_entryCache[strCacheKey];
			}
			else
			{
				return itMap->second;
			}
		}
		return CStatusCacheEntry();

	}
	else
	{
		EnumFiles((CTGitPath*)&path, TRUE);
		UpdateCurrentStatus();
		return CStatusCacheEntry(m_ownStatus);
	}

}