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; }
bool CSVNStatusCache::BlockPath(const CTSVNPath& path, bool specific, ULONGLONG timeout /* = 0 */) { if (timeout == 0) timeout = BLOCK_PATH_DEFAULT_TIMEOUT; if (timeout > BLOCK_PATH_MAX_TIMEOUT) timeout = BLOCK_PATH_MAX_TIMEOUT; timeout = GetTickCount64() + (timeout * 1000); // timeout is in seconds, but we need the milliseconds if (!specific) { CTSVNPath p(path); do { CTSVNPath dbPath(p); dbPath.AppendPathString(g_SVNAdminDir.GetAdminDirName() + L"\\wc.db"); if (!dbPath.Exists()) p = p.GetContainingDirectory(); else { CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": block path %s\n", p.GetWinPath()); AutoLocker lock(m_NoWatchPathCritSec); m_NoWatchPaths[p] = timeout; return true; } } while (!p.IsEmpty()); } CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": block path %s\n", path.GetWinPath()); AutoLocker lock(m_NoWatchPathCritSec); m_NoWatchPaths[path.GetDirectory()] = timeout; return true; }
bool CRemoteCacheLink::ReleaseLockForPath(const CTSVNPath& path) { EnsureCommandPipeOpen(); if (m_hCommandPipe) { DWORD cbWritten; TSVNCacheCommand cmd; SecureZeroMemory(&cmd, sizeof(TSVNCacheCommand)); cmd.command = TSVNCACHECOMMAND_RELEASE; wcsncpy_s(cmd.path, path.GetDirectory().GetWinPath(), MAX_PATH); BOOL fSuccess = WriteFile( m_hCommandPipe, // handle to pipe &cmd, // buffer to write from sizeof(cmd), // number of bytes to write &cbWritten, // number of bytes written NULL); // not overlapped I/O if (! fSuccess || sizeof(cmd) != cbWritten) { CloseCommandPipe(); return false; } return true; } return false; }
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 }
bool CSVNStatusCache::UnBlockPath(const CTSVNPath& path) { bool ret = false; CTSVNPath p(path); do { CTSVNPath dbPath(p); dbPath.AppendPathString(g_SVNAdminDir.GetAdminDirName() + L"\\wc.db"); if (!dbPath.Exists()) p = p.GetContainingDirectory(); else { AutoLocker lock(m_NoWatchPathCritSec); std::map<CTSVNPath, ULONGLONG>::iterator it = m_NoWatchPaths.find(p); if (it != m_NoWatchPaths.end()) { CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": path removed from no good: %s\n", it->first.GetWinPath()); m_NoWatchPaths.erase(it); ret = true; } break; } } while (!p.IsEmpty()); AutoLocker lock(m_NoWatchPathCritSec); std::map<CTSVNPath, ULONGLONG>::iterator it = m_NoWatchPaths.find(path.GetDirectory()); if (it != m_NoWatchPaths.end()) { CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": path removed from no good: %s\n", it->first.GetWinPath()); m_NoWatchPaths.erase(it); ret = true; } AddFolderForCrawling(path.GetDirectory()); return ret; }
int SVNBase::ShowErrorDialog( HWND hParent, const CTSVNPath& wcPath, const CString& sErr) { UNREFERENCED_PARAMETER(wcPath); int ret = -1; CString sError = Err ? GetErrorString(Err) : PostCommitErr; if (!sErr.IsEmpty()) sError = sErr; CString sCleanup = CString(MAKEINTRESOURCE(IDS_RUNCLEANUPNOW)); CString sClose = CString(MAKEINTRESOURCE(IDS_CLOSE)); CString sInstruction = CString(MAKEINTRESOURCE(IDS_SVNREPORTEDANERROR)); TASKDIALOGCONFIG tconfig = { 0 }; tconfig.cbSize = sizeof(TASKDIALOGCONFIG); tconfig.hwndParent = hParent; tconfig.dwFlags = TDF_ENABLE_HYPERLINKS | TDF_ALLOW_DIALOG_CANCELLATION | TDF_POSITION_RELATIVE_TO_WINDOW | TDF_SIZE_TO_CONTENT; tconfig.dwCommonButtons = TDCBF_CLOSE_BUTTON; tconfig.pszWindowTitle = L"TortoiseSVN"; tconfig.pszMainIcon = TD_ERROR_ICON; tconfig.pszMainInstruction = sInstruction; tconfig.pszContent = (LPCTSTR)sError; #ifdef HAVE_APPUTILS TASKDIALOG_BUTTON aCustomButtons[2]; aCustomButtons[0].nButtonID = 1000; aCustomButtons[0].pszButtonText = sCleanup; aCustomButtons[1].nButtonID = IDOK; aCustomButtons[1].pszButtonText = sClose; if (Err && (Err->apr_err == SVN_ERR_WC_CLEANUP_REQUIRED) && (!wcPath.IsEmpty())) { tconfig.dwCommonButtons = 0; tconfig.dwFlags |= TDF_USE_COMMAND_LINKS; tconfig.pButtons = aCustomButtons; tconfig.cButtons = _countof(aCustomButtons); } #endif TaskDialogIndirect(&tconfig, &ret, NULL, NULL); #ifdef HAVE_APPUTILS if (ret == 1000) { // run cleanup CString sCmd; sCmd.Format(L"/command:cleanup /path:\"%s\" /cleanup /nodlg /hwnd:%p", wcPath.GetDirectory().GetWinPath(), (void*)hParent); CAppUtils::RunTortoiseProc(sCmd); } #endif return ret; }
bool CSVNStatusCache::BlockPath(const CTSVNPath& path, DWORD timeout /* = 0 */) { if (timeout == 0) timeout = BLOCK_PATH_DEFAULT_TIMEOUT; if (timeout > BLOCK_PATH_MAX_TIMEOUT) timeout = BLOCK_PATH_MAX_TIMEOUT; timeout = GetTickCount() + (timeout * 1000); // timeout is in seconds, but we need the milliseconds AutoLocker lock(m_NoWatchPathCritSec); m_NoWatchPaths[path.GetDirectory()] = timeout; return true; }
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; }
bool SVNDiff::ShowCompare( const CTSVNPath& url1, const SVNRev& rev1, const CTSVNPath& url2, const SVNRev& rev2, SVNRev peg, bool ignoreprops, const CString& options, bool ignoreancestry /*= false*/, bool blame /*= false*/, svn_node_kind_t nodekind /*= svn_node_unknown*/ ) { CTSVNPath tempfile; CString mimetype; CProgressDlg progDlg; progDlg.SetTitle(IDS_APPNAME); progDlg.SetTime(false); m_pSVN->SetAndClearProgressInfo(&progDlg); CAppUtils::DiffFlags diffFlags; diffFlags.ReadOnly().AlternativeTool(m_bAlternativeTool); if ((m_pSVN->PathIsURL(url1))||(!rev1.IsWorking())||(!url1.IsEquivalentTo(url2))) { // no working copy path! progDlg.ShowModeless(GetHWND()); tempfile = CTempFiles::Instance().GetTempFilePath(false, url1); // first find out if the url points to a file or dir CString sRepoRoot; if ((nodekind != svn_node_dir)&&(nodekind != svn_node_file)) { progDlg.SetLine(1, CString(MAKEINTRESOURCE(IDS_PROGRESS_INFO))); SVNInfo info; const SVNInfoData * data = info.GetFirstFileInfo(url1, (peg.IsValid() ? peg : m_headPeg), rev1, svn_depth_empty); if (data == NULL) { data = info.GetFirstFileInfo(url1, (peg.IsValid() ? peg : rev1), rev1, svn_depth_empty); if (data == NULL) { data = info.GetFirstFileInfo(url1, (peg.IsValid() ? peg : rev2), rev1, svn_depth_empty); if (data == NULL) { progDlg.Stop(); m_pSVN->SetAndClearProgressInfo((HWND)NULL); info.ShowErrorDialog(GetHWND()); return false; } else { sRepoRoot = data->reposRoot; nodekind = data->kind; peg = peg.IsValid() ? peg : rev2; } } else { sRepoRoot = data->reposRoot; nodekind = data->kind; peg = peg.IsValid() ? peg : rev1; } } else { sRepoRoot = data->reposRoot; nodekind = data->kind; peg = peg.IsValid() ? peg : m_headPeg; } } else { sRepoRoot = m_pSVN->GetRepositoryRoot(url1); peg = peg.IsValid() ? peg : m_headPeg; } if (nodekind == svn_node_dir) { if (rev1.IsWorking()) { if (UnifiedDiff(tempfile, url1, rev1, url2, rev2, (peg.IsValid() ? peg : SVNRev::REV_WC), options)) { CString sWC; sWC.LoadString(IDS_DIFF_WORKINGCOPY); progDlg.Stop(); m_pSVN->SetAndClearProgressInfo((HWND)NULL); return !!CAppUtils::StartExtPatch(tempfile, url1.GetDirectory(), sWC, url2.GetSVNPathString(), TRUE); } } else { progDlg.Stop(); m_pSVN->SetAndClearProgressInfo((HWND)NULL); CFileDiffDlg fdlg; fdlg.DoBlame(blame); if (url1.IsEquivalentTo(url2)) { fdlg.SetDiff(url1, (peg.IsValid() ? peg : m_headPeg), rev1, rev2, svn_depth_infinity, ignoreancestry); fdlg.DoModal(); } else { fdlg.SetDiff(url1, rev1, url2, rev2, svn_depth_infinity, ignoreancestry); fdlg.DoModal(); } } } else { if (url1.IsEquivalentTo(url2) && !ignoreprops) { svn_revnum_t baseRev = 0; DiffProps(url1, rev2, rev1, baseRev); } // diffing two revs of a file, so export two files CTSVNPath tempfile1 = CTempFiles::Instance().GetTempFilePath(m_bRemoveTempFiles, blame ? CTSVNPath() : url1, rev1); CTSVNPath tempfile2 = CTempFiles::Instance().GetTempFilePath(m_bRemoveTempFiles, blame ? CTSVNPath() : url2, rev2); m_pSVN->SetAndClearProgressInfo(&progDlg, true); // activate progress bar progDlg.FormatPathLine(1, IDS_PROGRESSGETFILEREVISION, (LPCTSTR)url1.GetUIFileOrDirectoryName(), (LPCTSTR)rev1.ToString()); CAppUtils::GetMimeType(url1, mimetype, rev1); CBlame blamer; blamer.SetAndClearProgressInfo(&progDlg, true); if (blame) { if (!blamer.BlameToFile(url1, 1, rev1, peg.IsValid() ? peg : rev1, tempfile1, options, TRUE, TRUE)) { if ((peg.IsValid())&&(blamer.GetSVNError()->apr_err != SVN_ERR_CLIENT_IS_BINARY_FILE)) { if (!blamer.BlameToFile(url1, 1, rev1, rev1, tempfile1, options, TRUE, TRUE)) { progDlg.Stop(); m_pSVN->SetAndClearProgressInfo((HWND)NULL); blamer.ShowErrorDialog(GetHWND()); return false; } } else { if (blamer.GetSVNError()->apr_err != SVN_ERR_CLIENT_IS_BINARY_FILE) { progDlg.Stop(); m_pSVN->SetAndClearProgressInfo((HWND)NULL); } blamer.ShowErrorDialog(GetHWND()); if (blamer.GetSVNError()->apr_err == SVN_ERR_CLIENT_IS_BINARY_FILE) blame = false; else return false; } } } if (!blame) { bool tryWorking = (!m_pSVN->PathIsURL(url1) && rev1.IsWorking() && PathFileExists(url1.GetWinPath())); if (!m_pSVN->Export(url1, tempfile1, peg.IsValid() && !tryWorking ? peg : rev1, rev1)) { if (peg.IsValid()) { if (!m_pSVN->Export(url1, tempfile1, rev1, rev1)) { progDlg.Stop(); m_pSVN->SetAndClearProgressInfo((HWND)NULL); m_pSVN->ShowErrorDialog(GetHWND()); return false; } } else { progDlg.Stop(); m_pSVN->SetAndClearProgressInfo((HWND)NULL); m_pSVN->ShowErrorDialog(GetHWND()); return false; } } } SetFileAttributes(tempfile1.GetWinPath(), FILE_ATTRIBUTE_READONLY); progDlg.FormatPathLine(1, IDS_PROGRESSGETFILEREVISION, (LPCTSTR)url2.GetUIFileOrDirectoryName(), (LPCTSTR)rev2.ToString()); progDlg.SetProgress(50,100); if (blame) { if (!blamer.BlameToFile(url2, 1, rev2, peg.IsValid() ? peg : rev2, tempfile2, options, TRUE, TRUE)) { if (peg.IsValid()) { if (!blamer.BlameToFile(url2, 1, rev2, rev2, tempfile2, options, TRUE, TRUE)) { progDlg.Stop(); m_pSVN->SetAndClearProgressInfo((HWND)NULL); m_pSVN->ShowErrorDialog(GetHWND()); return false; } } else { progDlg.Stop(); m_pSVN->SetAndClearProgressInfo((HWND)NULL); m_pSVN->ShowErrorDialog(GetHWND()); return false; } } } else { if (!m_pSVN->Export(url2, tempfile2, peg.IsValid() ? peg : rev2, rev2)) { if (peg.IsValid()) { if (!m_pSVN->Export(url2, tempfile2, rev2, rev2)) { progDlg.Stop(); m_pSVN->SetAndClearProgressInfo((HWND)NULL); m_pSVN->ShowErrorDialog(GetHWND()); return false; } } else { progDlg.Stop(); m_pSVN->SetAndClearProgressInfo((HWND)NULL); m_pSVN->ShowErrorDialog(GetHWND()); return false; } } } SetFileAttributes(tempfile2.GetWinPath(), FILE_ATTRIBUTE_READONLY); progDlg.SetProgress(100,100); progDlg.Stop(); m_pSVN->SetAndClearProgressInfo((HWND)NULL); CString revname1, revname2; if (url1.IsEquivalentTo(url2)) { revname1.Format(L"%s Revision %s", (LPCTSTR)url1.GetUIFileOrDirectoryName(), (LPCTSTR)rev1.ToString()); revname2.Format(L"%s Revision %s", (LPCTSTR)url2.GetUIFileOrDirectoryName(), (LPCTSTR)rev2.ToString()); } else { if (sRepoRoot.IsEmpty()) { revname1.Format(L"%s Revision %s", (LPCTSTR)url1.GetSVNPathString(), (LPCTSTR)rev1.ToString()); revname2.Format(L"%s Revision %s", (LPCTSTR)url2.GetSVNPathString(), (LPCTSTR)rev2.ToString()); } else { if (url1.IsUrl()) revname1.Format(L"%s Revision %s", (LPCTSTR)url1.GetSVNPathString().Mid(sRepoRoot.GetLength()), (LPCTSTR)rev1.ToString()); else revname1.Format(L"%s Revision %s", (LPCTSTR)url1.GetSVNPathString(), (LPCTSTR)rev1.ToString()); if (url2.IsUrl() && (url2.GetSVNPathString().Left(sRepoRoot.GetLength()).Compare(sRepoRoot) == 0)) revname2.Format(L"%s Revision %s", (LPCTSTR)url2.GetSVNPathString().Mid(sRepoRoot.GetLength()), (LPCTSTR)rev2.ToString()); else revname2.Format(L"%s Revision %s", (LPCTSTR)url2.GetSVNPathString(), (LPCTSTR)rev2.ToString()); } } return CAppUtils::StartExtDiff(tempfile1, tempfile2, revname1, revname2, url1, url2, rev1, rev2, peg, diffFlags.Blame(blame), m_JumpLine, L"", mimetype); } } else { // compare with working copy if (PathIsDirectory(url1.GetWinPath())) { if (UnifiedDiff(tempfile, url1, rev1, url1, rev2, (peg.IsValid() ? peg : SVNRev::REV_WC), options)) { CString sWC, sRev; sWC.LoadString(IDS_DIFF_WORKINGCOPY); sRev.Format(IDS_DIFF_REVISIONPATCHED, (LONG)rev2); progDlg.Stop(); m_pSVN->SetAndClearProgressInfo((HWND)NULL); return !!CAppUtils::StartExtPatch(tempfile, url1.GetDirectory(), sWC, sRev, TRUE); } } else { ASSERT(rev1.IsWorking()); if (url1.IsEquivalentTo(url2) && !ignoreprops) { svn_revnum_t baseRev = 0; DiffProps(url1, rev1, rev2, baseRev); } m_pSVN->SetAndClearProgressInfo(&progDlg, true); // activate progress bar progDlg.ShowModeless(GetHWND()); progDlg.FormatPathLine(1, IDS_PROGRESSGETFILEREVISION, (LPCTSTR)url1.GetUIFileOrDirectoryName(), (LPCTSTR)rev2.ToString()); tempfile = CTempFiles::Instance().GetTempFilePath(m_bRemoveTempFiles, url1, rev2); if (blame) { CBlame blamer; if (!blamer.BlameToFile(url1, 1, rev2, (peg.IsValid() ? peg : SVNRev::REV_WC), tempfile, options, TRUE, TRUE)) { if (peg.IsValid()) { if (!blamer.BlameToFile(url1, 1, rev2, SVNRev::REV_WC, tempfile, options, TRUE, TRUE)) { progDlg.Stop(); m_pSVN->SetAndClearProgressInfo((HWND)NULL); m_pSVN->ShowErrorDialog(GetHWND()); return false; } } else { progDlg.Stop(); m_pSVN->SetAndClearProgressInfo((HWND)NULL); m_pSVN->ShowErrorDialog(GetHWND()); return false; } } progDlg.Stop(); m_pSVN->SetAndClearProgressInfo((HWND)NULL); SetFileAttributes(tempfile.GetWinPath(), FILE_ATTRIBUTE_READONLY); CTSVNPath tempfile2 = CTempFiles::Instance().GetTempFilePath(false, url1); if (!blamer.BlameToFile(url1, 1, SVNRev::REV_WC, SVNRev::REV_WC, tempfile2, options, TRUE, TRUE)) { progDlg.Stop(); m_pSVN->SetAndClearProgressInfo((HWND)NULL); m_pSVN->ShowErrorDialog(GetHWND()); return false; } CString revname, wcname; revname.Format(L"%s Revision %ld", (LPCTSTR)url1.GetFilename(), (LONG)rev2); wcname.Format(IDS_DIFF_WCNAME, (LPCTSTR)url1.GetFilename()); m_pSVN->SetAndClearProgressInfo((HWND)NULL); return CAppUtils::StartExtDiff(tempfile, tempfile2, revname, wcname, url1, url2, rev1, rev2, peg, diffFlags, m_JumpLine, url1.GetFileOrDirectoryName(), L""); } else { if (!m_pSVN->Export(url1, tempfile, (peg.IsValid() ? peg : SVNRev::REV_WC), rev2)) { if (peg.IsValid()) { if (!m_pSVN->Export(url1, tempfile, SVNRev::REV_WC, rev2)) { progDlg.Stop(); m_pSVN->SetAndClearProgressInfo((HWND)NULL); m_pSVN->ShowErrorDialog(GetHWND()); return false; } } else { progDlg.Stop(); m_pSVN->SetAndClearProgressInfo((HWND)NULL); m_pSVN->ShowErrorDialog(GetHWND()); return false; } } progDlg.Stop(); m_pSVN->SetAndClearProgressInfo((HWND)NULL); SetFileAttributes(tempfile.GetWinPath(), FILE_ATTRIBUTE_READONLY); CString revname, wcname; revname.Format(L"%s Revision %s", (LPCTSTR)url1.GetFilename(), (LPCTSTR)rev2.ToString()); wcname.Format(IDS_DIFF_WCNAME, (LPCTSTR)url1.GetFilename()); return CAppUtils::StartExtDiff(tempfile, url1, revname, wcname, url1, url1, rev2, rev1, peg, diffFlags, m_JumpLine, url1.GetFileOrDirectoryName(), L""); } } } m_pSVN->SetAndClearProgressInfo((HWND)NULL); return false; }
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; }
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; }
unsigned int __stdcall CommandThread(LPVOID lpvParam) { CCrashReportThread crashthread; CTraceToOutputDebugString::Instance()(__FUNCTION__ ": CommandThread started\n"); DWORD cbBytesRead; CAutoFile hPipe; // The thread's parameter is a handle to a pipe instance. hPipe = std::move((HANDLE) lpvParam); while (bRun) { // Read client requests from the pipe. TSVNCacheCommand command; BOOL fSuccess = ReadFile( hPipe, // handle to pipe &command, // buffer to receive data sizeof(command), // size of buffer &cbBytesRead, // number of bytes read NULL); // not overlapped I/O if (! fSuccess || cbBytesRead == 0) { DisconnectNamedPipe(hPipe); CTraceToOutputDebugString::Instance()(__FUNCTION__ ": Command thread exited\n"); return 1; } // sanitize request: // * Make sure the string properly 0-terminated // by resetting overlong paths to the empty string // * Set all trailing chars to 0. // This is more or less paranoia code but maybe something // is feeding garbage into our queue. for (size_t i = MAX_PATH+1; (i > 0) && (command.path[i-1] != 0); --i) command.path[i-1] = 0; size_t pathLength = wcslen (command.path); SecureZeroMemory ( command.path + pathLength , sizeof (command.path) - pathLength * sizeof (TCHAR)); // process request switch (command.command) { case TSVNCACHECOMMAND_END: FlushFileBuffers(hPipe); DisconnectNamedPipe(hPipe); CTraceToOutputDebugString::Instance()(__FUNCTION__ ": Command thread exited\n"); return 0; case TSVNCACHECOMMAND_CRAWL: { CTSVNPath changedpath; changedpath.SetFromWin(command.path, true); // remove the path from our cache - that will 'invalidate' it. { CAutoWriteLock writeLock(CSVNStatusCache::Instance().GetGuard()); CSVNStatusCache::Instance().RemoveCacheForPath(changedpath); } CSVNStatusCache::Instance().AddFolderForCrawling(changedpath.GetDirectory()); } break; case TSVNCACHECOMMAND_REFRESHALL: { CAutoWriteLock writeLock(CSVNStatusCache::Instance().GetGuard()); CSVNStatusCache::Instance().Refresh(); } break; case TSVNCACHECOMMAND_RELEASE: { CTSVNPath changedpath; changedpath.SetFromWin(command.path, true); CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": release handle for path %s\n", changedpath.GetWinPath()); CAutoWriteLock writeLock(CSVNStatusCache::Instance().GetGuard()); CSVNStatusCache::Instance().CloseWatcherHandles(changedpath); CSVNStatusCache::Instance().RemoveCacheForPath(changedpath); } break; case TSVNCACHECOMMAND_BLOCK: { CTSVNPath changedpath; changedpath.SetFromWin(command.path); CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": block path %s\n", changedpath.GetWinPath()); CSVNStatusCache::Instance().BlockPath(changedpath, false); } break; case TSVNCACHECOMMAND_UNBLOCK: { CTSVNPath changedpath; changedpath.SetFromWin(command.path); CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": unblock path %s\n", changedpath.GetWinPath()); CSVNStatusCache::Instance().UnBlockPath(changedpath); } break; } } // Flush the pipe to allow the client to read the pipe's contents // before disconnecting. Then disconnect the pipe, and close the // handle to this pipe instance. FlushFileBuffers(hPipe); DisconnectNamedPipe(hPipe); CTraceToOutputDebugString::Instance()(__FUNCTION__ ": Command thread exited\n"); return 0; }
bool ConflictEditorCommand::Execute() { CTSVNPath merge = cmdLinePath; CTSVNPath directory = merge.GetDirectory(); bool bRet = false; bool bAlternativeTool = !!parser.HasKey(_T("alternative")); // we have the conflicted file (%merged) // now look for the other required files SVNStatus stat; stat.GetStatus(merge); if (stat.status == NULL) return false; if (stat.status->text_status == svn_wc_status_conflicted) { // we have a text conflict, use our merge tool to resolve the conflict CTSVNPath theirs(directory); CTSVNPath mine(directory); CTSVNPath base(directory); bool bConflictData = false; if ((stat.status->entry)&&(stat.status->entry->conflict_new)) { theirs.AppendPathString(CUnicodeUtils::GetUnicode(stat.status->entry->conflict_new)); bConflictData = true; } if ((stat.status->entry)&&(stat.status->entry->conflict_old)) { base.AppendPathString(CUnicodeUtils::GetUnicode(stat.status->entry->conflict_old)); bConflictData = true; } if ((stat.status->entry)&&(stat.status->entry->conflict_wrk)) { mine.AppendPathString(CUnicodeUtils::GetUnicode(stat.status->entry->conflict_wrk)); bConflictData = true; } else { mine = merge; } if (bConflictData) bRet = !!CAppUtils::StartExtMerge(CAppUtils::MergeFlags().AlternativeTool(bAlternativeTool), base, theirs, mine, merge); } if (stat.status->prop_status == svn_wc_status_conflicted) { // we have a property conflict CTSVNPath prej(directory); if ((stat.status->entry)&&(stat.status->entry->prejfile)) { prej.AppendPathString(CUnicodeUtils::GetUnicode(stat.status->entry->prejfile)); // there's a problem: the prej file contains a _description_ of the conflict, and // that description string might be translated. That means we have no way of parsing // the file to find out the conflicting values. // The only thing we can do: show a dialog with the conflict description, then // let the user either accept the existing property or open the property edit dialog // to manually change the properties and values. And a button to mark the conflict as // resolved. CEditPropConflictDlg dlg; dlg.SetPrejFile(prej); dlg.SetConflictedItem(merge); bRet = (dlg.DoModal() != IDCANCEL); } } if (stat.status->tree_conflict) { // we have a tree conflict SVNInfo info; const SVNInfoData * pInfoData = info.GetFirstFileInfo(merge, SVNRev(), SVNRev()); if (pInfoData) { if (pInfoData->treeconflict_kind == svn_wc_conflict_kind_text) { CTSVNPath theirs(directory); CTSVNPath mine(directory); CTSVNPath base(directory); bool bConflictData = false; if (pInfoData->treeconflict_theirfile) { theirs.AppendPathString(pInfoData->treeconflict_theirfile); bConflictData = true; } if (pInfoData->treeconflict_basefile) { base.AppendPathString(pInfoData->treeconflict_basefile); bConflictData = true; } if (pInfoData->treeconflict_myfile) { mine.AppendPathString(pInfoData->treeconflict_myfile); bConflictData = true; } else { mine = merge; } if (bConflictData) bRet = !!CAppUtils::StartExtMerge(CAppUtils::MergeFlags().AlternativeTool(bAlternativeTool), base, theirs, mine, merge); } else if (pInfoData->treeconflict_kind == svn_wc_conflict_kind_tree) { CString sConflictAction; CString sConflictReason; CString sResolveTheirs; CString sResolveMine; CTSVNPath treeConflictPath = CTSVNPath(pInfoData->treeconflict_path); CString sItemName = treeConflictPath.GetUIFileOrDirectoryName(); if (pInfoData->treeconflict_nodekind == svn_node_file) { switch (pInfoData->treeconflict_operation) { default: case svn_wc_operation_none: case svn_wc_operation_update: switch (pInfoData->treeconflict_action) { default: case svn_wc_conflict_action_edit: sConflictAction.Format(IDS_TREECONFLICT_FILEUPDATEEDIT, (LPCTSTR)sItemName); sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_KEEPREPOSITORYFILE); break; case svn_wc_conflict_action_add: sConflictAction.Format(IDS_TREECONFLICT_FILEUPDATEADD, (LPCTSTR)sItemName); sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_KEEPREPOSITORYFILE); break; case svn_wc_conflict_action_delete: sConflictAction.Format(IDS_TREECONFLICT_FILEUPDATEDELETE, (LPCTSTR)sItemName); sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_REMOVEFILE); break; } break; case svn_wc_operation_switch: switch (pInfoData->treeconflict_action) { default: case svn_wc_conflict_action_edit: sConflictAction.Format(IDS_TREECONFLICT_FILESWITCHEDIT, (LPCTSTR)sItemName); sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_KEEPREPOSITORYFILE); break; case svn_wc_conflict_action_add: sConflictAction.Format(IDS_TREECONFLICT_FILESWITCHADD, (LPCTSTR)sItemName); sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_KEEPREPOSITORYFILE); break; case svn_wc_conflict_action_delete: sConflictAction.Format(IDS_TREECONFLICT_FILESWITCHDELETE, (LPCTSTR)sItemName); sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_REMOVEFILE); break; } break; case svn_wc_operation_merge: switch (pInfoData->treeconflict_action) { default: case svn_wc_conflict_action_edit: sConflictAction.Format(IDS_TREECONFLICT_FILEMERGEEDIT, (LPCTSTR)sItemName); sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_KEEPREPOSITORYFILE); break; case svn_wc_conflict_action_add: sConflictAction.Format(IDS_TREECONFLICT_FILEMERGEADD, (LPCTSTR)sItemName); sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_KEEPREPOSITORYFILE); break; case svn_wc_conflict_action_delete: sConflictAction.Format(IDS_TREECONFLICT_FILEMERGEDELETE, (LPCTSTR)sItemName); sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_REMOVEFILE); break; } break; } } else //if (pInfoData->treeconflict_nodekind == svn_node_dir) { switch (pInfoData->treeconflict_operation) { default: case svn_wc_operation_none: case svn_wc_operation_update: switch (pInfoData->treeconflict_action) { default: case svn_wc_conflict_action_edit: sConflictAction.Format(IDS_TREECONFLICT_DIRUPDATEEDIT, (LPCTSTR)sItemName); sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_KEEPREPOSITORYDIR); break; case svn_wc_conflict_action_add: sConflictAction.Format(IDS_TREECONFLICT_DIRUPDATEADD, (LPCTSTR)sItemName); sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_KEEPREPOSITORYDIR); break; case svn_wc_conflict_action_delete: sConflictAction.Format(IDS_TREECONFLICT_DIRUPDATEDELETE, (LPCTSTR)sItemName); sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_REMOVEDIR); break; } break; case svn_wc_operation_switch: switch (pInfoData->treeconflict_action) { default: case svn_wc_conflict_action_edit: sConflictAction.Format(IDS_TREECONFLICT_DIRSWITCHEDIT, (LPCTSTR)sItemName); sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_KEEPREPOSITORYDIR); break; case svn_wc_conflict_action_add: sConflictAction.Format(IDS_TREECONFLICT_DIRSWITCHADD, (LPCTSTR)sItemName); sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_KEEPREPOSITORYDIR); break; case svn_wc_conflict_action_delete: sConflictAction.Format(IDS_TREECONFLICT_DIRSWITCHDELETE, (LPCTSTR)sItemName); sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_REMOVEDIR); break; } break; case svn_wc_operation_merge: switch (pInfoData->treeconflict_action) { default: case svn_wc_conflict_action_edit: sConflictAction.Format(IDS_TREECONFLICT_DIRMERGEEDIT, (LPCTSTR)sItemName); sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_KEEPREPOSITORYDIR); break; case svn_wc_conflict_action_add: sConflictAction.Format(IDS_TREECONFLICT_DIRMERGEADD, (LPCTSTR)sItemName); sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_KEEPREPOSITORYDIR); break; case svn_wc_conflict_action_delete: sConflictAction.Format(IDS_TREECONFLICT_DIRMERGEDELETE, (LPCTSTR)sItemName); sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_REMOVEDIR); break; } break; } } UINT uReasonID = 0; switch (pInfoData->treeconflict_reason) { case svn_wc_conflict_reason_edited: uReasonID = IDS_TREECONFLICT_REASON_EDITED; sResolveMine.LoadString(pInfoData->treeconflict_nodekind == svn_node_dir ? IDS_TREECONFLICT_RESOLVE_KEEPLOCALDIR : IDS_TREECONFLICT_RESOLVE_KEEPLOCALFILE); break; case svn_wc_conflict_reason_obstructed: uReasonID = IDS_TREECONFLICT_REASON_OBSTRUCTED; sResolveMine.LoadString(pInfoData->treeconflict_nodekind == svn_node_dir ? IDS_TREECONFLICT_RESOLVE_KEEPLOCALDIR : IDS_TREECONFLICT_RESOLVE_KEEPLOCALFILE); break; case svn_wc_conflict_reason_deleted: uReasonID = IDS_TREECONFLICT_REASON_DELETED; sResolveMine.LoadString(IDS_TREECONFLICT_RESOLVE_MARKASRESOLVED); break; case svn_wc_conflict_reason_added: uReasonID = IDS_TREECONFLICT_REASON_ADDED; sResolveMine.LoadString(pInfoData->treeconflict_nodekind == svn_node_dir ? IDS_TREECONFLICT_RESOLVE_KEEPLOCALDIR : IDS_TREECONFLICT_RESOLVE_KEEPLOCALFILE); break; case svn_wc_conflict_reason_missing: uReasonID = IDS_TREECONFLICT_REASON_MISSING; sResolveMine.LoadString(IDS_TREECONFLICT_RESOLVE_MARKASRESOLVED); break; case svn_wc_conflict_reason_unversioned: uReasonID = IDS_TREECONFLICT_REASON_UNVERSIONED; sResolveMine.LoadString(pInfoData->treeconflict_nodekind == svn_node_dir ? IDS_TREECONFLICT_RESOLVE_KEEPLOCALDIR : IDS_TREECONFLICT_RESOLVE_KEEPLOCALFILE); break; } sConflictReason.Format(uReasonID, (LPCTSTR)sConflictAction); CTreeConflictEditorDlg dlg; dlg.SetConflictInfoText(sConflictReason); dlg.SetResolveTexts(sResolveTheirs, sResolveMine); dlg.SetPath(treeConflictPath); dlg.SetConflictSources(stat.status->tree_conflict->src_left_version, stat.status->tree_conflict->src_right_version); dlg.SetConflictReason(pInfoData->treeconflict_reason); dlg.SetConflictAction(pInfoData->treeconflict_action); INT_PTR dlgRet = dlg.DoModal(); bRet = (dlgRet != IDCANCEL); } } } return bRet; }
UINT CFileDiffDlg::ExportThread() { RefreshCursor(); if (m_pProgDlg == NULL) return 1; long count = 0; SetAndClearProgressInfo(m_pProgDlg, false); m_pProgDlg->SetTitle(IDS_PROGRESSWAIT); m_pProgDlg->SetAnimation(AfxGetResourceHandle(), IDR_DOWNLOAD); m_pProgDlg->ShowModeless(this); for (INT_PTR i=0; (i<m_arSelectedFileList.GetCount())&&(!m_pProgDlg->HasUserCancelled()); ++i) { CFileDiffDlg::FileDiff fd = m_arSelectedFileList[i]; CTSVNPath url1 = CTSVNPath(m_path1.GetSVNPathString() + _T("/") + fd.path.GetSVNPathString()); CTSVNPath url2 = m_bDoPegDiff ? url1 : CTSVNPath(m_path2.GetSVNPathString() + _T("/") + fd.path.GetSVNPathString()); if ((fd.node == svn_node_dir)&&(fd.kind != svn_client_diff_summarize_kind_added)) { // just create the directory CreateDirectoryEx(NULL, m_strExportDir+_T("\\")+CPathUtils::PathUnescape(fd.path.GetWinPathString()), NULL); continue; } CString sTemp; m_pProgDlg->FormatPathLine(1, IDS_PROGRESSGETFILE, (LPCTSTR)url1.GetSVNPathString()); CTSVNPath savepath = CTSVNPath(m_strExportDir); savepath.AppendPathString(_T("\\") + CPathUtils::PathUnescape(fd.path.GetWinPathString())); CPathUtils::MakeSureDirectoryPathExists(fd.node == svn_node_file ? savepath.GetContainingDirectory().GetWinPath() : savepath.GetDirectory().GetWinPath()); if (fd.node == svn_node_dir) { // exporting a folder requires calling SVN::Export() so we also export all // children of that added folder. if ((fd.kind == svn_client_diff_summarize_kind_added)&&(!Export(url2, savepath, m_bDoPegDiff ? m_peg : m_rev2, m_rev2, true, true))) { if ((!m_bDoPegDiff)||(!Export(url2, savepath, m_rev2, m_rev2, true, true))) { delete m_pProgDlg; m_pProgDlg = NULL; CMessageBox::Show(this->m_hWnd, GetLastErrorMessage(), _T("TortoiseSVN"), MB_ICONERROR); InterlockedExchange(&m_bThreadRunning, FALSE); RefreshCursor(); return 1; } } } else { // exporting a file requires calling SVN::Cat(), since SVN::Export() only works // with folders. if ((fd.kind != svn_client_diff_summarize_kind_deleted)&&(!Cat(url2, m_bDoPegDiff ? m_peg : m_rev2, m_rev2, savepath))) { if ((!m_bDoPegDiff)||(!Cat(url2, m_rev2, m_rev2, savepath))) { delete m_pProgDlg; m_pProgDlg = NULL; CMessageBox::Show(this->m_hWnd, GetLastErrorMessage(), _T("TortoiseSVN"), MB_ICONERROR); InterlockedExchange(&m_bThreadRunning, FALSE); RefreshCursor(); return 1; } } } count++; m_pProgDlg->SetProgress (count, static_cast<DWORD>(m_arSelectedFileList.GetCount())); } m_pProgDlg->Stop(); SetAndClearProgressInfo(NULL, false); delete m_pProgDlg; m_pProgDlg = NULL; InterlockedExchange(&m_bThreadRunning, FALSE); RefreshCursor(); return 0; }
bool ConflictEditorCommand::Execute() { CTSVNPath merge = cmdLinePath; CTSVNPath directory = merge.GetDirectory(); bool bRet = false; bool bAlternativeTool = !!parser.HasKey(L"alternative"); // Use Subversion 1.10 API to resolve possible tree conlifcts. SVNConflictInfo conflict; if (!conflict.Get(merge)) { conflict.ShowErrorDialog(GetExplorerHWND()); return false; } // Resolve tree conflicts first. if (conflict.HasTreeConflict()) { CProgressDlg progressDlg; progressDlg.SetTitle(IDS_PROC_EDIT_TREE_CONFLICTS); CString sProgressLine; sProgressLine.LoadString(IDS_PROGRS_FETCHING_TREE_CONFLICT_INFO); progressDlg.SetLine(1, sProgressLine); progressDlg.SetShowProgressBar(false); progressDlg.ShowModal(GetExplorerHWND(), FALSE); conflict.SetProgressDlg(&progressDlg); if (!conflict.FetchTreeDetails()) { // Ignore errors while fetching additional tree conflict information. // Use still may want to resolve it manually. conflict.ClearSVNError(); } progressDlg.Stop(); conflict.SetProgressDlg(NULL); CNewTreeConflictEditorDlg dlg; dlg.SetConflictInfo(&conflict); dlg.DoModal(GetExplorerHWND()); if (dlg.IsCancelled()) return false; if (dlg.GetResult() == svn_client_conflict_option_postpone) return false; // Send notififcation that status may be changed. We cannot use // '/resolvemsghwnd' here because satus of multiple files may be changed // during tree conflict resolution. if (parser.HasVal(L"refreshmsghwnd")) { HWND refreshMsgWnd = (HWND)parser.GetLongLongVal(L"refreshmsghwnd"); UINT WM_REFRESH_STATUS_MSG = RegisterWindowMessage(L"TORTOISESVN_REFRESH_STATUS_MSG"); ::PostMessage(refreshMsgWnd, WM_REFRESH_STATUS_MSG, 0, 0); } } // we have the conflicted file (%merged) // now look for the other required files SVNInfo info; const SVNInfoData * pInfoData = info.GetFirstFileInfo(merge, SVNRev(), SVNRev()); if (pInfoData == NULL) return false; for (auto conflIt = pInfoData->conflicts.cbegin(); conflIt != pInfoData->conflicts.cend(); ++conflIt) { switch (conflIt->kind) { case svn_wc_conflict_kind_text: { // we have a text conflict, use our merge tool to resolve the conflict CTSVNPath theirs = CTSVNPath(conflIt->conflict_new); CTSVNPath mine = CTSVNPath(conflIt->conflict_wrk); CTSVNPath base = CTSVNPath(conflIt->conflict_old); if (mine.IsEmpty()) mine = merge; bRet = !!CAppUtils::StartExtMerge(CAppUtils::MergeFlags().AlternativeTool(bAlternativeTool), base, theirs, mine, merge, true, CString(), CString(), CString(), CString(), merge.GetFileOrDirectoryName()); } break; case svn_wc_conflict_kind_property: { // we have a property conflict CTSVNPath prej(conflIt->prejfile); CEditPropConflictDlg dlg; dlg.SetPrejFile(prej); dlg.SetConflictedItem(merge); dlg.SetPropertyName(conflIt->propname); dlg.SetPropValues(conflIt->propvalue_base, conflIt->propvalue_working, conflIt->propvalue_incoming_old, conflIt->propvalue_incoming_new); bRet = (dlg.DoModal() != IDCANCEL); } break; case svn_wc_conflict_kind_tree: { CTSVNPath treeConflictPath = CTSVNPath(conflIt->treeconflict_path); CTreeConflictEditorDlg dlg; dlg.SetPath(treeConflictPath); dlg.SetConflictLeftSources(conflIt->src_left_version_url, conflIt->src_left_version_path, conflIt->src_left_version_rev, conflIt->src_left_version_kind); dlg.SetConflictRightSources(conflIt->src_right_version_url, conflIt->src_right_version_path, conflIt->src_right_version_rev, conflIt->src_right_version_kind); dlg.SetConflictReason(conflIt->treeconflict_reason); dlg.SetConflictAction(conflIt->treeconflict_action); dlg.SetConflictOperation(conflIt->treeconflict_operation); dlg.SetKind(conflIt->treeconflict_nodekind); INT_PTR dlgRet = dlg.DoModal(); bRet = (dlgRet != IDCANCEL); } break; } } return bRet; }