コード例 #1
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;
}
コード例 #2
0
ファイル: RenameCommand.cpp プロジェクト: fatterbetter/ZTools
bool RenameCommand::RenameWithReplace(HWND hWnd, const CTSVNPathList &srcPathList,
                                      const CTSVNPath &destPath,
                                      const CString &message /* = L"" */,
                                      bool move_as_child /* = false */,
                                      bool make_parents /* = false */) const
{
    SVN svn;
    UINT idret = IDYES;
    bool bRet = true;
    if (destPath.Exists() && !destPath.IsDirectory() && !destPath.IsEquivalentToWithoutCase(srcPathList[0]))
    {
        CString sReplace;
        sReplace.Format(IDS_PROC_REPLACEEXISTING, destPath.GetWinPath());

        CTaskDialog taskdlg(sReplace,
                            CString(MAKEINTRESOURCE(IDS_PROC_REPLACEEXISTING_TASK2)),
                            L"TortoiseSVN",
                            0,
                            TDF_USE_COMMAND_LINKS | TDF_ALLOW_DIALOG_CANCELLATION | TDF_POSITION_RELATIVE_TO_WINDOW);
        taskdlg.AddCommandControl(1, CString(MAKEINTRESOURCE(IDS_PROC_REPLACEEXISTING_TASK3)));
        taskdlg.AddCommandControl(2, CString(MAKEINTRESOURCE(IDS_PROC_REPLACEEXISTING_TASK4)));
        taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
        taskdlg.SetDefaultCommandControl(2);
        taskdlg.SetMainIcon(TD_WARNING_ICON);
        INT_PTR ret = taskdlg.DoModal(hWnd);
        if (ret == 1) // replace
            idret = IDYES;
        else
            idret = IDNO;

        if (idret == IDYES)
        {
            if (!svn.Remove(CTSVNPathList(destPath), true, false))
            {
                destPath.Delete(true);
            }
        }
    }
    if ((idret != IDNO)&&(!svn.Move(srcPathList, destPath, message, move_as_child, make_parents)))
    {
        auto apr_err = svn.GetSVNError()->apr_err;
        if ((apr_err == SVN_ERR_ENTRY_NOT_FOUND) || (apr_err == SVN_ERR_WC_PATH_NOT_FOUND))
        {
            bRet = !!MoveFile(srcPathList[0].GetWinPath(), destPath.GetWinPath());
        }
        else
        {
            svn.ShowErrorDialog(hWnd, srcPathList.GetCommonDirectory());
            bRet = false;
        }
    }
    if (idret == IDNO)
        bRet = false;
    return bRet;
}
コード例 #3
0
CCachedDirectory::CCachedDirectory(const CTSVNPath& directoryPath)
    : m_wcDbFileTime(0)
    , m_bCurrentFullStatusValid(false)
    , m_currentFullStatus(svn_wc_status_none)
    , m_mostImportantFileStatus(svn_wc_status_none)
    , m_pCtx(NULL)
    , m_FetchingStatus(FALSE)
{
    ATLASSERT(directoryPath.IsDirectory() || !PathFileExists(directoryPath.GetWinPath()));

    m_directoryPath = directoryPath;
}
コード例 #4
0
ファイル: TSVNPath.cpp プロジェクト: yuexiaoyun/tortoisesvn
    void GetDirectoryTest()
    {
        // Bit tricky, this test, because we need to know something about the file
        // layout on the machine which is running the test
        TCHAR winDir[MAX_PATH + 1] = { 0 };
        GetWindowsDirectory(winDir, _countof(winDir));
        CString sWinDir(winDir);

        CTSVNPath testPath;
        // This is a file which we know will always be there
        testPath.SetFromUnknown(sWinDir + L"\\win.ini");
        ATLASSERT(!testPath.IsDirectory());
        ATLASSERT(testPath.GetDirectory().GetWinPathString() == sWinDir);
        ATLASSERT(testPath.GetContainingDirectory().GetWinPathString() == sWinDir);

        // Now do the test on the win directory itself - It's hard to be sure about the containing directory
        // but we know it must be different to the directory itself
        testPath.SetFromUnknown(sWinDir);
        ATLASSERT(testPath.IsDirectory());
        ATLASSERT(testPath.GetDirectory().GetWinPathString() == sWinDir);
        ATLASSERT(testPath.GetContainingDirectory().GetWinPathString() != sWinDir);
        ATLASSERT(testPath.GetContainingDirectory().GetWinPathString().GetLength() < sWinDir.GetLength());

        // Try a root path
        testPath.SetFromUnknown(L"C:\\");
        ATLASSERT(testPath.IsDirectory());
        ATLASSERT(testPath.GetDirectory().GetWinPathString().CompareNoCase(L"C:\\")==0);
        ATLASSERT(testPath.GetContainingDirectory().IsEmpty());
        // Try a root UNC path
        testPath.SetFromUnknown(L"\\MYSTATION");
        ATLASSERT(testPath.GetContainingDirectory().IsEmpty());

        // test the UI path methods
        testPath.SetFromUnknown(L"c:\\testing%20test");
        ATLASSERT(testPath.GetUIFileOrDirectoryName().CompareNoCase(L"testing%20test") == 0);
#ifdef _MFC_VER
        testPath.SetFromUnknown(L"http://server.com/testing%20special%20chars%20%c3%a4%c3%b6%c3%bc");
        ATLASSERT(testPath.GetUIFileOrDirectoryName().CompareNoCase(L"testing special chars \344\366\374") == 0);
#endif
    }
コード例 #5
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);
    }
}
コード例 #6
0
bool DropExternalCommand::Execute()
{
    bool bSuccess = false;
    CString droppath = parser.GetVal(L"droptarget");
    CTSVNPath droptsvnpath = CTSVNPath(droppath);
    if (droptsvnpath.IsAdminDir())
        droptsvnpath = droptsvnpath.GetDirectory();
    if (!droptsvnpath.IsDirectory())
        droptsvnpath = droptsvnpath.GetDirectory();

    // first get the svn:externals property from the target folder
    SVNProperties props(droptsvnpath, SVNRev::REV_WC, false, false);
    std::string sExternalsValue;
    for (int i = 0; i < props.GetCount(); ++i)
    {
        if (props.GetItemName(i).compare(SVN_PROP_EXTERNALS) == 0)
        {
            sExternalsValue = props.GetItemValue(i);
            break;
        }
    }

    // we don't add admin dirs as externals
    pathList.RemoveAdminPaths();
    if (pathList.GetCount() == 0)
        return bSuccess;

    SVNStatus status;
    status.GetStatus(droptsvnpath);
    CString sTargetRepoRootUrl;
    if (status.status && status.status->repos_root_url)
    {
        sTargetRepoRootUrl = CUnicodeUtils::GetUnicode(status.status->repos_root_url);
    }
    if (sTargetRepoRootUrl.IsEmpty())
    {
        // failed to get the status and/or the repo root url
        CString messageString;
        messageString.Format(IDS_ERR_NOURLOFFILE, droptsvnpath.GetWinPath());
        ::MessageBox(GetExplorerHWND(), messageString, L"TortoiseSVN", MB_ICONERROR);
    }
    SVN svn;
    for (auto i = 0; i < pathList.GetCount(); ++i)
    {
        CTSVNPath destPath = droptsvnpath;
        destPath.AppendPathString(pathList[i].GetFileOrDirectoryName());
        bool bExists = !!PathFileExists(destPath.GetWinPath());
        if (!bExists &&
            (PathIsDirectory(pathList[i].GetWinPath()) || CopyFile(pathList[i].GetWinPath(), destPath.GetWinPath(), TRUE)))
        {
            SVNStatus sourceStatus;
            sourceStatus.GetStatus(pathList[i]);
            if (sourceStatus.status && sourceStatus.status->repos_root_url)
            {
                CString sExternalRootUrl = CUnicodeUtils::GetUnicode(sourceStatus.status->repos_root_url);
                CString sExternalUrl = svn.GetURLFromPath(pathList[i]);
                CString sExtValue = sExternalUrl + L" " + pathList[i].GetFileOrDirectoryName();
                // check if the url is from the same repo as the target, and if it is
                // use a relative external url instead of a full url
                if (sTargetRepoRootUrl.Compare(sExternalRootUrl) == 0)
                {
                    sExtValue = L"^" + sExternalUrl.Mid(sTargetRepoRootUrl.GetLength()) + L" " + pathList[i].GetFileOrDirectoryName();
                }
                if (!sExternalsValue.empty())
                {
                    if (sExternalsValue[sExternalsValue.size() - 1] != '\n')
                        sExternalsValue += "\n";
                }
                sExternalsValue += CUnicodeUtils::StdGetUTF8((LPCWSTR)sExtValue);
                bSuccess = true;
            }
        }
        else
        {
            // the file already exists, there can't be an external with the
            // same name.

            CString messageString;
            messageString.Format(IDS_DROPEXT_FILEEXISTS, (LPCWSTR)pathList[i].GetFileOrDirectoryName());
            ::MessageBox(GetExplorerHWND(), messageString, L"TortoiseSVN", MB_ICONERROR);
            bSuccess = false;
        }
    }
    if (bSuccess)
    {
        bSuccess = !!props.Add(SVN_PROP_EXTERNALS, sExternalsValue, true);
        if (bSuccess)
        {
            CString sInfo;
            sInfo.Format(IDS_DROPEXT_UPDATE_TASK1, (LPCTSTR)droptsvnpath.GetFileOrDirectoryName());
            CTaskDialog taskdlg(sInfo,
                                CString(MAKEINTRESOURCE(IDS_DROPEXT_UPDATE_TASK2)),
                                L"TortoiseSVN",
                                0,
                                TDF_ENABLE_HYPERLINKS | TDF_USE_COMMAND_LINKS | TDF_ALLOW_DIALOG_CANCELLATION | TDF_POSITION_RELATIVE_TO_WINDOW | TDF_SIZE_TO_CONTENT);
            taskdlg.AddCommandControl(1, CString(MAKEINTRESOURCE(IDS_DROPEXT_UPDATE_TASK3)));
            taskdlg.AddCommandControl(2, CString(MAKEINTRESOURCE(IDS_DROPEXT_UPDATE_TASK4)));
            taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
            taskdlg.SetDefaultCommandControl(2);
            taskdlg.SetMainIcon(TD_WARNING_ICON);
            bool doUpdate = (taskdlg.DoModal(GetExplorerHWND()) == 1);
            if (doUpdate)
            {
                DWORD exitcode = 0;
                CString error;
                ProjectProperties pprops;
                pprops.ReadPropsPathList(pathList);
                CHooks::Instance().SetProjectProperties(droptsvnpath, pprops);
                if (CHooks::Instance().StartUpdate(GetExplorerHWND(), pathList, exitcode, error))
                {
                    if (exitcode)
                    {
                        CString temp;
                        temp.Format(IDS_ERR_HOOKFAILED, (LPCTSTR)error);
                        ::MessageBox(GetExplorerHWND(), temp, L"TortoiseSVN", MB_ICONERROR);
                        return FALSE;
                    }
                }

                CSVNProgressDlg progDlg;
                theApp.m_pMainWnd = &progDlg;
                progDlg.SetCommand(CSVNProgressDlg::SVNProgress_Update);
                progDlg.SetAutoClose(parser);
                progDlg.SetOptions(ProgOptSkipPreChecks);
                progDlg.SetPathList(CTSVNPathList(droptsvnpath));
                progDlg.SetRevision(SVNRev(L"HEAD"));
                progDlg.SetProjectProperties(pprops);
                progDlg.SetDepth(svn_depth_unknown);
                progDlg.DoModal();
                return !progDlg.DidErrorsOccur();
            }
        }
        else
        {
            // adding the svn:externals property failed, remove all the copied files
            props.ShowErrorDialog(GetExplorerHWND());
        }
    }

    return bSuccess != false;
}
コード例 #7
0
ファイル: SVNDiff.cpp プロジェクト: code-mx/tortoisesvn
bool SVNDiff::DiffWCFile(const CTSVNPath& filePath,
                         bool ignoreprops,
                         svn_wc_status_kind status, /* = svn_wc_status_none */
                         svn_wc_status_kind text_status /* = svn_wc_status_none */,
                         svn_wc_status_kind prop_status /* = svn_wc_status_none */,
                         svn_wc_status_kind remotetext_status /* = svn_wc_status_none */,
                         svn_wc_status_kind remoteprop_status /* = svn_wc_status_none */)
{
    CTSVNPath basePath;
    CTSVNPath remotePath;
    SVNRev remoteRev;
    svn_revnum_t baseRev = 0;

    // first diff the remote properties against the wc props
    // TODO: should we attempt to do a three way diff with the properties too
    // if they're modified locally and remotely?
    if (!ignoreprops && (remoteprop_status > svn_wc_status_normal))
    {
        DiffProps(filePath, SVNRev::REV_HEAD, SVNRev::REV_WC, baseRev);
    }
    if (!ignoreprops && (prop_status > svn_wc_status_normal)&&(filePath.IsDirectory()))
    {
        DiffProps(filePath, SVNRev::REV_WC, SVNRev::REV_BASE, baseRev);
    }
    if (filePath.IsDirectory())
        return true;

    if ((status > svn_wc_status_normal) || (text_status > svn_wc_status_normal))
    {
        basePath = SVN::GetPristinePath(filePath);
        if (baseRev == 0)
        {
            SVNStatus stat;
            CTSVNPath dummy;
            svn_client_status_t * s = stat.GetFirstFileStatus(filePath, dummy);
            if (s)
                baseRev = s->revision >= 0 ? s->revision : s->changed_rev;
        }
        // If necessary, convert the line-endings on the file before diffing
        if ((DWORD)CRegDWORD(L"Software\\TortoiseSVN\\ConvertBase", TRUE))
        {
            CTSVNPath temporaryFile = CTempFiles::Instance().GetTempFilePath(m_bRemoveTempFiles, filePath, SVNRev::REV_BASE);
            if (!m_pSVN->Export(filePath, temporaryFile, SVNRev(SVNRev::REV_BASE), SVNRev(SVNRev::REV_BASE)))
            {
                temporaryFile.Reset();
            }
            else
            {
                basePath = temporaryFile;
                SetFileAttributes(basePath.GetWinPath(), FILE_ATTRIBUTE_READONLY);
            }
        }
    }

    if (remotetext_status > svn_wc_status_normal)
    {
        remotePath = CTempFiles::Instance().GetTempFilePath(false, filePath, SVNRev::REV_HEAD);

        CProgressDlg progDlg;
        progDlg.SetTitle(IDS_APPNAME);
        progDlg.SetTime(false);
        m_pSVN->SetAndClearProgressInfo(&progDlg, true);    // activate progress bar
        progDlg.ShowModeless(GetHWND());
        progDlg.FormatPathLine(1, IDS_PROGRESSGETFILE, (LPCTSTR)filePath.GetUIFileOrDirectoryName());
        remoteRev = SVNRev::REV_HEAD;
        if (!m_pSVN->Export(filePath, remotePath, remoteRev, remoteRev))
        {
            progDlg.Stop();
            m_pSVN->SetAndClearProgressInfo((HWND)NULL);
            m_pSVN->ShowErrorDialog(GetHWND());
            return false;
        }
        progDlg.Stop();
        m_pSVN->SetAndClearProgressInfo((HWND)NULL);
        SetFileAttributes(remotePath.GetWinPath(), FILE_ATTRIBUTE_READONLY);
    }

    CString name = filePath.GetUIFileOrDirectoryName();
    CString n1, n2, n3;
    n1.Format(IDS_DIFF_WCNAME, (LPCTSTR)name);
    if (baseRev)
        n2.FormatMessage(IDS_DIFF_BASENAMEREV, (LPCTSTR)name, baseRev);
    else
        n2.Format(IDS_DIFF_BASENAME, (LPCTSTR)name);
    n3.Format(IDS_DIFF_REMOTENAME, (LPCTSTR)name);

    if ((text_status <= svn_wc_status_normal)&&(prop_status <= svn_wc_status_normal)&&(status <= svn_wc_status_normal))
    {
        // Hasn't changed locally - diff remote against WC
        return CAppUtils::StartExtDiff(
            filePath, remotePath, n1, n3, filePath, filePath, SVNRev::REV_WC, remoteRev, remoteRev, CAppUtils::DiffFlags().AlternativeTool(m_bAlternativeTool),
            m_JumpLine, filePath.GetFileOrDirectoryName(), L"");
    }
    else if (remotePath.IsEmpty())
    {
        return DiffFileAgainstBase(filePath, baseRev, ignoreprops, status, text_status, prop_status);
    }
    else
    {
        // Three-way diff
        CAppUtils::MergeFlags flags;
        flags.bAlternativeTool = m_bAlternativeTool;
        flags.bReadOnly = true;
        return !!CAppUtils::StartExtMerge(flags,
            basePath, remotePath, filePath, CTSVNPath(), false, n2, n3, n1, CString(), filePath.GetFileOrDirectoryName());
    }
}
コード例 #8
0
ファイル: SVNDiff.cpp プロジェクト: code-mx/tortoisesvn
bool SVNDiff::UnifiedDiff(CTSVNPath& tempfile, const CTSVNPath& url1, const SVNRev& rev1, const CTSVNPath& url2, const SVNRev& rev2, const SVNRev& peg, const CString& options, bool bIgnoreAncestry /* = false */, bool bIgnoreProperties /* = true */)
{
    tempfile = CTempFiles::Instance().GetTempFilePath(m_bRemoveTempFiles, CTSVNPath(L"Test.diff"));
    bool bIsUrl = !!SVN::PathIsURL(url1);

    CProgressDlg progDlg;
    progDlg.SetTitle(IDS_APPNAME);
    progDlg.SetLine(1, CString(MAKEINTRESOURCE(IDS_PROGRESS_UNIFIEDDIFF)));
    progDlg.SetTime(false);
    m_pSVN->SetAndClearProgressInfo(&progDlg);
    progDlg.ShowModeless(GetHWND());
    // find the root of the files
    CTSVNPathList plist;
    plist.AddPath(url1);
    plist.AddPath(url2);
    CTSVNPath relativeTo = plist.GetCommonRoot();
    if (!relativeTo.IsUrl())
    {
        if (!relativeTo.IsDirectory())
            relativeTo = relativeTo.GetContainingDirectory();
    }
    if (relativeTo.IsEmpty() && url1.Exists() && url2.IsUrl())
    {
        // the source path exists, i.e. it's a local path, so
        // use this as the relative url
        relativeTo = url1.GetDirectory();
    }
    // the 'relativeTo' path must be a path: svn throws an error if it's used for urls.
    else if ((!url2.IsEquivalentTo(url1) && (relativeTo.IsEquivalentTo(url1) || relativeTo.IsEquivalentTo(url2))) || url1.IsUrl() || url2.IsUrl())
        relativeTo.Reset();
    if ((!url1.IsEquivalentTo(url2))||((rev1.IsWorking() || rev1.IsBase())&&(rev2.IsWorking() || rev2.IsBase())))
    {
        if (!m_pSVN->Diff(url1, rev1, url2, rev2, relativeTo, svn_depth_infinity, true, false, false, false, false, false, bIgnoreProperties, false, options, bIgnoreAncestry, tempfile))
        {
            progDlg.Stop();
            m_pSVN->SetAndClearProgressInfo((HWND)NULL);
            m_pSVN->ShowErrorDialog(GetHWND());
            return false;
        }
    }
    else
    {
        if (!m_pSVN->PegDiff(url1, (peg.IsValid() ? peg : (bIsUrl ? m_headPeg : SVNRev::REV_WC)), rev1, rev2, relativeTo, svn_depth_infinity, true, false, false, false, false, false, bIgnoreProperties, false, options, false, tempfile))
        {
            if (!m_pSVN->Diff(url1, rev1, url2, rev2, relativeTo, svn_depth_infinity, true, false, false, false, false, false, bIgnoreProperties, false, options, false, tempfile))
            {
                progDlg.Stop();
                m_pSVN->SetAndClearProgressInfo((HWND)NULL);
                m_pSVN->ShowErrorDialog(GetHWND());
                return false;
            }
        }
    }
    if (CAppUtils::CheckForEmptyDiff(tempfile))
    {
        progDlg.Stop();
        m_pSVN->SetAndClearProgressInfo((HWND)NULL);
        TaskDialog(GetHWND(), AfxGetResourceHandle(), MAKEINTRESOURCE(IDS_APPNAME), MAKEINTRESOURCE(IDS_ERR_ERROROCCURED), MAKEINTRESOURCE(IDS_ERR_EMPTYDIFF), TDCBF_OK_BUTTON, TD_ERROR_ICON, NULL);
        return false;
    }
    progDlg.Stop();
    m_pSVN->SetAndClearProgressInfo((HWND)NULL);
    return true;
}
コード例 #9
0
ファイル: SVNDiff.cpp プロジェクト: code-mx/tortoisesvn
bool SVNDiff::DiffFileAgainstBase( const CTSVNPath& filePath, svn_revnum_t & baseRev, bool ignoreprops, svn_wc_status_kind status /*= svn_wc_status_none*/, svn_wc_status_kind text_status /*= svn_wc_status_none*/, svn_wc_status_kind prop_status /*= svn_wc_status_none*/ )
{
    bool retvalue = false;
    bool fileexternal = false;
    if ((text_status == svn_wc_status_none)||(prop_status == svn_wc_status_none))
    {
        SVNStatus stat;
        stat.GetStatus(filePath);
        if (stat.status == NULL)
            return false;
        text_status = stat.status->text_status;
        prop_status = stat.status->prop_status;
        fileexternal = stat.status->file_external != 0;
    }
    if (!ignoreprops && (prop_status > svn_wc_status_normal))
    {
        DiffProps(filePath, SVNRev::REV_WC, SVNRev::REV_BASE, baseRev);
    }

    if (filePath.IsDirectory())
        return true;
    if ((status >= svn_wc_status_normal) || (text_status >= svn_wc_status_normal))
    {
        CTSVNPath basePath(SVN::GetPristinePath(filePath));
        if (baseRev == 0)
        {
            SVNInfo info;
            const SVNInfoData * infodata = info.GetFirstFileInfo(filePath, SVNRev(), SVNRev());

            if (infodata)
            {
                if (infodata->copyfromurl && infodata->copyfromurl[0])
                    baseRev = infodata->copyfromrev;
                else
                    baseRev = infodata->lastchangedrev;
            }
        }
        // If necessary, convert the line-endings on the file before diffing
        // note: file externals can not be exported
        if (((DWORD)CRegDWORD(L"Software\\TortoiseSVN\\ConvertBase", TRUE)) && (!fileexternal))
        {
            CTSVNPath temporaryFile = CTempFiles::Instance().GetTempFilePath(m_bRemoveTempFiles, filePath, SVNRev::REV_BASE);
            if (!m_pSVN->Export(filePath, temporaryFile, SVNRev(SVNRev::REV_BASE), SVNRev(SVNRev::REV_BASE)))
            {
                temporaryFile.Reset();
            }
            else
            {
                basePath = temporaryFile;
                SetFileAttributes(basePath.GetWinPath(), FILE_ATTRIBUTE_READONLY);
            }
        }
        // for added/deleted files, we don't have a BASE file.
        // create an empty temp file to be used.
        if (!basePath.Exists())
        {
            basePath = CTempFiles::Instance().GetTempFilePath(m_bRemoveTempFiles, filePath, SVNRev::REV_BASE);
            SetFileAttributes(basePath.GetWinPath(), FILE_ATTRIBUTE_READONLY);
        }
        CString name = filePath.GetFilename();
        CTSVNPath wcFilePath = filePath;
        if (!wcFilePath.Exists())
        {
            wcFilePath = CTempFiles::Instance().GetTempFilePath(m_bRemoveTempFiles, filePath, SVNRev::REV_BASE);
            SetFileAttributes(wcFilePath.GetWinPath(), FILE_ATTRIBUTE_READONLY);
        }
        CString n1, n2;
        n1.Format(IDS_DIFF_WCNAME, (LPCTSTR)name);
        if (baseRev)
            n2.FormatMessage(IDS_DIFF_BASENAMEREV, (LPCTSTR)name, baseRev);
        else
            n2.Format(IDS_DIFF_BASENAME, (LPCTSTR)name);
        retvalue = CAppUtils::StartExtDiff(
            basePath, wcFilePath, n2, n1,
            filePath, filePath, SVNRev::REV_BASE, SVNRev::REV_WC, SVNRev::REV_BASE,
            CAppUtils::DiffFlags().Wait().AlternativeTool(m_bAlternativeTool), m_JumpLine, name, L"");
    }
    return retvalue;
}
コード例 #10
0
void CShellUpdater::WorkerThread()
{
    HANDLE hWaitHandles[2];
    hWaitHandles[0] = m_hTerminationEvent;
    hWaitHandles[1] = m_hWakeEvent;

    for(;;)
    {
        DWORD waitResult = WaitForMultipleObjects(_countof(hWaitHandles), hWaitHandles, FALSE, INFINITE);

        // exit event/working loop if the first event (m_hTerminationEvent)
        // has been signaled or if one of the events has been abandoned
        // (i.e. ~CShellUpdater() is being executed)
        if(waitResult == WAIT_OBJECT_0 || waitResult == WAIT_ABANDONED_0 || waitResult == WAIT_ABANDONED_0+1)
        {
            // Termination event
            break;
        }
        // wait some time before we notify the shell
        Sleep(50);
        for(;;)
        {
            CTSVNPath workingPath;
            if (!m_bRunning)
                return;
            Sleep(0);
            {
                AutoLocker lock(m_critSec);
                if(m_pathsToUpdate.empty())
                {
                    // Nothing left to do
                    break;
                }
                
                if(InterlockedExchange(&m_bItemsAddedSinceLastUpdate, FALSE))
                {
                    m_pathsToUpdate.erase(std::unique(m_pathsToUpdate.begin(), m_pathsToUpdate.end(), &CTSVNPath::PredLeftEquivalentToRight), m_pathsToUpdate.end());
                }

                workingPath = m_pathsToUpdate.front();
                m_pathsToUpdate.pop_front();
            }
            if (workingPath.IsEmpty())
                continue;
            CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": shell notification for %s\n", workingPath.GetWinPath());
            if (workingPath.IsDirectory())
            {
                // first send a notification about a sub folder change, so explorer doesn't discard
                // the folder notification. Since we only know for sure that the subversion admin
                // dir is present, we send a notification for that folder.
                CString admindir = workingPath.GetWinPathString() + L"\\" + g_SVNAdminDir.GetAdminDirName();
                SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH | SHCNF_FLUSHNOWAIT, (LPCTSTR)admindir, NULL);
                SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH | SHCNF_FLUSHNOWAIT, workingPath.GetWinPath(), NULL);
                // Sending an UPDATEDIR notification somehow overwrites/deletes the UPDATEITEM message. And without
                // that message, the folder overlays in the current view don't get updated without hitting F5.
                // Drawback is, without UPDATEDIR, the left tree view isn't always updated...

                //SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_PATH | SHCNF_FLUSHNOWAIT, workingPath.GetWinPath(), NULL);
            }
            else
                SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH | SHCNF_FLUSHNOWAIT, workingPath.GetWinPath(), NULL);
        }
    }
    _endthread();
}
コード例 #11
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.
    LONGLONG now = (LONGLONG)GetTickCount64();
    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 (m_shellCache.IsPathAllowed(path.GetWinPath()))
    {
        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);

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

        }
        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);
            if ((itMap != m_directoryCache.end())&&(itMap->second))
            {
                // 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);
    m_mostRecentStatus = CStatusCacheEntry();
    if (m_shellCache.ShowExcludedAsNormal() && path.IsDirectory() && m_shellCache.IsVersioned(path.GetWinPath(), true, true))
    {
        m_mostRecentStatus.ForceStatus(svn_wc_status_normal);
    }
    return m_mostRecentStatus;
}
コード例 #12
0
ファイル: RemoveCommand.cpp プロジェクト: fatterbetter/ZTools
bool RemoveCommand::Execute()
{
    bool bRet = false;
    // removing items from a working copy is done item-by-item so we
    // have a chance to show a progress bar
    //
    // removing items from an URL in the repository requires that we
    // ask the user for a log message.
    SVN svn;
    if ((pathList.GetCount())&&(SVN::PathIsURL(pathList[0])))
    {
        // Delete using URL's, not wc paths
        svn.SetPromptApp(&theApp);
        CInputLogDlg dlg;
        CString sUUID;
        svn.GetRepositoryRootAndUUID(pathList[0], true, sUUID);
        dlg.SetUUID(sUUID);
        CString sHint;
        if (pathList.GetCount() == 1)
            sHint.Format(IDS_INPUT_REMOVEONE, (LPCTSTR)pathList[0].GetSVNPathString());
        else
            sHint.Format(IDS_INPUT_REMOVEMORE, pathList.GetCount());
        dlg.SetActionText(sHint);
        if (dlg.DoModal()==IDOK)
        {
            if (!svn.Remove(pathList, true, !!parser.HasKey(L"keep"), dlg.GetLogMessage()))
            {
                svn.ShowErrorDialog(GetExplorerHWND(), pathList.GetCommonDirectory());
                return false;
            }
            return true;
        }
        return false;
    }
    else
    {
        bool bForce = false;
        for(int nPath = 0; nPath < pathList.GetCount(); nPath++)
        {
            CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": remove file %s\n", (LPCTSTR)pathList[nPath].GetUIPathString());
            // even though SVN::Remove takes a list of paths to delete at once
            // we delete each item individually so we can prompt the user
            // if something goes wrong or unversioned/modified items are
            // to be deleted
            CTSVNPathList removePathList(pathList[nPath]);
            if ((bForce)&&(!parser.HasKey(L"keep")))
            {
                CTSVNPath delPath = removePathList[0];
                if (!delPath.IsDirectory())
                    delPath.Delete(true);
                // note: we don't move folders to the trash bin, so they can't
                // get restored anymore - svn removes *all* files in a removed
                // folder, even modified and unversioned ones
                // We could move the folders here to the trash bin too, but then
                // the folder would be gone and will require a recursive commit.
                // Of course: a solution would be to first create a copy of the folder,
                // move the original folder to the trash, then rename the copied folder
                // to the original name, then let svn delete the folder - but
                // that would just take too much time for bigger folders...
            }
            if (!svn.Remove(removePathList, bForce, !!parser.HasKey(L"keep")))
            {
                if ((svn.GetSVNError()->apr_err == SVN_ERR_UNVERSIONED_RESOURCE) ||
                    (svn.GetSVNError()->apr_err == SVN_ERR_CLIENT_MODIFIED))
                {
                    UINT ret = 0;
                    CString msg;
                    if (pathList[nPath].IsDirectory())
                        msg.Format(IDS_PROC_REMOVEFORCE_TASK1_2, (LPCTSTR)svn.GetLastErrorMessage(0), (LPCTSTR)pathList[nPath].GetFileOrDirectoryName());
                    else
                        msg.Format(IDS_PROC_REMOVEFORCE_TASK1, (LPCTSTR)svn.GetLastErrorMessage(0), (LPCTSTR)pathList[nPath].GetFileOrDirectoryName());
                    CTaskDialog taskdlg(msg,
                                        CString(MAKEINTRESOURCE(IDS_PROC_REMOVEFORCE_TASK2)),
                                        L"TortoiseSVN",
                                        0,
                                        TDF_ENABLE_HYPERLINKS | TDF_USE_COMMAND_LINKS | TDF_ALLOW_DIALOG_CANCELLATION | TDF_POSITION_RELATIVE_TO_WINDOW);
                    taskdlg.AddCommandControl(IDYES, CString(MAKEINTRESOURCE(IDS_PROC_REMOVEFORCE_TASK3)));
                    taskdlg.AddCommandControl(IDNO, CString(MAKEINTRESOURCE(IDS_PROC_REMOVEFORCE_TASK4)));
                    taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
                    taskdlg.SetVerificationCheckboxText(CString(MAKEINTRESOURCE(IDS_PROC_REMOVEFORCE_TASK5)));
                    taskdlg.SetDefaultCommandControl(IDNO);
                    taskdlg.SetMainIcon(TD_WARNING_ICON);
                    ret = (UINT)taskdlg.DoModal(GetExplorerHWND());
                    if (taskdlg.GetVerificationCheckboxState())
                        bForce = true;
                    if (ret == IDYESTOALL)
                        bForce = true;
                    if ((ret == IDYES)||(ret==IDYESTOALL))
                    {
                        if (!parser.HasKey(L"keep"))
                        {
                            CTSVNPath delPath = removePathList[0];
                            if (!delPath.IsDirectory())
                                delPath.Delete(true);
                            // note: see comment for the delPath.Delete() above
                        }
                        if (!svn.Remove(removePathList, true, !!parser.HasKey(L"keep")))
                        {
                            svn.ShowErrorDialog(GetExplorerHWND(), removePathList.GetCommonDirectory());
                        }
                        else
                            bRet = true;
                    }
                }
                else
                    svn.ShowErrorDialog(GetExplorerHWND(), removePathList.GetCommonDirectory());
            }
        }
    }
    if (bRet)
        CShellUpdater::Instance().AddPathsForUpdate(pathList);
    return bRet;
}
コード例 #13
0
svn_error_t * CCachedDirectory::GetStatusCallback(void *baton, const char *path, const svn_client_status_t *status, apr_pool_t * pool)
{
    CCachedDirectory* pThis = (CCachedDirectory*)baton;

    if (path == NULL)
        return SVN_NO_ERROR;

    CTSVNPath svnPath;
    bool forceNormal = false;
    bool needsLock = false;

    const svn_wc_status_kind nodeStatus = status->node_status;
    if(status->versioned)
    {
        if ((nodeStatus != svn_wc_status_none)&&(nodeStatus != svn_wc_status_ignored))
            svnPath.SetFromSVN(path, (status->kind == svn_node_dir));
        else
            svnPath.SetFromSVN(path);

        if(svnPath.IsDirectory())
        {
            if(!svnPath.IsEquivalentToWithoutCase(pThis->m_directoryPath))
            {
                // Make sure we know about this child directory
                // This initial status value is likely to be overwritten from below at some point
                svn_wc_status_kind s = nodeStatus;
                if (status->conflicted)
                    s = SVNStatus::GetMoreImportant(s, svn_wc_status_conflicted);
                CCachedDirectory * cdir = CSVNStatusCache::Instance().GetDirectoryCacheEntryNoCreate(svnPath);
                if (cdir)
                {
                    // This child directory is already in our cache!
                    // So ask this dir about its recursive status
                    svn_wc_status_kind st = SVNStatus::GetMoreImportant(s, cdir->GetCurrentFullStatus());
                    pThis->SetChildStatus(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.
                    CSVNStatusCache::Instance().GetDirectoryCacheEntry(svnPath);
                    pThis->SetChildStatus(svnPath, s);
                }
            }
        }
        else
        {
            // only fetch the svn:needs-lock property if the status of this file is 'normal', because
            // if the status is something else, the needs-lock overlay won't show up anyway
            if ((pThis->m_pCtx)&&(nodeStatus == svn_wc_status_normal))
            {
                const svn_string_t * value = NULL;
                svn_error_t * err = svn_wc_prop_get2(&value, pThis->m_pCtx->wc_ctx, path, "svn:needs-lock", pool, pool);
                if ((err==NULL) && value)
                    needsLock = true;
                if (err)
                    svn_error_clear(err);
            }
        }
    }
    else
    {
        if ((status->kind != svn_node_unknown)&&(status->kind != svn_node_none))
            svnPath.SetFromSVN(path, status->kind == svn_node_dir);
        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 (((nodeStatus == svn_wc_status_unversioned)||(nodeStatus == svn_wc_status_ignored))&&(!svnPath.IsEquivalentToWithoutCase(pThis->m_directoryPath))&&(svnPath.IsDirectory()))
        {
            if (svnPath.IsWCRoot())
            {
                CSVNStatusCache::Instance().AddFolderForCrawling(svnPath);
                // Mark the directory as 'versioned' (status 'normal' for now).
                // This initial value will be overwritten from below some time later
                pThis->SetChildStatus(svnPath, svn_wc_status_normal);
                // Make sure the entry is also in the cache
                CSVNStatusCache::Instance().GetDirectoryCacheEntry(svnPath);
                // also mark the status in the status object as normal
                forceNormal = true;
            }
            else
            {
                pThis->SetChildStatus(svnPath, nodeStatus);
            }
        }
        else if (nodeStatus == svn_wc_status_external)
        {
            if ((status->kind == svn_node_dir) || (svnPath.IsDirectory()))
            {
                CSVNStatusCache::Instance().AddFolderForCrawling(svnPath);
                // Mark the directory as 'versioned' (status 'normal' for now).
                // This initial value will be overwritten from below some time later
                pThis->SetChildStatus(svnPath, svn_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.
                CSVNStatusCache::Instance().GetDirectoryCacheEntry(svnPath);
                // also mark the status in the status object as normal
                forceNormal = true;
            }
        }
        else
        {
            if (svnPath.IsDirectory())
            {
                svn_wc_status_kind s = nodeStatus;
                if (status->conflicted)
                    s = SVNStatus::GetMoreImportant(s, svn_wc_status_conflicted);
                pThis->SetChildStatus(svnPath, s);
            }
        }
    }

    pThis->AddEntry(svnPath, status, needsLock, forceNormal);

    return SVN_NO_ERROR;
}
コード例 #14
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();
}
コード例 #15
0
ファイル: RemoveCommand.cpp プロジェクト: fatterbetter/ZTools
bool RemoveCommand::Execute()
{
	bool bRet = false;
	// removing items from a working copy is done item-by-item so we
	// have a chance to show a progress bar
	//
	// removing items from an URL in the repository requires that we
	// ask the user for a log message.
	bool bForce = false;
	SVN svn;
	if ((pathList.GetCount())&&(SVN::PathIsURL(pathList[0])))
	{
		// Delete using URL's, not wc paths
		svn.SetPromptApp(&theApp);
		CInputLogDlg dlg;
		CString sUUID;
		svn.GetRepositoryRootAndUUID(pathList[0], true, sUUID);
		dlg.SetUUID(sUUID);
		CString sHint;
		if (pathList.GetCount() == 1)
			sHint.Format(IDS_INPUT_REMOVEONE, (LPCTSTR)pathList[0].GetSVNPathString());
		else
			sHint.Format(IDS_INPUT_REMOVEMORE, pathList.GetCount());
		dlg.SetActionText(sHint);
		if (dlg.DoModal()==IDOK)
		{
			if (!svn.Remove(pathList, true, !!parser.HasKey(_T("keep")), dlg.GetLogMessage()))
			{
				CMessageBox::Show(hwndExplorer, svn.GetLastErrorMessage(), _T("TortoiseSVN"), MB_ICONERROR);
				return false;
			}
			return true;
		}
		return false;
	}
	else
	{
		for(int nPath = 0; nPath < pathList.GetCount(); nPath++)
		{
			TRACE(_T("remove file %s\n"), (LPCTSTR)pathList[nPath].GetUIPathString());
			// even though SVN::Remove takes a list of paths to delete at once
			// we delete each item individually so we can prompt the user
			// if something goes wrong or unversioned/modified items are
			// to be deleted
			CTSVNPathList removePathList(pathList[nPath]);
			if ((bForce)&&(!parser.HasKey(_T("keep"))))
			{
				CTSVNPath delPath = removePathList[0];
				if (!delPath.IsDirectory())
					delPath.Delete(true);
				// note: we don't move folders to the trash bin, so they can't
				// get restored anymore - svn removes *all* files in a removed
				// folder, even modified and unversioned ones
				// We could move the folders here to the trash bin too, but then
				// the folder would be gone and will require a recursive commit.
				// Of course: a solution would be to first create a copy of the folder,
				// move the original folder to the trash, then rename the copied folder
				// to the original name, then let svn delete the folder - but
				// that would just take too much time for bigger folders...
			}
			if (!svn.Remove(removePathList, bForce, !!parser.HasKey(_T("keep"))))
			{
				if ((svn.Err->apr_err == SVN_ERR_UNVERSIONED_RESOURCE) ||
					(svn.Err->apr_err == SVN_ERR_CLIENT_MODIFIED))
				{
					CString msg, yes, no, yestoall;
					if (pathList[nPath].IsDirectory())
					{
						msg.Format(IDS_PROC_REMOVEFORCEFOLDER, pathList[nPath].GetWinPath());
					}
					else
					{
						msg.Format(IDS_PROC_REMOVEFORCE, (LPCTSTR)svn.GetLastErrorMessage());
					}
					yes.LoadString(IDS_MSGBOX_YES);
					no.LoadString(IDS_MSGBOX_NO);
					yestoall.LoadString(IDS_PROC_YESTOALL);
					UINT ret = CMessageBox::Show(hwndExplorer, msg, _T("TortoiseSVN"), 2, IDI_ERROR, yes, no, yestoall);
					if (ret == 3)
						bForce = true;
					if ((ret == 1)||(ret==3))
					{
						if (!parser.HasKey(_T("keep")))
						{
							CTSVNPath delPath = removePathList[0];
							if (!delPath.IsDirectory())
								delPath.Delete(true);
							// note: see comment for the delPath.Delete() above
						}
						if (!svn.Remove(removePathList, true, !!parser.HasKey(_T("keep"))))
						{
							CMessageBox::Show(hwndExplorer, svn.GetLastErrorMessage(), _T("TortoiseSVN"), MB_ICONERROR);
						}
						else
							bRet = true;
					}
				}
				else
					CMessageBox::Show(hwndExplorer, svn.GetLastErrorMessage(), _T("TortoiseSVN"), MB_ICONERROR);
			}
		}
	}
	if (bRet)
		CShellUpdater::Instance().AddPathsForUpdate(pathList);
	return bRet;
}