int CGitPropertyPage::LogThread() { CTGitPath path(filenames.front().c_str()); CAutoLocker lock(g_Git.m_critGitDllSec); // HACK for libgit2 CString ProjectTopDir; if(!path.HasAdminDir(&ProjectTopDir)) return 0; CAutoRepository repository(CUnicodeUtils::GetUTF8(ProjectTopDir)); if (!repository) return 0; int stripLength = ProjectTopDir.GetLength(); if (ProjectTopDir[stripLength - 1] != _T('\\')) ++stripLength; CTGitPath relatepath; relatepath.SetFromWin(path.GetWinPathString().Mid(stripLength)); CAutoCommit commit(FindFileRecentCommit(repository, relatepath.GetGitPathString())); if (commit) { SendMessage(m_hwnd, m_UpdateLastCommit, NULL, (LPARAM)(git_commit*)commit); } else { SendMessage(m_hwnd, m_UpdateLastCommit, NULL, NULL); } return 0; }
LRESULT CAddDlg::OnFileDropped(WPARAM, LPARAM lParam) { BringWindowToTop(); SetForegroundWindow(); SetActiveWindow(); // if multiple files/folders are dropped // this handler is called for every single item // separately. // To avoid creating multiple refresh threads and // causing crashes, we only add the items to the // list control and start a timer. // When the timer expires, we start the refresh thread, // but only if it isn't already running - otherwise we // restart the timer. CTGitPath path; path.SetFromWin((LPCTSTR)lParam); // check whether the dropped file belongs to the very same repository CString projectDir; if (!path.HasAdminDir(&projectDir) || !CTGitPath::ArePathStringsEqual(g_Git.m_CurrentDir, projectDir)) return 0; if (!m_addListCtrl.HasPath(path)) { if (m_pathList.AreAllPathsFiles()) { m_pathList.AddPath(path); m_pathList.RemoveDuplicates(); } else { // if the path list contains folders, we have to check whether // our just (maybe) added path is a child of one of those. If it is // a child of a folder already in the list, we must not add it. Otherwise // that path could show up twice in the list. bool bHasParentInList = false; for (int i=0; i<m_pathList.GetCount(); ++i) { if (m_pathList[i].IsAncestorOf(path)) { bHasParentInList = true; break; } } if (!bHasParentInList) { m_pathList.AddPath(path); m_pathList.RemoveDuplicates(); } } } m_addListCtrl.ResetChecked(path); // Always start the timer, since the status of an existing item might have changed SetTimer(REFRESHTIMER, 200, nullptr); CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": Item %s dropped, timer started\n", path.GetWinPath()); return 0; }
int _tmain(int argc, _TCHAR* argv[]) { CTGitPath path; CString root; TCHAR buff[256]; GetCurrentDirectory(256,buff); path.SetFromWin(buff); if(!path.HasAdminDir(&root)) { printf("not in git repository\n"); return -1; } CGitIndexList list; list.ReadIndex(root+_T("\\.git\\index")); CGitHeadFileList filelist; filelist.ReadHeadHash(buff); _tprintf(_T("update %d\n"), filelist.CheckHeadUpdate()); git_init(); // filelist.ReadTree(); WIN32_FIND_DATA data; CString str(buff); str+=_T("\\*.*"); GitStatus status; HANDLE handle = FindFirstFile(str,&data); while(FindNextFile(handle,&data)) { if( _tcsnccmp(data.cFileName, _T(".."),2) ==0) continue; if( _tcsnccmp(data.cFileName, _T("."),1) ==0 ) continue; CString spath(buff); spath += _T("\\"); spath += data.cFileName; CTGitPath path(spath); TCHAR name[100]; int t1,t2; t1 = ::GetCurrentTime(); status.GetStatusString(status.GetAllStatus(path), 100,name); t2 = ::GetCurrentTime(); _tprintf(_T("%s - %s - %d\n"),data.cFileName, name, t2-t1); } return 0; }
CTGitPath CTGitPath::GetSubPath(const CTGitPath &root) { CTGitPath path; if(GetWinPathString().Left(root.GetWinPathString().GetLength()) == root.GetWinPathString()) { CString str=GetWinPathString(); path.SetFromWin(str.Right(str.GetLength()-root.GetWinPathString().GetLength()-1)); } return path; }
void CPatchListCtrl::OnNMDblclk(NMHDR *pNMHDR, LRESULT *pResult) { LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR); CString path=GetItemText(pNMItemActivate->iItem,0); CTGitPath gitpath; gitpath.SetFromWin(path); CAppUtils::StartUnifiedDiffViewer(path,gitpath.GetFilename()); *pResult = 0; }
LRESULT CAddDlg::OnFileDropped(WPARAM, LPARAM lParam) { BringWindowToTop(); SetForegroundWindow(); SetActiveWindow(); // if multiple files/folders are dropped // this handler is called for every single item // separately. // To avoid creating multiple refresh threads and // causing crashes, we only add the items to the // list control and start a timer. // When the timer expires, we start the refresh thread, // but only if it isn't already running - otherwise we // restart the timer. CTGitPath path; path.SetFromWin((LPCTSTR)lParam); if (!m_addListCtrl.HasPath(path)) { if (m_pathList.AreAllPathsFiles()) { m_pathList.AddPath(path); m_pathList.RemoveDuplicates(); } else { // if the path list contains folders, we have to check whether // our just (maybe) added path is a child of one of those. If it is // a child of a folder already in the list, we must not add it. Otherwise // that path could show up twice in the list. bool bHasParentInList = false; for (int i=0; i<m_pathList.GetCount(); ++i) { if (m_pathList[i].IsAncestorOf(path)) { bHasParentInList = true; break; } } if (!bHasParentInList) { m_pathList.AddPath(path); m_pathList.RemoveDuplicates(); } } } // Always start the timer, since the status of an existing item might have changed SetTimer(REFRESHTIMER, 200, NULL); ATLTRACE(_T("Item %s dropped, timer started\n"), path.GetWinPath()); return 0; }
VOID GetAnswerToRequest(const TGITCacheRequest* pRequest, TGITCacheResponse* pReply, DWORD* pResponseLength) { CTGitPath path; *pResponseLength = 0; if(pRequest->flags & TGITCACHE_FLAGS_FOLDERISKNOWN) { path.SetFromWin(pRequest->path, !!(pRequest->flags & TGITCACHE_FLAGS_ISFOLDER)); } else { path.SetFromWin(pRequest->path); } CAutoReadWeakLock readLock(CGitStatusCache::Instance().GetGuard(), 2000); if (readLock.IsAcquired()) { CGitStatusCache::Instance().GetStatusForPath(path, pRequest->flags, false).BuildCacheResponse(*pReply, *pResponseLength); } else { CStatusCacheEntry entry; entry.BuildCacheResponse(*pReply, *pResponseLength); } }
VOID GetAnswerToRequest(const TGITCacheRequest* pRequest, TGITCacheResponse* pReply, DWORD* pResponseLength) { CTGitPath path; *pResponseLength = 0; if(pRequest->flags & TGITCACHE_FLAGS_FOLDERISKNOWN) { path.SetFromWin(pRequest->path, !!(pRequest->flags & TGITCACHE_FLAGS_ISFOLDER)); } else { path.SetFromWin(pRequest->path); } if (CGitStatusCache::Instance().WaitToRead(2000)) { CGitStatusCache::Instance().GetStatusForPath(path, pRequest->flags, false).BuildCacheResponse(*pReply, *pResponseLength); CGitStatusCache::Instance().Done(); } else { CStatusCacheEntry entry; entry.BuildCacheResponse(*pReply, *pResponseLength); } }
CTGitPath CTempFiles::ConstructTempPath(const CTGitPath& path) { DWORD len = ::GetTempPath(0, nullptr); auto temppath = std::make_unique<TCHAR[]>(len + 1); auto tempF = std::make_unique<TCHAR[]>(len + 50); ::GetTempPath (len+1, temppath.get()); CTGitPath tempfile; CString possibletempfile; if (path.IsEmpty()) { ::GetTempFileName(temppath.get(), L"tsm", 0, tempF.get()); tempfile = CTGitPath (tempF.get()); } else { int i=0; do { // use the UI path, which does unescaping for urls CString filename = path.GetUIFileOrDirectoryName(); // remove illegal chars which could be present in urls filename.Remove('?'); filename.Remove('*'); filename.Remove('<'); filename.Remove('>'); filename.Remove('|'); filename.Remove('"'); // the inner loop assures that the resulting path is < MAX_PATH // if that's not possible without reducing the 'filename' to less than 5 chars, use a path // that's longer than MAX_PATH (in that case, we can't really do much to avoid longer paths) do { possibletempfile.Format(L"%s%s.tsm%3.3x.tmp%s", temppath.get(), (LPCTSTR)filename, i, (LPCTSTR)path.GetFileExtension()); tempfile.SetFromWin(possibletempfile); filename = filename.Left(filename.GetLength()-1); } while ( (filename.GetLength() > 4) && (tempfile.GetWinPathString().GetLength() >= MAX_PATH)); i++; } while (PathFileExists(tempfile.GetWinPath())); } // caller has to actually grab the file path return tempfile; }
void CImportPatchDlg::OnBnClickedCancel() { if(this->m_bThreadRunning) { InterlockedExchange(&m_bExitThread,TRUE); } else { CTGitPath path; path.SetFromWin(g_Git.m_CurrentDir); if(path.HasRebaseApply()) if(CMessageBox::Show(NULL, IDS_PROC_APPLYPATCH_GITAMACTIVE, IDS_APPNAME, MB_YESNO | MB_ICONQUESTION) == IDYES) { CString output; if (g_Git.Run(_T("git.exe am --abort"), &output, CP_UTF8)) MessageBox(output, _T("TortoiseGit"), MB_OK | MB_ICONERROR); } OnCancel(); } }
void CImportPatchDlg::OnBnClickedCancel() { if(this->m_bThreadRunning) { InterlockedExchange(&m_bExitThread,TRUE); } else { CTGitPath path; path.SetFromWin(g_Git.m_CurrentDir); if(path.HasRebaseApply()) if(MessageBox(_T("\"git am\" is still in apply mode.\nDo you want to abort?"), _T("TortoiseGit"), MB_YESNO | MB_ICONQUESTION) == IDYES) { CString output; if(g_Git.Run(_T("git.exe am --abort"), &output, CP_ACP)) MessageBox(output, _T("TortoiseGit error"), MB_OK); } OnCancel(); } }
void CSendMailDlg::OnBnClickedOk() { this->UpdateData(); if (m_To.IsEmpty() && m_CC.IsEmpty() && CRegDWORD(_T("Software\\TortoiseGit\\TortoiseProc\\SendMail\\DeliveryType"), SEND_MAIL_MAPI) != SEND_MAIL_MAPI) { CMessageBox::Show(NULL,IDS_ERR_ADDRESS_NO_EMPTY,IDS_APPNAME,MB_OK|MB_ICONERROR); return; } int start =0; CString Address; while(start>=0) { Address=this->m_CC.Tokenize(_T(";"),start); m_AddressReg.AddEntry(Address); m_AddressReg.Save(); } start =0; while(start>=0) { Address=this->m_To.Tokenize(_T(";"),start); m_AddressReg.AddEntry(Address); m_AddressReg.Save(); } this->m_PathList.Clear(); for (int i = 0; i < m_ctrlList.GetItemCount(); ++i) { CTGitPath path; if(m_ctrlList.GetCheck(i)) { path.SetFromWin(m_ctrlList.GetItemText(i,0)); this->m_PathList.AddPath(path); } } m_regAttach=m_bAttachment; m_regCombine=m_bCombine; OnOK(); }
bool ImportPatchCommand::Execute() { CImportPatchDlg dlg; // dlg.m_bIsTag=TRUE; CString cmd; CString output; if (!orgPathList.IsEmpty() && !orgPathList[0].HasAdminDir()) { CString str=CAppUtils::ChooseRepository(NULL); if(str.IsEmpty()) return FALSE; CTGitPath path; path.SetFromWin(str); if(!path.HasAdminDir()) { CString err; err.Format(IDS_ERR_NOT_REPOSITORY, (LPCTSTR)str); CMessageBox::Show(NULL,err,_T("TortoiseGit"),MB_OK|MB_ICONERROR); return FALSE; } g_Git.m_CurrentDir=str; } for(int i = 0 ; i < this->orgPathList.GetCount(); ++i) { if(!orgPathList[i].IsDirectory()) { dlg.m_PathList.AddPath(orgPathList[i]); } } if(dlg.DoModal()==IDOK) { return TRUE; } return FALSE; }
CTGitPath CTempFiles::GetTempFilePath(bool bRemoveAtEnd, const CTGitPath& path /* = CTGitPath() */, const GitRev revision /* = GitRev() */) { DWORD len = ::GetTempPath(0, NULL); TCHAR * temppath = new TCHAR[len+1]; TCHAR * tempF = new TCHAR[len+50]; ::GetTempPath (len+1, temppath); CTGitPath tempfile; CString possibletempfile; if (path.IsEmpty()) { ::GetTempFileName (temppath, TEXT("git"), 0, tempF); tempfile = CTGitPath(tempF); } else { int i=0; do { if (!((GitRev&)revision).m_CommitHash.IsEmpty()) { possibletempfile.Format(_T("%s%s-rev%s.git%3.3x.tmp%s"), temppath, (LPCTSTR)path.GetFileOrDirectoryName(), (LPCTSTR)((GitRev&)revision).m_CommitHash.ToString().Left(7), i, (LPCTSTR)path.GetFileExtension()); } else { possibletempfile.Format(_T("%s%s.git%3.3x.tmp%s"), temppath, (LPCTSTR)path.GetFileOrDirectoryName(), i, (LPCTSTR)path.GetFileExtension()); } tempfile.SetFromWin(possibletempfile); i++; } while (PathFileExists(tempfile.GetWinPath())); } //now create the temp file, so that subsequent calls to GetTempFile() return //different filenames. HANDLE hFile = CreateFile(tempfile.GetWinPath(), GENERIC_READ, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, NULL); CloseHandle(hFile); delete [] temppath; delete [] tempF; if (bRemoveAtEnd) m_TempFileList.AddPath(tempfile); return tempfile; }
CTGitPath CTGitPath::GetContainingDirectory() const { EnsureBackslashPathSet(); CString sDirName = m_sBackslashPath.Left(m_sBackslashPath.ReverseFind('\\')); if(sDirName.GetLength() == 2 && sDirName[1] == ':') { // This is a root directory, which needs a trailing slash sDirName += '\\'; if(sDirName == m_sBackslashPath) { // We were clearly provided with a root path to start with - we should return nothing now sDirName.Empty(); } } if(sDirName.GetLength() == 1 && sDirName[0] == '\\') { // We have an UNC path and we already are the root sDirName.Empty(); } CTGitPath retVal; retVal.SetFromWin(sDirName); return retVal; }
BOOL CGitPropertyPage::PageProc (HWND /*hwnd*/, UINT uMessage, WPARAM wParam, LPARAM lParam) { switch (uMessage) { case WM_INITDIALOG: { InitWorkfileView(); return TRUE; } case WM_NOTIFY: { LPNMHDR point = (LPNMHDR)lParam; int code = point->code; // // Respond to notifications. // if (code == PSN_APPLY && m_bChanged) { do { CTGitPath path(filenames.front().c_str()); CString projectTopDir; if(!path.HasAdminDir(&projectTopDir) || path.IsDirectory()) break; int stripLength = projectTopDir.GetLength(); if (projectTopDir[stripLength - 1] != _T('\\')) ++stripLength; CAutoRepository repository(CUnicodeUtils::GetUTF8(projectTopDir)); if (!repository) break; CAutoIndex index; if (git_repository_index(index.GetPointer(), repository)) break; BOOL assumeValid = (BOOL)SendMessage(GetDlgItem(m_hwnd, IDC_ASSUMEVALID), BM_GETCHECK, 0, 0); BOOL skipWorktree = (BOOL)SendMessage(GetDlgItem(m_hwnd, IDC_SKIPWORKTREE), BM_GETCHECK, 0, 0); BOOL executable = (BOOL)SendMessage(GetDlgItem(m_hwnd, IDC_EXECUTABLE), BM_GETCHECK, 0, 0); BOOL symlink = (BOOL)SendMessage(GetDlgItem(m_hwnd, IDC_SYMLINK), BM_GETCHECK, 0, 0); bool changed = false; for (auto it = filenames.cbegin(); it < filenames.cend(); ++it) { CTGitPath file; file.SetFromWin(CString(it->c_str()).Mid(stripLength)); CStringA pathA = CUnicodeUtils::GetMulti(file.GetGitPathString(), CP_UTF8); size_t idx; if (!git_index_find(&idx, index, pathA)) { git_index_entry *e = const_cast<git_index_entry *>(git_index_get_byindex(index, idx)); // HACK if (assumeValid == BST_CHECKED) { if (!(e->flags & GIT_IDXENTRY_VALID)) { e->flags |= GIT_IDXENTRY_VALID; changed = true; } } else if (assumeValid != BST_INDETERMINATE) { if (e->flags & GIT_IDXENTRY_VALID) { e->flags &= ~GIT_IDXENTRY_VALID; changed = true; } } if (skipWorktree == BST_CHECKED) { if (!(e->flags_extended & GIT_IDXENTRY_SKIP_WORKTREE)) { e->flags_extended |= GIT_IDXENTRY_SKIP_WORKTREE; changed = true; } } else if (skipWorktree != BST_INDETERMINATE) { if (e->flags_extended & GIT_IDXENTRY_SKIP_WORKTREE) { e->flags_extended &= ~GIT_IDXENTRY_SKIP_WORKTREE; changed = true; } } if (executable == BST_CHECKED) { if (!(e->mode & 0111)) { e->mode |= 0111; changed = true; } } else if (executable != BST_INDETERMINATE) { if (e->mode & 0111) { e->mode &= ~0111; changed = true; } } if (symlink == BST_CHECKED) { if ((e->mode & GIT_FILEMODE_LINK) != GIT_FILEMODE_LINK) { e->mode |= GIT_FILEMODE_LINK; changed = true; } } else if (symlink != BST_INDETERMINATE) { if ((e->mode & GIT_FILEMODE_LINK) == GIT_FILEMODE_LINK) { e->mode &= ~GIT_FILEMODE_LINK; changed = true; } } if (changed) git_index_add(index, e); } } if (changed) { if (!git_index_write(index)) m_bChanged = false; } } while (0); } SetWindowLongPtr (m_hwnd, DWLP_MSGRESULT, FALSE); return TRUE; } case WM_DESTROY: return TRUE; case WM_COMMAND: PageProcOnCommand(wParam); break; } // switch (uMessage) if (uMessage == m_UpdateLastCommit) { DisplayCommit((git_commit *)lParam, IDC_LAST_HASH, IDC_LAST_SUBJECT, IDC_LAST_AUTHOR, IDC_LAST_DATE); return TRUE; } return FALSE; }
BOOL CTortoiseGitBlameDoc::OnOpenDocument(LPCTSTR lpszPathName,CString Rev) { if(Rev.IsEmpty()) Rev = _T("HEAD"); // enable blame for files which do not exist in current working tree if (!PathFileExists(lpszPathName) && Rev != _T("HEAD")) { if (!CDocument::OnOpenDocument(GetTempFile())) return FALSE; } else { if (!CDocument::OnOpenDocument(lpszPathName)) return FALSE; } m_CurrentFileName = lpszPathName; m_Rev=Rev; // (SDI documents will reuse this document) if(!g_Git.CheckMsysGitDir()) { CCommonAppUtils::RunTortoiseGitProc(_T(" /command:settings")); return FALSE; } CString topdir; if (!GitAdminDir::HasAdminDir(m_CurrentFileName, &topdir)) { CString temp; temp.Format(IDS_CANNOTBLAMENOGIT, (LPCTSTR)m_CurrentFileName); MessageBox(nullptr, temp, _T("TortoiseGitBlame"), MB_OK | MB_ICONERROR); return FALSE; } else { m_IsGitFile=TRUE; sOrigCWD = g_Git.m_CurrentDir = topdir; CString PathName = m_CurrentFileName; if(topdir[topdir.GetLength()-1] == _T('\\') || topdir[topdir.GetLength()-1] == _T('/')) PathName=PathName.Right(PathName.GetLength()-g_Git.m_CurrentDir.GetLength()); else PathName=PathName.Right(PathName.GetLength()-g_Git.m_CurrentDir.GetLength()-1); CTGitPath path; path.SetFromWin(PathName); if(!g_Git.m_CurrentDir.IsEmpty()) SetCurrentDirectory(g_Git.m_CurrentDir); try { // make sure all config files are read in order to check that none contains an error g_Git.GetConfigValue(_T("doesnot.exist")); } catch (char * libgiterr) { MessageBox(nullptr, CString(libgiterr), _T("TortoiseGitBlame"), MB_ICONERROR); return FALSE; } CString cmd, option; int dwDetectMovedOrCopiedLines = theApp.GetInt(_T("DetectMovedOrCopiedLines"), BLAME_DETECT_MOVED_OR_COPIED_LINES_DISABLED); int dwDetectMovedOrCopiedLinesNumCharactersWithinFile = theApp.GetInt(_T("DetectMovedOrCopiedLinesNumCharactersWithinFile"), BLAME_DETECT_MOVED_OR_COPIED_LINES_NUM_CHARACTERS_WITHIN_FILE_DEFAULT); int dwDetectMovedOrCopiedLinesNumCharactersFromFiles = theApp.GetInt(_T("DetectMovedOrCopiedLinesNumCharactersFromFiles"), BLAME_DETECT_MOVED_OR_COPIED_LINES_NUM_CHARACTERS_FROM_FILES_DEFAULT); switch(dwDetectMovedOrCopiedLines) { default: case BLAME_DETECT_MOVED_OR_COPIED_LINES_DISABLED: option.Empty(); break; case BLAME_DETECT_MOVED_OR_COPIED_LINES_WITHIN_FILE: option.Format(_T("-M%d"), dwDetectMovedOrCopiedLinesNumCharactersWithinFile); break; case BLAME_DETECT_MOVED_OR_COPIED_LINES_FROM_MODIFIED_FILES: option.Format(_T("-C%d"), dwDetectMovedOrCopiedLinesNumCharactersFromFiles); break; case BLAME_DETECT_MOVED_OR_COPIED_LINES_FROM_EXISTING_FILES_AT_FILE_CREATION: option.Format(_T("-C -C%d"), dwDetectMovedOrCopiedLinesNumCharactersFromFiles); break; case BLAME_DETECT_MOVED_OR_COPIED_LINES_FROM_EXISTING_FILES: option.Format(_T("-C -C -C%d"), dwDetectMovedOrCopiedLinesNumCharactersFromFiles); break; } if (theApp.GetInt(_T("IgnoreWhitespace"), 0) == 1) option += _T(" -w"); cmd.Format(_T("git.exe blame -p %s %s -- \"%s\""), (LPCTSTR)option, (LPCTSTR)Rev, (LPCTSTR)path.GetGitPathString()); m_BlameData.clear(); BYTE_VECTOR err; if(g_Git.Run(cmd, &m_BlameData, &err)) { CString str; if (!m_BlameData.empty()) CGit::StringAppend(&str, &m_BlameData[0], CP_UTF8); if (!err.empty()) CGit::StringAppend(&str, &err[0], CP_UTF8); MessageBox(nullptr, CString(MAKEINTRESOURCE(IDS_BLAMEERROR)) + _T("\n\n") + str, _T("TortoiseGitBlame"), MB_OK | MB_ICONERROR); return FALSE; } #ifdef USE_TEMPFILENAME if(!m_TempFileName.IsEmpty()) { ::DeleteFile(m_TempFileName); m_TempFileName.Empty(); } m_TempFileName=GetTempFile(); cmd.Format(_T("git.exe cat-file blob %s:\"%s\""), (LPCTSTR)Rev, (LPCTSTR)path.GetGitPathString()); if(g_Git.RunLogFile(cmd, m_TempFileName)) { CString str; str.Format(IDS_CHECKOUTFAILED, (LPCTSTR)path.GetGitPathString()); MessageBox(nullptr, CString(MAKEINTRESOURCE(IDS_BLAMEERROR)) + _T("\n\n") + str, _T("TortoiseGitBlame"), MB_OK | MB_ICONERROR); return FALSE; } #endif m_GitPath = path; CTortoiseGitBlameView *pView=DYNAMIC_DOWNCAST(CTortoiseGitBlameView,GetMainFrame()->GetActiveView()); if (!pView) { CWnd* pWnd = GetMainFrame()->GetDescendantWindow(AFX_IDW_PANE_FIRST, TRUE); if (pWnd && pWnd->IsKindOf(RUNTIME_CLASS(CTortoiseGitBlameView))) { pView = (CTortoiseGitBlameView*)pWnd; } else { return FALSE; } } pView->ParseBlame(); BOOL bShowCompleteLog = (theApp.GetInt(_T("ShowCompleteLog"), 1) == 1); if (bShowCompleteLog && BlameIsLimitedToOneFilename(dwDetectMovedOrCopiedLines)) { if (GetMainFrame()->m_wndOutput.LoadHistory(path.GetGitPathString(), m_Rev, (theApp.GetInt(_T("FollowRenames"), 0) == 1))) return FALSE; } else { std::set<CGitHash> hashes; pView->m_data.GetHashes(hashes); if (GetMainFrame()->m_wndOutput.LoadHistory(hashes)) return FALSE; } pView->MapLineToLogIndex(); pView->UpdateInfo(); if (m_lLine > 0) pView->GotoLine(m_lLine); SetPathName(m_CurrentFileName, FALSE); } return TRUE; }
bool CloneCommand::Execute() { CTGitPath cloneDirectory; if (!parser.HasKey(_T("hasurlhandler"))) { if (orgCmdLinePath.IsEmpty()) { cloneDirectory.SetFromWin(sOrigCWD, true); DWORD len = ::GetTempPath(0, NULL); std::unique_ptr<TCHAR[]> tszPath(new TCHAR[len]); ::GetTempPath(len, tszPath.get()); if (_tcsncicmp(cloneDirectory.GetWinPath(), tszPath.get(), len-2 /* \\ and \0 */) == 0) { // if the current directory is set to a temp directory, // we don't use that but leave it empty instead. cloneDirectory.Reset(); } } else cloneDirectory = orgCmdLinePath; } CCloneDlg dlg; dlg.m_Directory = cloneDirectory.GetWinPathString(); if (parser.HasKey(_T("url"))) dlg.m_URL = parser.GetVal(_T("url")); if (parser.HasKey(_T("exactpath"))) dlg.m_bExactPath = TRUE; if(dlg.DoModal()==IDOK) { CString recursiveStr; if(dlg.m_bRecursive) recursiveStr = _T("--recursive"); else recursiveStr = _T(""); CString bareStr; if(dlg.m_bBare) bareStr = _T("--bare"); else bareStr = _T(""); CString nocheckoutStr; if (dlg.m_bNoCheckout) nocheckoutStr = _T("--no-checkout"); CString branchStr; if (dlg.m_bBranch) branchStr = _T("--branch ") + dlg.m_strBranch; CString originStr; if (dlg.m_bOrigin) originStr = _T("--origin ") + dlg.m_strOrigin; if(dlg.m_bAutoloadPuttyKeyFile) { CAppUtils::LaunchPAgent(&dlg.m_strPuttyKeyFile); } CAppUtils::RemoveTrailSlash(dlg.m_Directory); if (!dlg.m_bSVN) CAppUtils::RemoveTrailSlash(dlg.m_URL); CString dir=dlg.m_Directory; CString url=dlg.m_URL; // is this a windows format UNC path, ie starts with \\? if (url.Find(_T("\\\\")) == 0) { // yes, change all \ to / // this should not be necessary but msysgit does not support the use \ here yet int atSign = url.Find(_T('@')); if (atSign > 0) { CString path = url.Mid(atSign); path.Replace(_T('\\'), _T('/')); url = url.Mid(0, atSign) + path; } else url.Replace( _T('\\'), _T('/')); } CString depth; if (dlg.m_bDepth) { depth.Format(_T(" --depth %d"),dlg.m_nDepth); } g_Git.m_CurrentDir = GetExistingDirectoryForClone(dlg.m_Directory); CString cmd; CString progressarg; int ver = CAppUtils::GetMsysgitVersion(); if(ver >= 0x01070002) //above 1.7.0.2 progressarg = _T("--progress"); cmd.Format(_T("git.exe clone %s %s %s %s %s %s -v %s \"%s\" \"%s\""), nocheckoutStr, recursiveStr, bareStr, branchStr, originStr, progressarg, depth, url, dir); // Handle Git SVN-clone if(dlg.m_bSVN) { //g_Git.m_CurrentDir=dlg.m_Directory; cmd.Format(_T("git.exe svn clone \"%s\" \"%s\""), url,dlg.m_Directory); if(dlg.m_bSVNTrunk) cmd+=_T(" -T ")+dlg.m_strSVNTrunk; if(dlg.m_bSVNBranch) cmd+=_T(" -b ")+dlg.m_strSVNBranchs; if(dlg.m_bSVNTags) cmd+=_T(" -t ")+dlg.m_strSVNTags; if(dlg.m_bSVNFrom) { CString str; str.Format(_T("%d:HEAD"),dlg.m_nSVNFrom); cmd+=_T(" -r ")+str; } if(dlg.m_bSVNUserName) { cmd+= _T(" --username "); cmd+=dlg.m_strUserName; } } else { if (g_Git.UsingLibGit2(CGit::GIT_CMD_CLONE)) { CGitProgressDlg GitDlg; CTGitPathList list; g_Git.m_CurrentDir = dir; list.AddPath(CTGitPath(dir)); GitDlg.SetCommand(CGitProgressList::GitProgress_Clone); GitDlg.SetUrl(url); GitDlg.SetPathList(list); GitDlg.SetIsBare(!!dlg.m_bBare); GitDlg.SetRefSpec(dlg.m_bBranch ? dlg.m_strBranch : CString()); GitDlg.SetRemote(dlg.m_bOrigin ? dlg.m_strOrigin : CString()); GitDlg.SetNoCheckout(!!dlg.m_bNoCheckout); GitDlg.DoModal(); return !GitDlg.DidErrorsOccur(); } } CProgressDlg progress; progress.m_GitCmd=cmd; progress.m_PostCmdList.Add(CString(MAKEINTRESOURCE(IDS_MENULOG))); progress.m_PostCmdList.Add(CString(MAKEINTRESOURCE(IDS_STATUSLIST_CONTEXT_EXPLORE))); INT_PTR ret = progress.DoModal(); if (dlg.m_bSVN) ::DeleteFile(g_Git.m_CurrentDir + _T("\\sys$command")); if( progress.m_GitStatus == 0) { if(dlg.m_bAutoloadPuttyKeyFile) { g_Git.m_CurrentDir = dlg.m_Directory; SetCurrentDirectory(g_Git.m_CurrentDir); if(g_Git.SetConfigValue(_T("remote.origin.puttykeyfile"), dlg.m_strPuttyKeyFile, CONFIG_LOCAL, CP_UTF8)) { CMessageBox::Show(NULL,_T("Fail set config remote.origin.puttykeyfile"),_T("TortoiseGit"),MB_OK|MB_ICONERROR); return FALSE; } } if (ret == IDC_PROGRESS_BUTTON1) { CString cmd = _T("/command:log"); cmd += _T(" /path:\"") + dlg.m_Directory + _T("\""); CAppUtils::RunTortoiseGitProc(cmd); return TRUE; } if (ret == IDC_PROGRESS_BUTTON1 + 1) { ShellExecute(nullptr, _T("explore"), dlg.m_Directory, nullptr, nullptr, SW_SHOW); return TRUE; } } if(ret == IDOK) return TRUE; } return FALSE; }
bool PasteMoveCommand::Execute() { CString sDroppath = parser.GetVal(_T("droptarget")); CTGitPath dropPath(sDroppath); if (dropPath.IsAdminDir()) return FALSE; if(!dropPath.HasAdminDir(&g_Git.m_CurrentDir)) return FALSE; GitStatus status; unsigned long count = 0; orgPathList.RemoveAdminPaths(); CString sNewName; CSysProgressDlg progress; progress.SetTitle(IDS_PROC_MOVING); progress.SetAnimation(IDR_MOVEANI); progress.SetTime(true); progress.ShowModeless(CWnd::FromHandle(hwndExplorer)); for (int nPath = 0; nPath < orgPathList.GetCount(); ++nPath) { CTGitPath destPath; if (sNewName.IsEmpty()) destPath = CTGitPath(sDroppath+_T("\\")+orgPathList[nPath].GetFileOrDirectoryName()); else destPath = CTGitPath(sDroppath+_T("\\")+sNewName); if (destPath.Exists()) { CString name = orgPathList[nPath].GetFileOrDirectoryName(); if (!sNewName.IsEmpty()) name = sNewName; progress.Stop(); CRenameDlg dlg; dlg.m_name = name; dlg.m_windowtitle.Format(IDS_PROC_NEWNAMEMOVE, (LPCTSTR)name); if (dlg.DoModal() != IDOK) { return FALSE; } destPath.SetFromWin(sDroppath+_T("\\")+dlg.m_name); } CString top; top.Empty(); orgPathList[nPath].HasAdminDir(&top); git_wc_status_kind s = status.GetAllStatus(orgPathList[nPath]); if ((s == git_wc_status_none)||(s == git_wc_status_unversioned)||(s == git_wc_status_ignored)||top != g_Git.m_CurrentDir) { // source file is unversioned: move the file to the target, then add it MoveFile(orgPathList[nPath].GetWinPath(), destPath.GetWinPath()); CString cmd,output; cmd.Format(_T("git.exe add -- \"%s\""),destPath.GetWinPath()); if (g_Git.Run(cmd, &output, CP_UTF8)) //if (!Git.Add(CTGitorgPathList(destPath), &props, Git_depth_infinity, true, false, true)) { TRACE(_T("%s\n"), output); CMessageBox::Show(hwndExplorer, output, _T("TortoiseGit"), MB_ICONERROR); return FALSE; //get out of here } CShellUpdater::Instance().AddPathForUpdate(destPath); } else { CString cmd,output; cmd.Format(_T("git.exe mv \"%s\" \"%s\""),orgPathList[nPath].GetGitPathString(),destPath.GetGitPathString()); if (g_Git.Run(cmd, &output, CP_UTF8)) //if (!Git.Move(CTGitorgPathList(orgPathList[nPath]), destPath, FALSE)) { #if 0 if (Git.Err && (Git.Err->apr_err == Git_ERR_UNVERSIONED_RESOURCE || Git.Err->apr_err == Git_ERR_CLIENT_MODIFIED)) { // file/folder seems to have local modifications. Ask the user if // a force is requested. CString temp = Git.GetLastErrorMessage(); CString sQuestion(MAKEINTRESOURCE(IDS_PROC_FORCEMOVE)); temp += _T("\n") + sQuestion; if (CMessageBox::Show(hwndExplorer, temp, _T("TortoiseGit"), MB_YESNO)==IDYES) { if (!Git.Move(CTGitPathList(pathList[nPath]), destPath, TRUE)) { CMessageBox::Show(hwndExplorer, Git.GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR); return FALSE; //get out of here } CShellUpdater::Instance().AddPathForUpdate(destPath); } } else #endif { TRACE(_T("%s\n"), (LPCTSTR)output); CMessageBox::Show(hwndExplorer, output, _T("TortoiseGit"), MB_ICONERROR); return FALSE; //get out of here } } else CShellUpdater::Instance().AddPathForUpdate(destPath); } ++count; if (progress.IsValid()) { progress.FormatPathLine(1, IDS_PROC_MOVINGPROG, orgPathList[nPath].GetWinPath()); progress.FormatPathLine(2, IDS_PROC_CPYMVPROG2, destPath.GetWinPath()); progress.SetProgress(count, orgPathList.GetCount()); } if ((progress.IsValid())&&(progress.HasUserCancelled())) { CMessageBox::Show(hwndExplorer, IDS_USERCANCELLED, IDS_APPNAME, MB_ICONINFORMATION); return FALSE; } } return true; }
BOOL CTortoiseGitBlameDoc::OnOpenDocument(LPCTSTR lpszPathName,CString Rev) { if(Rev.IsEmpty()) Rev = _T("HEAD"); // enable blame for files which do not exist in current working tree if (!PathFileExists(lpszPathName) && Rev != _T("HEAD")) { if (!CDocument::OnOpenDocument(GetTempFile())) return FALSE; } else { if (!CDocument::OnOpenDocument(lpszPathName)) return FALSE; } m_CurrentFileName = lpszPathName; m_Rev=Rev; // (SDI documents will reuse this document) if(!g_Git.CheckMsysGitDir()) { CCommonAppUtils::RunTortoiseGitProc(_T(" /command:settings")); return FALSE; } GitAdminDir admindir; CString topdir; if(!admindir.HasAdminDir(m_CurrentFileName, &topdir)) { CString temp; temp.Format(IDS_CANNOTBLAMENOGIT, CString(m_CurrentFileName)); CMessageBox::Show(NULL, temp, _T("TortoiseGitBlame"), MB_OK); return FALSE; } else { GitAdminDir lastAdminDir; CString oldTopDir; if (topdir != g_Git.m_CurrentDir && CTGitPath(g_Git.m_CurrentDir).HasAdminDir(&oldTopDir) && oldTopDir != topdir) { CString sMsg; sMsg.Format(IDS_ERR_DIFFENERTPREPO, oldTopDir, topdir); MessageBox(NULL, sMsg, _T("TortoiseGitBlame"), MB_OK | MB_ICONERROR); return FALSE; } m_IsGitFile=TRUE; sOrigCWD = g_Git.m_CurrentDir = topdir; CString PathName = m_CurrentFileName; if(topdir[topdir.GetLength()-1] == _T('\\') || topdir[topdir.GetLength()-1] == _T('/')) PathName=PathName.Right(PathName.GetLength()-g_Git.m_CurrentDir.GetLength()); else PathName=PathName.Right(PathName.GetLength()-g_Git.m_CurrentDir.GetLength()-1); CTGitPath path; path.SetFromWin(PathName); if(!g_Git.m_CurrentDir.IsEmpty()) SetCurrentDirectory(g_Git.m_CurrentDir); try { // make sure all config files are read in order to check that none contains an error g_Git.GetConfigValue(_T("doesnot.exist")); } catch (char * libgiterr) { MessageBox(NULL, CString(libgiterr), _T("TortoiseGitBlame"), MB_ICONERROR); return FALSE; } CString cmd; cmd.Format(_T("git.exe blame -s -l %s -- \"%s\""),Rev,path.GetGitPathString()); m_BlameData.clear(); BYTE_VECTOR err; if(g_Git.Run(cmd, &m_BlameData, &err)) { CString str; if (!m_BlameData.empty()) g_Git.StringAppend(&str, &m_BlameData[0], CP_UTF8); if (!err.empty()) g_Git.StringAppend(&str, &err[0], CP_UTF8); MessageBox(NULL, CString(MAKEINTRESOURCE(IDS_BLAMEERROR)) + _T("\n\n") + str, _T("TortoiseGitBlame"), MB_OK); return FALSE; } if(!m_TempFileName.IsEmpty()) { ::DeleteFile(m_TempFileName); m_TempFileName.Empty(); } m_TempFileName=GetTempFile(); cmd.Format(_T("git.exe cat-file blob %s:\"%s\""),Rev,path.GetGitPathString()); if(g_Git.RunLogFile(cmd, m_TempFileName)) { CString str; str.Format(IDS_CHECKOUTFAILED, path.GetGitPathString()); MessageBox(NULL, CString(MAKEINTRESOURCE(IDS_BLAMEERROR)) + _T("\n\n") + str, _T("TortoiseGitBlame"), MB_OK); return FALSE; } m_GitPath = path; if (GetMainFrame()->m_wndOutput.LoadHistory(path.GetGitPathString(), m_Rev, (theApp.GetInt(_T("FollowRenames"), 0) == 1))) return FALSE; CTortoiseGitBlameView *pView=DYNAMIC_DOWNCAST(CTortoiseGitBlameView,GetMainFrame()->GetActiveView()); if(pView == NULL) { CWnd* pWnd = GetMainFrame()->GetDescendantWindow(AFX_IDW_PANE_FIRST, TRUE); if (pWnd != NULL && pWnd->IsKindOf(RUNTIME_CLASS(CTortoiseGitBlameView))) { pView = (CTortoiseGitBlameView*)pWnd; } else { return FALSE; } } pView->UpdateInfo(); } return TRUE; }
void CDirectoryWatcher::WorkerThread() { DWORD numBytes; CDirWatchInfo * pdi = NULL; LPOVERLAPPED lpOverlapped; WCHAR buf[READ_DIR_CHANGE_BUFFER_SIZE] = {0}; WCHAR * pFound = NULL; CTGitPath path; while (m_bRunning) { if (watchedPaths.GetCount()) { if (!GetQueuedCompletionStatus(m_hCompPort, &numBytes, (PULONG_PTR) &pdi, &lpOverlapped, INFINITE)) { // Error retrieving changes // Clear the list of watched objects and recreate that list if (!m_bRunning) return; { AutoLocker lock(m_critSec); ClearInfoMap(); } DWORD lasterr = GetLastError(); if ((m_hCompPort != INVALID_HANDLE_VALUE)&&(lasterr!=ERROR_SUCCESS)&&(lasterr!=ERROR_INVALID_HANDLE)) { CloseHandle(m_hCompPort); m_hCompPort = INVALID_HANDLE_VALUE; } // Since we pass m_hCompPort to CreateIoCompletionPort, we // have to set this to NULL to have that API create a new // handle. m_hCompPort = NULL; for (int i=0; i<watchedPaths.GetCount(); ++i) { CTGitPath watchedPath = watchedPaths[i]; HANDLE hDir = CreateFile(watchedPath.GetWinPath(), FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, //security attributes OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | //required privileges: SE_BACKUP_NAME and SE_RESTORE_NAME. FILE_FLAG_OVERLAPPED, NULL); if (hDir == INVALID_HANDLE_VALUE) { // this could happen if a watched folder has been removed/renamed ATLTRACE(_T("CDirectoryWatcher: CreateFile failed. Can't watch directory %s\n"), watchedPaths[i].GetWinPath()); CloseHandle(m_hCompPort); m_hCompPort = INVALID_HANDLE_VALUE; AutoLocker lock(m_critSec); watchedPaths.RemovePath(watchedPath); i--; if (i<0) i=0; break; } DEV_BROADCAST_HANDLE NotificationFilter; SecureZeroMemory(&NotificationFilter, sizeof(NotificationFilter)); NotificationFilter.dbch_size = sizeof(DEV_BROADCAST_HANDLE); NotificationFilter.dbch_devicetype = DBT_DEVTYP_HANDLE; NotificationFilter.dbch_handle = hDir; NotificationFilter.dbch_hdevnotify = RegisterDeviceNotification(hWnd, &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE); CDirWatchInfo * pDirInfo = new CDirWatchInfo(hDir, watchedPath); pDirInfo->m_hDevNotify = NotificationFilter.dbch_hdevnotify; m_hCompPort = CreateIoCompletionPort(hDir, m_hCompPort, (ULONG_PTR)pDirInfo, 0); if (m_hCompPort == NULL) { ATLTRACE(_T("CDirectoryWatcher: CreateIoCompletionPort failed. Can't watch directory %s\n"), watchedPath.GetWinPath()); AutoLocker lock(m_critSec); ClearInfoMap(); delete pDirInfo; pDirInfo = NULL; watchedPaths.RemovePath(watchedPath); i--; if (i<0) i=0; break; } if (!ReadDirectoryChangesW(pDirInfo->m_hDir, pDirInfo->m_Buffer, READ_DIR_CHANGE_BUFFER_SIZE, TRUE, FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE, &numBytes,// not used &pDirInfo->m_Overlapped, NULL)) //no completion routine! { ATLTRACE(_T("CDirectoryWatcher: ReadDirectoryChangesW failed. Can't watch directory %s\n"), watchedPath.GetWinPath()); AutoLocker lock(m_critSec); ClearInfoMap(); delete pDirInfo; pDirInfo = NULL; watchedPaths.RemovePath(watchedPath); i--; if (i<0) i=0; break; } AutoLocker lock(m_critSec); watchInfoMap[pDirInfo->m_hDir] = pDirInfo; ATLTRACE(_T("watching path %s\n"), pDirInfo->m_DirName.GetWinPath()); } } else { if (!m_bRunning) return; // NOTE: the longer this code takes to execute until ReadDirectoryChangesW // is called again, the higher the chance that we miss some // changes in the file system! if (pdi) { if (numBytes == 0) { goto continuewatching; } PFILE_NOTIFY_INFORMATION pnotify = (PFILE_NOTIFY_INFORMATION)pdi->m_Buffer; if ((ULONG_PTR)pnotify - (ULONG_PTR)pdi->m_Buffer > READ_DIR_CHANGE_BUFFER_SIZE) goto continuewatching; DWORD nOffset = pnotify->NextEntryOffset; do { nOffset = pnotify->NextEntryOffset; if (pnotify->FileNameLength >= (READ_DIR_CHANGE_BUFFER_SIZE*sizeof(TCHAR))) continue; SecureZeroMemory(buf, READ_DIR_CHANGE_BUFFER_SIZE*sizeof(TCHAR)); _tcsncpy_s(buf, READ_DIR_CHANGE_BUFFER_SIZE, pdi->m_DirPath, READ_DIR_CHANGE_BUFFER_SIZE); errno_t err = _tcsncat_s(buf+pdi->m_DirPath.GetLength(), READ_DIR_CHANGE_BUFFER_SIZE-pdi->m_DirPath.GetLength(), pnotify->FileName, _TRUNCATE); if (err == STRUNCATE) { pnotify = (PFILE_NOTIFY_INFORMATION)((LPBYTE)pnotify + nOffset); continue; } buf[(pnotify->FileNameLength/sizeof(TCHAR))+pdi->m_DirPath.GetLength()] = 0; pnotify = (PFILE_NOTIFY_INFORMATION)((LPBYTE)pnotify + nOffset); if (m_FolderCrawler) { if ((pFound = wcsstr(buf, L"\\tmp"))!=NULL) { pFound += 4; if (((*pFound)=='\\')||((*pFound)=='\0')) { if ((ULONG_PTR)pnotify - (ULONG_PTR)pdi->m_Buffer > READ_DIR_CHANGE_BUFFER_SIZE) break; continue; } } if ((pFound = wcsstr(buf, L":\\RECYCLER\\"))!=NULL) { if ((pFound-buf) < 5) { // a notification for the recycle bin - ignore it if ((ULONG_PTR)pnotify - (ULONG_PTR)pdi->m_Buffer > READ_DIR_CHANGE_BUFFER_SIZE) break; continue; } } if ((pFound = wcsstr(buf, L":\\$Recycle.Bin\\"))!=NULL) { if ((pFound-buf) < 5) { // a notification for the recycle bin - ignore it if ((ULONG_PTR)pnotify - (ULONG_PTR)pdi->m_Buffer > READ_DIR_CHANGE_BUFFER_SIZE) break; continue; } } if ((pFound = wcsstr(buf, L".tmp"))!=NULL) { // assume files with a .tmp extension are not versioned and interesting, // so ignore them. if ((ULONG_PTR)pnotify - (ULONG_PTR)pdi->m_Buffer > READ_DIR_CHANGE_BUFFER_SIZE) break; continue; } bool isIndex = false; if ((pFound = wcsstr(buf, L".git"))!=NULL) { // omit repository data change except .git/index.lock- or .git/HEAD.lock-files if ((ULONG_PTR)pnotify - (ULONG_PTR)pdi->m_Buffer > READ_DIR_CHANGE_BUFFER_SIZE) break; if ((wcsstr(pFound, L"index.lock") != NULL && wcsstr(pFound, L"HEAD.lock") != NULL) && pnotify->Action == FILE_ACTION_ADDED) { m_FolderCrawler->BlockPath(CTGitPath(buf).GetContainingDirectory().GetContainingDirectory()); // optimize here, and use general BlockPath with priorities continue; } else if ((wcsstr(pFound, L"index.lock") != NULL && wcsstr(pFound, L"HEAD.lock") != NULL) && pnotify->Action == FILE_ACTION_REMOVED) { isIndex = true; m_FolderCrawler->BlockPath(CTGitPath(buf).GetContainingDirectory().GetContainingDirectory(), 1); } else { continue; } } path.SetFromWin(buf); if(!path.HasAdminDir() && !isIndex) continue; ATLTRACE(_T("change notification: %s\n"), buf); m_FolderCrawler->AddPathForUpdate(CTGitPath(buf)); } if ((ULONG_PTR)pnotify - (ULONG_PTR)pdi->m_Buffer > READ_DIR_CHANGE_BUFFER_SIZE) break; } while (nOffset); continuewatching: SecureZeroMemory(pdi->m_Buffer, sizeof(pdi->m_Buffer)); SecureZeroMemory(&pdi->m_Overlapped, sizeof(OVERLAPPED)); if (!ReadDirectoryChangesW(pdi->m_hDir, pdi->m_Buffer, READ_DIR_CHANGE_BUFFER_SIZE, TRUE, FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE, &numBytes,// not used &pdi->m_Overlapped, NULL)) //no completion routine! { // Since the call to ReadDirectoryChangesW failed, just // wait a while. We don't want to have this thread // running using 100% CPU if something goes completely // wrong. Sleep(200); } } } } // if (watchedPaths.GetCount()) else Sleep(200); } // while (m_bRunning) }
DWORD WINAPI CommandThread(LPVOID lpvParam) { ATLTRACE("CommandThread started\n"); DWORD cbBytesRead; BOOL fSuccess; CAutoFile hPipe; // The thread's parameter is a handle to a pipe instance. hPipe = lpvParam; while (bRun) { // Read client requests from the pipe. TGITCacheCommand command; 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); ATLTRACE("Command thread exited\n"); return 1; } switch (command.command) { case TGITCACHECOMMAND_END: FlushFileBuffers(hPipe); DisconnectNamedPipe(hPipe); ATLTRACE("Command thread exited\n"); return 0; case TGITCACHECOMMAND_CRAWL: { CTGitPath changedpath; changedpath.SetFromWin(command.path, true); // remove the path from our cache - that will 'invalidate' it. { CAutoWriteLock writeLock(CGitStatusCache::Instance().GetGuard()); CGitStatusCache::Instance().RemoveCacheForPath(changedpath); } CGitStatusCache::Instance().AddFolderForCrawling(changedpath.GetDirectory()); } break; case TGITCACHECOMMAND_REFRESHALL: { CAutoWriteLock writeLock(CGitStatusCache::Instance().GetGuard()); CGitStatusCache::Instance().Refresh(); } break; case TGITCACHECOMMAND_RELEASE: { CTGitPath changedpath; changedpath.SetFromWin(command.path, true); ATLTRACE(_T("release handle for path %s\n"), changedpath.GetWinPath()); CAutoWriteLock writeLock(CGitStatusCache::Instance().GetGuard()); CGitStatusCache::Instance().CloseWatcherHandles(changedpath); CGitStatusCache::Instance().RemoveCacheForPath(changedpath); } break; case TGITCACHECOMMAND_BLOCK: { CTGitPath changedpath; changedpath.SetFromWin(command.path); ATLTRACE(_T("block path %s\n"), changedpath.GetWinPath()); CGitStatusCache::Instance().BlockPath(changedpath); } break; case TGITCACHECOMMAND_UNBLOCK: { CTGitPath changedpath; changedpath.SetFromWin(command.path); ATLTRACE(_T("block path %s\n"), changedpath.GetWinPath()); CGitStatusCache::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); ATLTRACE("Command thread exited\n"); return 0; }
void CShellUpdater::UpdateShell() { // Tell the shell extension to purge its cache CTraceToOutputDebugString::Instance()(__FUNCTION__ ": Setting cache invalidation event %I64u\n", GetTickCount64()); SetEvent(m_hInvalidationEvent); // We use the SVN 'notify' call-back to add items to the list // Because this might call-back more than once per file (for example, when committing) // it's possible that there may be duplicates in the list. // There's no point asking the shell to do more than it has to, so we remove the duplicates before // passing the list on m_pathsForUpdating.RemoveDuplicates(); // if we use the external cache, we tell the cache directly that something // has changed, without the detour via the shell. CAutoFile hPipe = CreateFile( GetCacheCommandPipeName(), // pipe name GENERIC_READ | // read and write access GENERIC_WRITE, 0, // no sharing nullptr, // default security attributes OPEN_EXISTING, // opens existing pipe FILE_FLAG_OVERLAPPED, // default attributes nullptr); // no template file if (!hPipe) return; // The pipe connected; change to message-read mode. DWORD dwMode = PIPE_READMODE_MESSAGE; if (!SetNamedPipeHandleState( hPipe, // pipe handle &dwMode, // new pipe mode nullptr, // don't set maximum bytes nullptr)) // don't set maximum time { CTraceToOutputDebugString::Instance()(__FUNCTION__ ": SetNamedPipeHandleState failed"); return; } CTGitPath path; for (int nPath = 0; nPath < m_pathsForUpdating.GetCount(); ++nPath) { path.SetFromWin(g_Git.CombinePath(m_pathsForUpdating[nPath])); CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": Cache Item Update for %s (%I64u)\n", (LPCTSTR)path.GetWinPathString(), GetTickCount64()); if (!path.IsDirectory()) { // send notifications to the shell for changed files - folders are updated by the cache itself. SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH | SHCNF_FLUSHNOWAIT, path.GetWinPath(), nullptr); } DWORD cbWritten; TGITCacheCommand cmd; cmd.command = TGITCACHECOMMAND_CRAWL; wcsncpy_s(cmd.path, path.GetDirectory().GetWinPath(), _countof(cmd.path) - 1); BOOL fSuccess = WriteFile( hPipe, // handle to pipe &cmd, // buffer to write from sizeof(cmd), // number of bytes to write &cbWritten, // number of bytes written nullptr); // not overlapped I/O if (!fSuccess || sizeof(cmd) != cbWritten) { DisconnectNamedPipe(hPipe); return; } } // now tell the cache we don't need it's command thread anymore DWORD cbWritten; TGITCacheCommand cmd; cmd.command = TGITCACHECOMMAND_END; WriteFile( hPipe, // handle to pipe &cmd, // buffer to write from sizeof(cmd), // number of bytes to write &cbWritten, // number of bytes written nullptr); // not overlapped I/O DisconnectNamedPipe(hPipe); }
void CPatchListCtrl::OnContextMenu(CWnd* /*pWnd*/, CPoint point) { int selected=this->GetSelectedCount(); int index=0; POSITION pos=this->GetFirstSelectedItemPosition(); index=this->GetNextSelectedItem(pos); CIconMenu popup; if (popup.CreatePopupMenu()) { if(selected == 1) { if( m_ContextMenuMask&GetMenuMask(MENU_VIEWPATCH)) popup.AppendMenuIcon(MENU_VIEWPATCH, IDS_MENU_VIEWPATCH, 0); if( m_ContextMenuMask&GetMenuMask(MENU_VIEWWITHMERGE)) popup.AppendMenuIcon(MENU_VIEWWITHMERGE, IDS_MENU_VIEWWITHMERGE, 0); popup.SetDefaultItem(MENU_VIEWPATCH, FALSE); } if(selected >= 1) { if( m_ContextMenuMask&GetMenuMask(MENU_SENDMAIL)) popup.AppendMenuIcon(MENU_SENDMAIL, IDS_MENU_SENDMAIL, IDI_MENUSENDMAIL); if( m_ContextMenuMask&GetMenuMask(MENU_APPLY)) popup.AppendMenuIcon(MENU_APPLY, IDS_MENU_APPLY, 0); } int cmd = popup.TrackPopupMenu(TPM_RETURNCMD | TPM_LEFTALIGN | TPM_NONOTIFY, point.x, point.y, this, 0); switch (cmd) { case MENU_VIEWPATCH: { CString path=GetItemText(index,0); CTGitPath gitpath; gitpath.SetFromWin(path); CAppUtils::StartUnifiedDiffViewer(path,gitpath.GetFilename()); break; } case MENU_VIEWWITHMERGE: { CString path=GetItemText(index,0); CTGitPath gitpath; gitpath.SetFromWin(path); CTGitPath dir; dir.SetFromGit(g_Git.m_CurrentDir); CAppUtils::StartExtPatch(gitpath,dir); break; } case MENU_SENDMAIL: { LaunchProc(_T("sendmail")); break; } case MENU_APPLY: { LaunchProc(_T("importpatch")); break; } default: break; } } }
void CShellUpdater::UpdateShell() { // Tell the shell extension to purge its cache ATLTRACE("Setting cache invalidation event %d\n", GetTickCount()); SetEvent(m_hInvalidationEvent); // We use the SVN 'notify' call-back to add items to the list // Because this might call-back more than once per file (for example, when committing) // it's possible that there may be duplicates in the list. // There's no point asking the shell to do more than it has to, so we remove the duplicates before // passing the list on m_pathsForUpdating.RemoveDuplicates(); // if we use the external cache, we tell the cache directly that something // has changed, without the detour via the shell. HANDLE hPipe = CreateFile( GetCacheCommandPipeName(), // pipe name GENERIC_READ | // read and write access GENERIC_WRITE, 0, // no sharing NULL, // default security attributes OPEN_EXISTING, // opens existing pipe FILE_FLAG_OVERLAPPED, // default attributes NULL); // no template file if (hPipe != INVALID_HANDLE_VALUE) { // The pipe connected; change to message-read mode. DWORD dwMode; dwMode = PIPE_READMODE_MESSAGE; if(SetNamedPipeHandleState( hPipe, // pipe handle &dwMode, // new pipe mode NULL, // don't set maximum bytes NULL)) // don't set maximum time { CTGitPath path; for(int nPath = 0; nPath < m_pathsForUpdating.GetCount(); nPath++) { path.SetFromWin(g_Git.m_CurrentDir+_T("\\")+m_pathsForUpdating[nPath].GetWinPathString()); ATLTRACE(_T("Cache Item Update for %s (%d)\n"), path.GetWinPathString(), GetTickCount()); if (!path.IsDirectory()) { // send notifications to the shell for changed files - folders are updated by the cache itself. SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH | SHCNF_FLUSHNOWAIT, path.GetWinPath(), NULL); } DWORD cbWritten; TSVNCacheCommand cmd; cmd.command = TSVNCACHECOMMAND_CRAWL; wcsncpy_s(cmd.path, MAX_PATH+1, path.GetDirectory().GetWinPath(), MAX_PATH); BOOL fSuccess = WriteFile( hPipe, // 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) { DisconnectNamedPipe(hPipe); CloseHandle(hPipe); hPipe = INVALID_HANDLE_VALUE; break; } } if (hPipe != INVALID_HANDLE_VALUE) { // now tell the cache we don't need it's command thread anymore DWORD cbWritten; TSVNCacheCommand cmd; cmd.command = TSVNCACHECOMMAND_END; WriteFile( hPipe, // 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 DisconnectNamedPipe(hPipe); CloseHandle(hPipe); hPipe = INVALID_HANDLE_VALUE; } } else { ATLTRACE("SetNamedPipeHandleState failed"); CloseHandle(hPipe); } } }
UINT CImportPatchDlg::PatchThread() { CTGitPath path; path.SetFromWin(g_Git.m_CurrentDir); int i=0; UpdateOkCancelText(); for(i=m_CurrentItem;i<m_cList.GetItemCount();i++) { if (m_pTaskbarList) { m_pTaskbarList->SetProgressState(m_hWnd, TBPF_NORMAL); m_pTaskbarList->SetProgressValue(m_hWnd, i, m_cList.GetItemCount()); } m_cList.SetItemData(i, CPatchListCtrl::STATUS_APPLYING|m_cList.GetItemData(i)); CRect rect; this->m_cList.GetItemRect(i,&rect,LVIR_BOUNDS); this->m_cList.InvalidateRect(rect); if(m_bExitThread) break; if(m_cList.GetCheck(i)) { CString cmd; while(path.HasRebaseApply()) { if (m_pTaskbarList) m_pTaskbarList->SetProgressState(m_hWnd, TBPF_ERROR); int ret = CMessageBox::Show(NULL, _T("<ct=0x0000FF>previous rebase directory rebase-apply still exists but mbox given</ct>\n\n Do you want to"), _T("TortoiseGit"), 1,IDI_ERROR ,_T("&Abort"), _T("&Skip"),_T("&Resolved")); switch(ret) { case 1: cmd = _T("git.exe am --abort"); break; case 2: cmd = _T("git.exe am --skip"); i++; break; case 3: cmd = _T("git.exe am --resolved"); break; default: cmd.Empty(); } if(cmd.IsEmpty()) { m_bExitThread = TRUE; break; } this->AddLogString(cmd); CString output; if(g_Git.Run(cmd, &output, CP_ACP)) { this->AddLogString(output); this->AddLogString(_T("Fail")); } else { this->AddLogString(_T("Done")); } } if(m_bExitThread) break; cmd = _T("git.exe am "); if(this->m_bAddSignedOffBy) cmd += _T("--signoff "); if(this->m_b3Way) cmd += _T("--3way "); if(this->m_bIgnoreSpace) cmd += _T("--ignore-space-change "); if(this->m_bKeepCR) cmd += _T("--keep-cr "); cmd += _T("\""); cmd += m_cList.GetItemText(i,0); cmd += _T("\""); this->AddLogString(cmd); CString output; if(g_Git.Run(cmd,&output,CP_ACP)) { //keep STATUS_APPLYING to let user retry failed patch m_cList.SetItemData(i, CPatchListCtrl::STATUS_APPLY_FAIL|CPatchListCtrl::STATUS_APPLYING); this->AddLogString(output); this->AddLogString(_T("Fail")); if (m_pTaskbarList) m_pTaskbarList->SetProgressState(m_hWnd, TBPF_ERROR); break; } else { m_cList.SetItemData(i, CPatchListCtrl::STATUS_APPLY_SUCCESS); this->AddLogString(_T("Success")); } } else { AddLogString(CString(_T("Skip Patch: "))+m_cList.GetItemText(i,0)); m_cList.SetItemData(i, CPatchListCtrl::STATUS_APPLY_SKIP); } m_cList.SetItemData(m_CurrentItem, (~CPatchListCtrl::STATUS_APPLYING)&m_cList.GetItemData(i)); m_CurrentItem++; this->m_cList.GetItemRect(i,&rect,LVIR_BOUNDS); this->m_cList.InvalidateRect(rect); UpdateOkCancelText(); } //in case am fail, need refresh finial item status CRect rect; this->m_cList.GetItemRect(i,&rect,LVIR_BOUNDS); this->m_cList.InvalidateRect(rect); this->m_cList.GetItemRect(m_CurrentItem,&rect,LVIR_BOUNDS); this->m_cList.InvalidateRect(rect); if (m_pTaskbarList) { m_pTaskbarList->SetProgressValue(m_hWnd, m_CurrentItem, m_cList.GetItemCount()); if (m_bExitThread && m_CurrentItem != m_cList.GetItemCount()) m_pTaskbarList->SetProgressState(m_hWnd, TBPF_PAUSED); else if (!m_bExitThread && m_CurrentItem == m_cList.GetItemCount()) m_pTaskbarList->SetProgressState(m_hWnd, TBPF_NORMAL); } EnableInputCtrl(true); InterlockedExchange(&m_bThreadRunning, FALSE); UpdateOkCancelText(); return 0; }
bool DropMoveCommand::Execute() { CString droppath = parser.GetVal(_T("droptarget")); CString ProjectTop; if (!CTGitPath(droppath).HasAdminDir(&ProjectTop)) return FALSE; if (ProjectTop != g_Git.m_CurrentDir ) { CMessageBox::Show(NULL,_T("Target and source must be the same git repository"),_T("TortoiseGit"),MB_OK); return FALSE; } droppath = droppath.Right(droppath.GetLength()-ProjectTop.GetLength()-1); unsigned long count = 0; pathList.RemoveAdminPaths(); CString sNewName; if ((parser.HasKey(_T("rename")))&&(pathList.GetCount()==1)) { // ask for a new name of the source item do { CRenameDlg renDlg; renDlg.m_windowtitle.LoadString(IDS_PROC_MOVERENAME); renDlg.m_name = pathList[0].GetFileOrDirectoryName(); if (renDlg.DoModal() != IDOK) { return FALSE; } sNewName = renDlg.m_name; } while(sNewName.IsEmpty() || PathFileExists(droppath+_T("\\")+sNewName)); } CSysProgressDlg progress; if (progress.IsValid()) { progress.SetTitle(IDS_PROC_MOVING); progress.SetAnimation(IDR_MOVEANI); progress.SetTime(true); progress.ShowModeless(CWnd::FromHandle(hwndExplorer)); } for(int nPath = 0; nPath < pathList.GetCount(); nPath++) { CTGitPath destPath; if (sNewName.IsEmpty()) destPath = CTGitPath(droppath+_T("\\")+pathList[nPath].GetFileOrDirectoryName()); else destPath = CTGitPath(droppath+_T("\\")+sNewName); if (destPath.Exists()) { CString name = pathList[nPath].GetFileOrDirectoryName(); if (!sNewName.IsEmpty()) name = sNewName; progress.Stop(); CRenameDlg dlg; dlg.m_name = name; dlg.m_windowtitle.Format(IDS_PROC_NEWNAMEMOVE, (LPCTSTR)name); if (dlg.DoModal() != IDOK) { return FALSE; } destPath.SetFromWin(droppath+_T("\\")+dlg.m_name); } CString cmd,out; cmd.Format(_T("git.exe mv -- \"%s\" \"%s\""),pathList[nPath].GetGitPathString(),destPath.GetGitPathString()); if(g_Git.Run(cmd,&out,CP_ACP)) { if (CMessageBox::Show(hwndExplorer, out, _T("TortoiseGit"), MB_YESNO)==IDYES) { #if 0 if (!svn.Move(CTSVNPathList(pathList[nPath]), destPath, TRUE)) { CMessageBox::Show(hwndExplorer, svn.GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR); return FALSE; //get out of here } CShellUpdater::Instance().AddPathForUpdate(destPath); #endif } else { //TRACE(_T("%s\n"), (LPCTSTR)svn.GetLastErrorMessage()); CMessageBox::Show(hwndExplorer, _T("Cancel"), _T("TortoiseGit"), MB_ICONERROR); return FALSE; //get out of here } } else CShellUpdater::Instance().AddPathForUpdate(destPath); count++; if (progress.IsValid()) { progress.FormatPathLine(1, IDS_PROC_MOVINGPROG, pathList[nPath].GetWinPath()); progress.FormatPathLine(2, IDS_PROC_CPYMVPROG2, destPath.GetWinPath()); progress.SetProgress(count, pathList.GetCount()); } if ((progress.IsValid())&&(progress.HasUserCancelled())) { CMessageBox::Show(hwndExplorer, IDS_SVN_USERCANCELLED, IDS_APPNAME, MB_ICONINFORMATION); return FALSE; } } return true; }
bool CloneCommand::Execute() { CTGitPath cloneDirectory; if (!parser.HasKey(_T("hasurlhandler"))) { if (orgCmdLinePath.IsEmpty()) { cloneDirectory.SetFromWin(sOrigCWD, true); DWORD len = ::GetTempPath(0, nullptr); auto tszPath = std::make_unique<TCHAR[]>(len); ::GetTempPath(len, tszPath.get()); if (_tcsncicmp(cloneDirectory.GetWinPath(), tszPath.get(), len-2 /* \\ and \0 */) == 0) { // if the current directory is set to a temp directory, // we don't use that but leave it empty instead. cloneDirectory.Reset(); } } else cloneDirectory = orgCmdLinePath; } CCloneDlg dlg; dlg.m_Directory = cloneDirectory.GetWinPathString(); if (parser.HasKey(_T("url"))) dlg.m_URL = parser.GetVal(_T("url")); if (parser.HasKey(_T("exactpath"))) dlg.m_bExactPath = TRUE; if(dlg.DoModal()==IDOK) { CString recursiveStr; if(dlg.m_bRecursive) recursiveStr = _T(" --recursive"); CString bareStr; if(dlg.m_bBare) bareStr = _T(" --bare"); CString nocheckoutStr; if (dlg.m_bNoCheckout) nocheckoutStr = _T(" --no-checkout"); CString branchStr; if (dlg.m_bBranch) branchStr = _T(" --branch ") + dlg.m_strBranch; CString originStr; if (dlg.m_bOrigin && !dlg.m_bSVN) originStr = _T(" --origin ") + dlg.m_strOrigin; if(dlg.m_bAutoloadPuttyKeyFile) { CAppUtils::LaunchPAgent(&dlg.m_strPuttyKeyFile); } CAppUtils::RemoveTrailSlash(dlg.m_Directory); if (!dlg.m_bSVN) CAppUtils::RemoveTrailSlash(dlg.m_URL); CString dir=dlg.m_Directory; CString url=dlg.m_URL; // is this a windows format UNC path, ie starts with \\? if (url.Find(_T("\\\\")) == 0) { // yes, change all \ to / // this should not be necessary but msysgit does not support the use \ here yet int atSign = url.Find(_T('@')); if (atSign > 0) { CString path = url.Mid(atSign); path.Replace(_T('\\'), _T('/')); url = url.Mid(0, atSign) + path; } else url.Replace( _T('\\'), _T('/')); } CString depth; if (dlg.m_bDepth) { depth.Format(_T(" --depth %d"),dlg.m_nDepth); } CString cmd; cmd.Format(_T("git.exe clone --progress%s%s%s%s%s -v%s \"%s\" \"%s\""), (LPCTSTR)nocheckoutStr, (LPCTSTR)recursiveStr, (LPCTSTR)bareStr, (LPCTSTR)branchStr, (LPCTSTR)originStr, (LPCTSTR)depth, (LPCTSTR)url, (LPCTSTR)dir); bool retry = false; auto postCmdCallback = [&](DWORD status, PostCmdList& postCmdList) { if (status) { postCmdList.emplace_back(IDI_REFRESH, IDS_MSGBOX_RETRY, [&]{ retry = true; }); return; } // After cloning, change current directory to the cloned directory g_Git.m_CurrentDir = dlg.m_Directory; if (dlg.m_bAutoloadPuttyKeyFile) // do this here, since it might be needed for actions performed in Log StorePuttyKey(dlg.m_Directory, dlg.m_bOrigin && !dlg.m_strOrigin.IsEmpty() ? dlg.m_strOrigin : _T("origin"), dlg.m_strPuttyKeyFile); postCmdList.emplace_back(IDI_LOG, IDS_MENULOG, [&] { CString cmd = _T("/command:log"); cmd += _T(" /path:\"") + dlg.m_Directory + _T("\""); CAppUtils::RunTortoiseGitProc(cmd); }); postCmdList.emplace_back(IDI_EXPLORER, IDS_STATUSLIST_CONTEXT_EXPLORE, [&]{ CAppUtils::ExploreTo(hWndExplorer, dlg.m_Directory); }); }; // Handle Git SVN-clone if(dlg.m_bSVN) { //g_Git.m_CurrentDir=dlg.m_Directory; cmd.Format(_T("git.exe svn clone \"%s\" \"%s\""), (LPCTSTR)url, (LPCTSTR)dlg.m_Directory); if (dlg.m_bOrigin) { CString str; if (dlg.m_strOrigin.IsEmpty()) str = _T(" --prefix \"\""); else str.Format(_T(" --prefix \"%s/\""), (LPCTSTR)dlg.m_strOrigin); cmd += str; } if(dlg.m_bSVNTrunk) cmd+=_T(" -T ")+dlg.m_strSVNTrunk; if(dlg.m_bSVNBranch) cmd+=_T(" -b ")+dlg.m_strSVNBranchs; if(dlg.m_bSVNTags) cmd+=_T(" -t ")+dlg.m_strSVNTags; if(dlg.m_bSVNFrom) { CString str; str.Format(_T("%d:HEAD"),dlg.m_nSVNFrom); cmd+=_T(" -r ")+str; } if(dlg.m_bSVNUserName) { cmd+= _T(" --username "); cmd+=dlg.m_strUserName; } } else { if (g_Git.UsingLibGit2(CGit::GIT_CMD_CLONE)) { while (true) { retry = false; CGitProgressDlg GitDlg; CTGitPathList list; g_Git.m_CurrentDir = GetExistingDirectoryForClone(dlg.m_Directory); list.AddPath(CTGitPath(dir)); CloneProgressCommand cloneProgressCommand; GitDlg.SetCommand(&cloneProgressCommand); cloneProgressCommand.m_PostCmdCallback = postCmdCallback; cloneProgressCommand.SetUrl(url); cloneProgressCommand.SetPathList(list); cloneProgressCommand.SetIsBare(dlg.m_bBare == TRUE); if (dlg.m_bBranch) cloneProgressCommand.SetRefSpec(dlg.m_strBranch); if (dlg.m_bOrigin) cloneProgressCommand.SetRemote(dlg.m_strOrigin); cloneProgressCommand.SetNoCheckout(dlg.m_bNoCheckout == TRUE); GitDlg.DoModal(); if (!retry) return !GitDlg.DidErrorsOccur(); } } } while (true) { retry = false; g_Git.m_CurrentDir = GetExistingDirectoryForClone(dlg.m_Directory); CProgressDlg progress; progress.m_GitCmd=cmd; progress.m_PostCmdCallback = postCmdCallback; INT_PTR ret = progress.DoModal(); if (!retry) return ret == IDOK; } } return FALSE; }
BOOL CTortoiseGitBlameDoc::OnOpenDocument(LPCTSTR lpszPathName,CString Rev) { if (!CDocument::OnOpenDocument(lpszPathName)) return FALSE; m_CurrentFileName=lpszPathName; m_Rev=Rev; // (SDI documents will reuse this document) if(!g_Git.CheckMsysGitDir()) { CMessageBox::Show(NULL,_T("MsysGit have not install or config fail"),_T("TortoiseGitBlame"),MB_OK); return FALSE; } GitAdminDir admindir; CString topdir; if(!admindir.HasAdminDir(lpszPathName,&topdir)) { CMessageBox::Show(NULL,CString(lpszPathName)+_T(" is not controled by git\nJust Show File Context"),_T("TortoiseGitBlame"),MB_OK); } else { m_IsGitFile=TRUE; g_Git.m_CurrentDir=topdir; CString PathName=lpszPathName; if(topdir[topdir.GetLength()-1] == _T('\\') || topdir[topdir.GetLength()-1] == _T('/')) PathName=PathName.Right(PathName.GetLength()-g_Git.m_CurrentDir.GetLength()); else PathName=PathName.Right(PathName.GetLength()-g_Git.m_CurrentDir.GetLength()-1); CTGitPath path; path.SetFromWin(PathName); if(!g_Git.m_CurrentDir.IsEmpty()) SetCurrentDirectory(g_Git.m_CurrentDir); m_GitPath = path; GetMainFrame()->m_wndOutput.LoadHistory(path.GetGitPathString()); CString cmd; if(Rev.IsEmpty()) Rev=_T("HEAD"); cmd.Format(_T("git.exe blame -s -l %s -- \"%s\""),Rev,path.GetGitPathString()); m_BlameData.clear(); BYTE_VECTOR err; if(g_Git.Run(cmd, &m_BlameData, &err)) { CString str; g_Git.StringAppend(&str, &m_BlameData[0], CP_ACP); g_Git.StringAppend(&str, &err[0], CP_ACP); CMessageBox::Show(NULL,CString(_T("Blame Error")) + str,_T("TortoiseGitBlame"),MB_OK); } if(!m_TempFileName.IsEmpty()) { ::DeleteFile(m_TempFileName); m_TempFileName.Empty(); } m_TempFileName=GetTempFile(); if(Rev.IsEmpty()) Rev=_T("HEAD"); cmd.Format(_T("git.exe cat-file blob %s:\"%s\""),Rev,path.GetGitPathString()); if(g_Git.RunLogFile(cmd, m_TempFileName)) { CString str; str.Format(_T("Fail get file %s"), path.GetGitPathString()); CMessageBox::Show(NULL,CString(_T("Blame Error")) + str,_T("TortoiseGitBlame"),MB_OK); } CTortoiseGitBlameView *pView=DYNAMIC_DOWNCAST(CTortoiseGitBlameView,GetMainFrame()->GetActiveView()); if(pView == NULL) { CWnd* pWnd = GetMainFrame()->GetDescendantWindow(AFX_IDW_PANE_FIRST, TRUE); if (pWnd != NULL && pWnd->IsKindOf(RUNTIME_CLASS(CTortoiseGitBlameView))) { pView = (CTortoiseGitBlameView*)pWnd; } else { return FALSE; } } pView->UpdateInfo(); } return TRUE; }
UINT CImportPatchDlg::PatchThread() { CTGitPath path; path.SetFromWin(g_Git.m_CurrentDir); int i=0; UpdateOkCancelText(); for (i = m_CurrentItem; i < m_cList.GetItemCount(); ++i) { if (m_pTaskbarList) { m_pTaskbarList->SetProgressState(m_hWnd, TBPF_NORMAL); m_pTaskbarList->SetProgressValue(m_hWnd, i, m_cList.GetItemCount()); } m_cList.SetItemData(i, CPatchListCtrl::STATUS_APPLYING|m_cList.GetItemData(i)); CRect rect; this->m_cList.GetItemRect(i,&rect,LVIR_BOUNDS); this->m_cList.InvalidateRect(rect); if(m_bExitThread) break; if(m_cList.GetCheck(i)) { CString cmd; while(path.HasRebaseApply()) { if (m_pTaskbarList) m_pTaskbarList->SetProgressState(m_hWnd, TBPF_ERROR); int ret = CMessageBox::Show(NULL, IDS_PROC_APPLYPATCH_REBASEDIRFOUND, IDS_APPNAME, 1, IDI_ERROR, IDS_ABORTBUTTON, IDS_SKIPBUTTON, IDS_RESOLVEDBUTTON); switch(ret) { case 1: cmd = _T("git.exe am --abort"); break; case 2: cmd = _T("git.exe am --skip"); ++i; break; case 3: cmd = _T("git.exe am --resolved"); break; default: cmd.Empty(); } if(cmd.IsEmpty()) { m_bExitThread = TRUE; break; } this->AddLogString(cmd); CString output; if (g_Git.Run(cmd, &output, CP_UTF8)) { this->AddLogString(output); this->AddLogString(CString(MAKEINTRESOURCE(IDS_FAIL))); } else { this->AddLogString(CString(MAKEINTRESOURCE(IDS_DONE))); } } if(m_bExitThread) break; cmd = _T("git.exe am "); if(this->m_bAddSignedOffBy) cmd += _T("--signoff "); if(this->m_b3Way) cmd += _T("--3way "); if(this->m_bIgnoreSpace) cmd += _T("--ignore-space-change "); if(this->m_bKeepCR) cmd += _T("--keep-cr "); cmd += _T("\""); cmd += m_cList.GetItemText(i,0); cmd += _T("\""); this->AddLogString(cmd); CString output; if (g_Git.Run(cmd, &output, CP_UTF8)) { //keep STATUS_APPLYING to let user retry failed patch m_cList.SetItemData(i, CPatchListCtrl::STATUS_APPLY_FAIL|CPatchListCtrl::STATUS_APPLYING); this->AddLogString(output); this->AddLogString(CString(MAKEINTRESOURCE(IDS_FAIL))); if (m_pTaskbarList) m_pTaskbarList->SetProgressState(m_hWnd, TBPF_ERROR); break; } else { m_cList.SetItemData(i, CPatchListCtrl::STATUS_APPLY_SUCCESS); this->AddLogString(CString(MAKEINTRESOURCE(IDS_SUCCESS))); } } else { CString sMessage; sMessage.Format(IDS_PROC_SKIPPATCH, m_cList.GetItemText(i,0)); AddLogString(sMessage); m_cList.SetItemData(i, CPatchListCtrl::STATUS_APPLY_SKIP); } m_cList.SetItemData(m_CurrentItem, (~CPatchListCtrl::STATUS_APPLYING)&m_cList.GetItemData(i)); ++m_CurrentItem; this->m_cList.GetItemRect(i,&rect,LVIR_BOUNDS); this->m_cList.InvalidateRect(rect); UpdateOkCancelText(); } //in case am fail, need refresh finial item status CRect rect; this->m_cList.GetItemRect(i,&rect,LVIR_BOUNDS); this->m_cList.InvalidateRect(rect); this->m_cList.GetItemRect(m_CurrentItem,&rect,LVIR_BOUNDS); this->m_cList.InvalidateRect(rect); if (m_pTaskbarList) { m_pTaskbarList->SetProgressValue(m_hWnd, m_CurrentItem, m_cList.GetItemCount()); if (m_bExitThread && m_CurrentItem != m_cList.GetItemCount()) m_pTaskbarList->SetProgressState(m_hWnd, TBPF_PAUSED); else if (!m_bExitThread && m_CurrentItem == m_cList.GetItemCount()) m_pTaskbarList->SetProgressState(m_hWnd, TBPF_NORMAL); } EnableInputCtrl(true); InterlockedExchange(&m_bThreadRunning, FALSE); UpdateOkCancelText(); return 0; }