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