int CTGitPathList::ParserFromLsFile(BYTE_VECTOR &out,bool /*staged*/) { int pos=0; CString one; CTGitPath path; CString part; this->Clear(); while (pos >= 0 && pos < (int)out.size()) { one.Empty(); path.Reset(); CGit::StringAppend(&one, &out[pos], CP_UTF8); int tabstart=0; // m_Action is never used and propably never worked (needs to be set after path.SetFromGit) // also dropped LOGACTIONS_CACHE for 'H' // path.m_Action=path.ParserAction(out[pos]); one.Tokenize(_T("\t"),tabstart); if(tabstart>=0) path.SetFromGit(one.Right(one.GetLength()-tabstart)); else return -1; tabstart=0; part=one.Tokenize(_T(" "),tabstart); //Tag if (tabstart < 0) return -1; part=one.Tokenize(_T(" "),tabstart); //Mode if (tabstart < 0) return -1; part=one.Tokenize(_T(" "),tabstart); //Hash if (tabstart < 0) return -1; part=one.Tokenize(_T("\t"),tabstart); //Stage if (tabstart < 0) return -1; path.m_Stage=_ttol(part); this->AddPath(path); pos=out.findNextString(pos); } return 0; }
int GitRev::SafeFetchFullInfo(CGit *git) { if(InterlockedExchange(&m_IsUpdateing,TRUE) == FALSE) { this->m_Files.Clear(); git->CheckAndInitDll(); GIT_COMMIT commit; GIT_COMMIT_LIST list; GIT_HASH parent; memset(&commit,0,sizeof(GIT_COMMIT)); CAutoLocker lock(g_Git.m_critGitDllSec); try { if (git_get_commit_from_hash(&commit, this->m_CommitHash.m_hash)) return -1; } catch (char *) { return -1; } int i=0; git_get_commit_first_parent(&commit,&list); bool isRoot = (list==NULL); while(git_get_commit_next_parent(&list,parent) == 0 || isRoot) { GIT_FILE file=0; int count=0; try { if (isRoot) git_root_diff(git->GetGitDiff(), this->m_CommitHash.m_hash, &file, &count, 1); else git_diff(git->GetGitDiff(), parent, commit.m_hash, &file, &count, 1); } catch (char *) { git_free_commit(&commit); return -1; } isRoot = false; CTGitPath path; CString strnewname; CString stroldname; for (int j = 0; j < count; ++j) { path.Reset(); char *newname; char *oldname; strnewname.Empty(); stroldname.Empty(); int mode,IsBin,inc,dec; git_get_diff_file(git->GetGitDiff(),file,j,&newname,&oldname, &mode,&IsBin,&inc,&dec); git->StringAppend(&strnewname, (BYTE*)newname, CP_UTF8); git->StringAppend(&stroldname, (BYTE*)oldname, CP_UTF8); path.SetFromGit(strnewname,&stroldname); path.ParserAction((BYTE)mode); path.m_ParentNo = i; this->m_Action|=path.m_Action; if(IsBin) { path.m_StatAdd=_T("-"); path.m_StatDel=_T("-"); } else { path.m_StatAdd.Format(_T("%d"),inc); path.m_StatDel.Format(_T("%d"),dec); } m_Files.AddPath(path); } git_diff_flush(git->GetGitDiff()); ++i; } InterlockedExchange(&m_IsUpdateing,FALSE); InterlockedExchange(&m_IsFull,TRUE); git_free_commit(&commit); } return 0; }
int GitRev::SafeGetSimpleList(CGit *git) { if(InterlockedExchange(&m_IsUpdateing,TRUE) == FALSE) { m_SimpleFileList.clear(); git->CheckAndInitDll(); GIT_COMMIT commit; GIT_COMMIT_LIST list; GIT_HASH parent; memset(&commit,0,sizeof(GIT_COMMIT)); CAutoLocker lock(g_Git.m_critGitDllSec); try { if(git_get_commit_from_hash(&commit, this->m_CommitHash.m_hash)) return -1; } catch (char *) { return -1; } int i=0; bool isRoot = this->m_ParentHash.empty(); git_get_commit_first_parent(&commit,&list); while(git_get_commit_next_parent(&list,parent) == 0 || isRoot) { GIT_FILE file=0; int count=0; try { if(isRoot) git_root_diff(git->GetGitSimpleListDiff(), commit.m_hash, &file, &count, 0); else git_diff(git->GetGitSimpleListDiff(), parent, commit.m_hash, &file, &count, 0); } catch (char *) { return -1; } isRoot = false; CTGitPath path; CString strnewname; CString stroldname; for (int j = 0; j < count; ++j) { path.Reset(); char *newname; char *oldname; strnewname.Empty(); stroldname.Empty(); int mode,IsBin,inc,dec; try { git_get_diff_file(git->GetGitSimpleListDiff(), file, j, &newname, &oldname, &mode, &IsBin, &inc, &dec); } catch (char *) { return -1; } git->StringAppend(&strnewname, (BYTE*)newname, CP_UTF8); m_SimpleFileList.push_back(strnewname); } git_diff_flush(git->GetGitSimpleListDiff()); ++i; } InterlockedExchange(&m_IsUpdateing,FALSE); InterlockedExchange(&m_IsSimpleListReady, TRUE); git_free_commit(&commit); } return 0; }
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; }
int CLogCache::LoadOneItem(GitRev &Rev,ULONGLONG offset) { if(m_pCacheData == NULL) return -1; if (offset + sizeof(SLogCacheRevItemHeader) > m_DataFileLength) return -2; SLogCacheRevItemHeader *header; header = (SLogCacheRevItemHeader *)(this->m_pCacheData + offset); if( !CheckHeader(header)) return -2; Rev.m_Action = 0; SLogCacheRevFileHeader *fileheader; offset += sizeof(SLogCacheRevItemHeader); fileheader =(SLogCacheRevFileHeader *)(this->m_pCacheData + offset); for (DWORD i = 0; i < header->m_FileCount; ++i) { CTGitPath path; CString oldfile; path.Reset(); if (offset + sizeof(SLogCacheRevFileHeader) > m_DataFileLength) return -2; if(!CheckHeader(fileheader)) return -2; CString file(fileheader->m_FileName, fileheader->m_FileNameSize); if(fileheader->m_OldFileNameSize) { oldfile = CString(fileheader->m_FileName + fileheader->m_FileNameSize, fileheader->m_OldFileNameSize); } path.SetFromGit(file,&oldfile); path.m_ParentNo = fileheader ->m_ParentNo; path.m_Stage = fileheader ->m_Stage; path.m_Action = fileheader ->m_Action; Rev.m_Action |= path.m_Action; if(fileheader->m_Add == 0xFFFFFFFF) path.m_StatAdd=_T("-"); else path.m_StatAdd.Format(_T("%d"),fileheader->m_Add); if(fileheader->m_Del == 0xFFFFFFFF) path.m_StatDel=_T("-"); else path.m_StatDel.Format(_T("%d"), fileheader->m_Del); Rev.m_Files.AddPath(path); offset += sizeof(*fileheader) + fileheader->m_OldFileNameSize*sizeof(TCHAR) + fileheader->m_FileNameSize*sizeof(TCHAR) - sizeof(TCHAR); fileheader = (SLogCacheRevFileHeader *) (this->m_pCacheData + offset); } return 0; }
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; }
int CGit::GetDiffPath(CTGitPathList *PathList, CGitHash *hash1, CGitHash *hash2, char *arg) { GIT_FILE file=0; int ret=0; GIT_DIFF diff=0; CAutoLocker lock(g_Git.m_critGitDllSec); if(arg == NULL) diff = GetGitDiff(); else git_open_diff(&diff, arg); if(diff ==NULL) return -1; bool isStat = 0; if(arg == NULL) isStat = true; else isStat = !!strstr(arg, "stat"); int count=0; if(hash2 == NULL) ret = git_root_diff(diff, hash1->m_hash, &file, &count,isStat); else ret = git_diff(diff,hash2->m_hash,hash1->m_hash,&file,&count,isStat); if(ret) return -1; CTGitPath path; CString strnewname; CString stroldname; for(int j=0;j<count;j++) { path.Reset(); char *newname; char *oldname; strnewname.Empty(); stroldname.Empty(); int mode=0,IsBin=0,inc=0,dec=0; git_get_diff_file(diff,file,j,&newname,&oldname, &mode,&IsBin,&inc,&dec); StringAppend(&strnewname, (BYTE*)newname, CP_UTF8); StringAppend(&stroldname, (BYTE*)oldname, CP_UTF8); path.SetFromGit(strnewname,&stroldname); path.ParserAction((BYTE)mode); if(IsBin) { path.m_StatAdd=_T("-"); path.m_StatDel=_T("-"); } else { path.m_StatAdd.Format(_T("%d"),inc); path.m_StatDel.Format(_T("%d"),dec); } PathList->AddPath(path); } git_diff_flush(diff); if(arg) git_close_diff(diff); return 0; }
int CTGitPathList::ParserFromLog(BYTE_VECTOR &log, bool parseDeletes /*false*/) { this->Clear(); std::map<CString, size_t> duplicateMap; int pos=0; CTGitPath path; m_Action=0; int logend = (int)log.size(); while (pos >= 0 && pos < logend) { path.Reset(); if(log[pos]=='\n') ++pos; if (pos >= logend) return -1; if(log[pos]==':') { bool merged=false; if (pos + 1 >= logend) return -1; if(log[pos+1] ==':') { merged=true; } int end=log.find(0,pos); int actionstart=-1; int file1=-1,file2=-1; if( end>0 ) { actionstart=log.find(' ',end-6); pos=actionstart; } if( actionstart>0 ) { ++actionstart; if (actionstart >= logend) return -1; file1 = log.find(0,actionstart); if( file1>=0 ) { ++file1; pos=file1; } if( log[actionstart] == 'C' || log[actionstart] == 'R' ) { file2=file1; file1 = log.find(0,file1); if(file1>=0 ) { ++file1; pos=file1; } } } CString pathname1; CString pathname2; if( file1>=0 ) CGit::StringAppend(&pathname1, &log[file1], CP_UTF8); if( file2>=0 ) CGit::StringAppend(&pathname2, &log[file2], CP_UTF8); if (actionstart < 0) return -1; auto existing = duplicateMap.find(pathname1); if (existing != duplicateMap.end()) { CTGitPath& p = m_paths[existing->second]; p.ParserAction(log[actionstart]); if(merged) p.m_Action |= CTGitPath::LOGACTIONS_MERGED; m_Action |= p.m_Action; } else { int ac=path.ParserAction(log[actionstart] ); ac |= merged?CTGitPath::LOGACTIONS_MERGED:0; path.SetFromGit(pathname1,&pathname2); path.m_Action=ac; //action must be set after setfromgit. SetFromGit will clear all status. this->m_Action|=ac; AddPath(path); duplicateMap.insert(std::pair<CString, size_t>(path.GetGitPathString(), m_paths.size() - 1)); } } else { int tabstart=0; path.Reset(); CString StatAdd; CString StatDel; CString file1; CString file2; tabstart=log.find('\t',pos); if(tabstart >=0) { log[tabstart]=0; CGit::StringAppend(&StatAdd, &log[pos], CP_UTF8); pos=tabstart+1; } tabstart=log.find('\t',pos); if(tabstart >=0) { log[tabstart]=0; CGit::StringAppend(&StatDel, &log[pos], CP_UTF8); pos=tabstart+1; } if(log[pos] == 0) //rename { ++pos; CGit::StringAppend(&file2, &log[pos], CP_UTF8); int sec=log.find(0,pos); if(sec>=0) { ++sec; CGit::StringAppend(&file1, &log[sec], CP_UTF8); } pos=sec; } else { CGit::StringAppend(&file1, &log[pos], CP_UTF8); } path.SetFromGit(file1,&file2); auto existing = duplicateMap.find(path.GetGitPathString()); if (existing != duplicateMap.end()) { CTGitPath& p = m_paths[existing->second]; p.m_StatAdd = StatAdd; p.m_StatDel = StatDel; } else { //path.SetFromGit(pathname); if (parseDeletes) { path.m_StatAdd=_T("0"); path.m_StatDel=_T("0"); path.m_Action |= CTGitPath::LOGACTIONS_DELETED | CTGitPath::LOGACTIONS_MISSING; } else { path.m_StatAdd=StatAdd; path.m_StatDel=StatDel; } AddPath(path); duplicateMap.insert(std::pair<CString, size_t>(path.GetGitPathString(), m_paths.size() - 1)); } } pos=log.findNextString(pos); } return 0; }
BOOL CTortoiseProcApp::InitInstance() { CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": InitInstance\n")); CheckUpgrade(); CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows)); CMFCButton::EnableWindowsTheming(); CHistoryCombo::m_nGitIconIndex = SYS_IMAGE_LIST().AddIcon((HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_GITCONFIG), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE)); Gdiplus::GdiplusStartupInput gdiplusStartupInput; Gdiplus::GdiplusStartup(&m_gdiplusToken,&gdiplusStartupInput,NULL); //set the resource dll for the required language CRegDWORD loc = CRegDWORD(_T("Software\\TortoiseGit\\LanguageID"), 1033); long langId = loc; { CString langStr; langStr.Format(_T("%ld"), langId); CCrashReport::Instance().AddUserInfoToReport(L"LanguageID", langStr); } CString langDll; CStringA langpath = CStringA(CPathUtils::GetAppParentDirectory()); langpath += "Languages"; do { langDll.Format(_T("%sLanguages\\TortoiseProc%ld.dll"), (LPCTSTR)CPathUtils::GetAppParentDirectory(), langId); CString sVer = _T(STRPRODUCTVER); CString sFileVer = CPathUtils::GetVersionFromFile(langDll); if (sFileVer == sVer) { HINSTANCE hInst = LoadLibrary(langDll); if (hInst != NULL) { CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": Load Language DLL %s\n"), langDll); AfxSetResourceHandle(hInst); break; } } { DWORD lid = SUBLANGID(langId); lid--; if (lid > 0) { langId = MAKELANGID(PRIMARYLANGID(langId), lid); } else langId = 0; } } while (langId != 0); TCHAR buf[6] = { 0 }; _tcscpy_s(buf, _T("en")); langId = loc; // MFC uses a help file with the same name as the application by default, // which means we have to change that default to our language specific help files CString sHelppath = CPathUtils::GetAppDirectory() + _T("TortoiseGit_en.chm"); free((void*)m_pszHelpFilePath); m_pszHelpFilePath=_tcsdup(sHelppath); sHelppath = CPathUtils::GetAppParentDirectory() + _T("Languages\\TortoiseGit_en.chm"); do { CString sLang = _T("_"); if (GetLocaleInfo(MAKELCID(langId, SORT_DEFAULT), LOCALE_SISO639LANGNAME, buf, _countof(buf))) { sLang += buf; sHelppath.Replace(_T("_en"), sLang); if (PathFileExists(sHelppath)) { free((void*)m_pszHelpFilePath); m_pszHelpFilePath=_tcsdup(sHelppath); break; } } sHelppath.Replace(sLang, _T("_en")); if (GetLocaleInfo(MAKELCID(langId, SORT_DEFAULT), LOCALE_SISO3166CTRYNAME, buf, _countof(buf))) { sLang += _T("_"); sLang += buf; sHelppath.Replace(_T("_en"), sLang); if (PathFileExists(sHelppath)) { free((void*)m_pszHelpFilePath); m_pszHelpFilePath=_tcsdup(sHelppath); break; } } sHelppath.Replace(sLang, _T("_en")); DWORD lid = SUBLANGID(langId); lid--; if (lid > 0) { langId = MAKELANGID(PRIMARYLANGID(langId), lid); } else langId = 0; } while (langId); CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": Set Help Filename %s\n"), m_pszHelpFilePath); setlocale(LC_ALL, ""); if (!g_Git.CheckMsysGitDir()) { UINT ret = CMessageBox::Show(NULL, IDS_PROC_NOMSYSGIT, IDS_APPNAME, 3, IDI_HAND, IDS_PROC_SETMSYSGITPATH, IDS_PROC_GOTOMSYSGITWEBSITE, IDS_ABORTBUTTON); if(ret == 2) { ShellExecute(NULL, NULL, _T("http://msysgit.github.io/"), NULL, NULL, SW_SHOW); } else if(ret == 1) { // open settings dialog CSinglePropSheetDlg(CString(MAKEINTRESOURCE(IDS_PROC_SETTINGS_TITLE)), new CSetMainPage(), this->GetMainWnd()).DoModal(); } return FALSE; } if (CAppUtils::GetMsysgitVersion() < 0x01070a00) { int ret = CMessageBox::ShowCheck(NULL, IDS_PROC_OLDMSYSGIT, IDS_APPNAME, 1, IDI_EXCLAMATION, IDS_PROC_GOTOMSYSGITWEBSITE, IDS_ABORTBUTTON, IDS_IGNOREBUTTON, _T("OldMsysgitVersionWarning"), IDS_PROC_NOTSHOWAGAINIGNORE); if (ret == 1) { CMessageBox::RemoveRegistryKey(_T("OldMsysgitVersionWarning")); // only store answer if it is "Ignore" ShellExecute(NULL, NULL, _T("http://msysgit.github.io/"), NULL, NULL, SW_SHOW); return FALSE; } else if (ret == 2) { CMessageBox::RemoveRegistryKey(_T("OldMsysgitVersionWarning")); // only store answer if it is "Ignore" return FALSE; } } { CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": Registering Crash Report ...\n")); CCrashReport::Instance().AddUserInfoToReport(L"msysGitDir", CGit::ms_LastMsysGitDir); CString versionString; versionString.Format(_T("%d"), CGit::ms_LastMsysGitVersion); CCrashReport::Instance().AddUserInfoToReport(L"msysGitVersion", versionString); } CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": Initializing UI components ...\n")); // InitCommonControls() is required on Windows XP if an application // manifest specifies use of ComCtl32.dll version 6 or later to enable // visual styles. Otherwise, any window creation will fail. INITCOMMONCONTROLSEX used = { sizeof(INITCOMMONCONTROLSEX), ICC_ANIMATE_CLASS | ICC_BAR_CLASSES | ICC_COOL_CLASSES | ICC_DATE_CLASSES | ICC_HOTKEY_CLASS | ICC_INTERNET_CLASSES | ICC_LISTVIEW_CLASSES | ICC_NATIVEFNTCTL_CLASS | ICC_PAGESCROLLER_CLASS | ICC_PROGRESS_CLASS | ICC_TAB_CLASSES | ICC_TREEVIEW_CLASSES | ICC_UPDOWN_CLASS | ICC_USEREX_CLASSES | ICC_WIN95_CLASSES }; InitCommonControlsEx(&used); AfxOleInit(); AfxEnableControlContainer(); AfxInitRichEdit5(); CWinAppEx::InitInstance(); SetRegistryKey(_T("TortoiseGit")); AfxGetApp()->m_pszProfileName = _tcsdup(_T("TortoiseProc")); // w/o this ResizableLib will store data under TortoiseGitProc which is not compatible with older versions CCmdLineParser parser(AfxGetApp()->m_lpCmdLine); hWndExplorer = NULL; CString sVal = parser.GetVal(_T("hwnd")); if (!sVal.IsEmpty()) hWndExplorer = (HWND)_wcstoui64(sVal, nullptr, 16); while (GetParent(hWndExplorer)!=NULL) hWndExplorer = GetParent(hWndExplorer); if (!IsWindow(hWndExplorer)) { hWndExplorer = NULL; } // if HKCU\Software\TortoiseGit\Debug is not 0, show our command line // in a message box if (CRegDWORD(_T("Software\\TortoiseGit\\Debug"), FALSE)==TRUE) AfxMessageBox(AfxGetApp()->m_lpCmdLine, MB_OK | MB_ICONINFORMATION); if (parser.HasKey(_T("urlhandler"))) { CString url = parser.GetVal(_T("urlhandler")); if (url.Find(_T("tgit://clone/")) == 0) { url = url.Mid(13); // 21 = "tgit://clone/".GetLength() } else if (url.Find(_T("github-windows://openRepo/")) == 0) { url = url.Mid(26); // 26 = "github-windows://openRepo/".GetLength() int questioMark = url.Find('?'); if (questioMark > 0) url = url.Left(questioMark); } else if (url.Find(_T("smartgit://cloneRepo/")) == 0) { url = url.Mid(21); // 21 = "smartgit://cloneRepo/".GetLength() } else { CMessageBox::Show(NULL, IDS_ERR_INVALIDPATH, IDS_APPNAME, MB_ICONERROR); return FALSE; } CString newCmd; newCmd.Format(_T("/command:clone /url:\"%s\" /hasurlhandler"), url); parser = CCmdLineParser(newCmd); } if ( parser.HasKey(_T("path")) && parser.HasKey(_T("pathfile"))) { CMessageBox::Show(NULL, IDS_ERR_INVALIDPATH, IDS_APPNAME, MB_ICONERROR); return FALSE; } CTGitPath cmdLinePath; CTGitPathList pathList; if (g_sGroupingUUID.IsEmpty()) g_sGroupingUUID = parser.GetVal(L"groupuuid"); if ( parser.HasKey(_T("pathfile")) ) { CString sPathfileArgument = CPathUtils::GetLongPathname(parser.GetVal(_T("pathfile"))); cmdLinePath.SetFromUnknown(sPathfileArgument); if (pathList.LoadFromFile(cmdLinePath)==false) return FALSE; // no path specified! if ( parser.HasKey(_T("deletepathfile")) ) { // We can delete the temporary path file, now that we've loaded it ::DeleteFile(cmdLinePath.GetWinPath()); } // This was a path to a temporary file - it's got no meaning now, and // anybody who uses it again is in for a problem... cmdLinePath.Reset(); } else { CString sPathArgument = CPathUtils::GetLongPathname(parser.GetVal(_T("path"))); if (parser.HasKey(_T("expaths"))) { // an /expaths param means we're started via the buttons in our Win7 library // and that means the value of /expaths is the current directory, and // the selected paths are then added as additional parameters but without a key, only a value // because of the "strange treatment of quotation marks and backslashes by CommandLineToArgvW" // we have to escape the backslashes first. Since we're only dealing with paths here, that's // a save bet. // Without this, a command line like: // /command:commit /expaths:"D:\" "D:\Utils" // would fail because the "D:\" is treated as the backslash being the escape char for the quotation // mark and we'd end up with: // argv[1] = /command:commit // argv[2] = /expaths:D:" D:\Utils // See here for more details: http://blogs.msdn.com/b/oldnewthing/archive/2010/09/17/10063629.aspx CString cmdLine = GetCommandLineW(); cmdLine.Replace(L"\\", L"\\\\"); int nArgs = 0; LPWSTR *szArglist = CommandLineToArgvW(cmdLine, &nArgs); if (szArglist) { // argument 0 is the process path, so start with 1 for (int i = 1; i < nArgs; ++i) { if (szArglist[i][0] != '/') { if (!sPathArgument.IsEmpty()) sPathArgument += '*'; sPathArgument += szArglist[i]; } } sPathArgument.Replace(L"\\\\", L"\\"); } LocalFree(szArglist); } if (sPathArgument.IsEmpty() && parser.HasKey(L"path")) { CMessageBox::Show(hWndExplorer, IDS_ERR_INVALIDPATH, IDS_APPNAME, MB_ICONERROR); return FALSE; } int asterisk = sPathArgument.Find('*'); cmdLinePath.SetFromUnknown(asterisk >= 0 ? sPathArgument.Left(asterisk) : sPathArgument); pathList.LoadFromAsteriskSeparatedString(sPathArgument); } if (pathList.IsEmpty()) { pathList.AddPath(CTGitPath::CTGitPath(g_Git.m_CurrentDir)); } // Set CWD to temporary dir, and restore it later { DWORD len = GetCurrentDirectory(0, NULL); if (len) { std::unique_ptr<TCHAR[]> originalCurrentDirectory(new TCHAR[len]); if (GetCurrentDirectory(len, originalCurrentDirectory.get())) { sOrigCWD = originalCurrentDirectory.get(); sOrigCWD = CPathUtils::GetLongPathname(sOrigCWD); } } TCHAR pathbuf[MAX_PATH] = {0}; GetTortoiseGitTempPath(MAX_PATH, pathbuf); SetCurrentDirectory(pathbuf); } CheckForNewerVersion(); CAutoGeneralHandle TGitMutex = ::CreateMutex(NULL, FALSE, _T("TortoiseGitProc.exe")); if (!g_Git.SetCurrentDir(cmdLinePath.GetWinPathString(), parser.HasKey(_T("submodule")) == TRUE)) { for (int i = 0; i < pathList.GetCount(); ++i) if(g_Git.SetCurrentDir(pathList[i].GetWinPath())) break; } if(!g_Git.m_CurrentDir.IsEmpty()) { sOrigCWD = g_Git.m_CurrentDir; SetCurrentDirectory(g_Git.m_CurrentDir); } if (g_sGroupingUUID.IsEmpty()) { CRegStdDWORD groupSetting = CRegStdDWORD(_T("Software\\TortoiseGit\\GroupTaskbarIconsPerRepo"), 3); switch (DWORD(groupSetting)) { case 1: case 2: // implemented differently to TortoiseSVN atm break; case 3: case 4: { CString wcroot; if (g_GitAdminDir.HasAdminDir(g_Git.m_CurrentDir, true, &wcroot)) { git_oid oid; CStringA wcRootA(wcroot + CPathUtils::GetAppDirectory()); if (!git_odb_hash(&oid, wcRootA, wcRootA.GetLength(), GIT_OBJ_BLOB)) { CStringA hash; git_oid_tostr(hash.GetBufferSetLength(GIT_OID_HEXSZ + 1), GIT_OID_HEXSZ + 1, &oid); hash.ReleaseBuffer(); g_sGroupingUUID = hash; } ProjectProperties pp; pp.ReadProps(); CString icon = pp.sIcon; icon.Replace('/', '\\'); if (icon.IsEmpty()) g_bGroupingRemoveIcon = true; g_sGroupingIcon = icon; } } } } CString sAppID = GetTaskIDPerUUID(g_sGroupingUUID).c_str(); InitializeJumpList(sAppID); EnsureGitLibrary(false); { CString err; try { // requires CWD to be set CGit::m_LogEncode = CAppUtils::GetLogOutputEncode(); // make sure all config files are read in order to check that none contains an error g_Git.GetConfigValue(_T("doesnot.exist")); } catch (char* msg) { err = CString(msg); } if (!err.IsEmpty()) { UINT choice = CMessageBox::Show(hWndExplorer, err, _T("TortoiseGit"), 1, IDI_ERROR, CString(MAKEINTRESOURCE(IDS_PROC_EDITLOCALGITCONFIG)), CString(MAKEINTRESOURCE(IDS_PROC_EDITGLOBALGITCONFIG)), CString(MAKEINTRESOURCE(IDS_ABORTBUTTON))); if (choice == 1) { // open the config file with alternative editor CAppUtils::LaunchAlternativeEditor(g_Git.GetGitLocalConfig()); } else if (choice == 2) { // open the global config file with alternative editor CAppUtils::LaunchAlternativeEditor(g_Git.GetGitGlobalConfig()); } return FALSE; } } // execute the requested command CommandServer server; Command * cmd = server.GetCommand(parser.GetVal(_T("command"))); if (cmd) { cmd->SetExplorerHwnd(hWndExplorer); cmd->SetParser(parser); cmd->SetPaths(pathList, cmdLinePath); retSuccess = cmd->Execute(); delete cmd; } // Look for temporary files left around by TortoiseSVN and // remove them. But only delete 'old' files because some // apps might still be needing the recent ones. { DWORD len = GetTortoiseGitTempPath(0, NULL); std::unique_ptr<TCHAR[]> path(new TCHAR[len + 100]); len = GetTortoiseGitTempPath (len + 100, path.get()); if (len != 0) { CDirFileEnum finder(path.get()); FILETIME systime_; ::GetSystemTimeAsFileTime(&systime_); __int64 systime = (((_int64)systime_.dwHighDateTime)<<32) | ((__int64)systime_.dwLowDateTime); bool isDir; CString filepath; while (finder.NextFile(filepath, &isDir)) { HANDLE hFile = ::CreateFile(filepath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, isDir ? FILE_FLAG_BACKUP_SEMANTICS : NULL, NULL); if (hFile != INVALID_HANDLE_VALUE) { FILETIME createtime_; if (::GetFileTime(hFile, &createtime_, NULL, NULL)) { ::CloseHandle(hFile); __int64 createtime = (((_int64)createtime_.dwHighDateTime)<<32) | ((__int64)createtime_.dwLowDateTime); if ((createtime + 864000000000) < systime) //only delete files older than a day { ::SetFileAttributes(filepath, FILE_ATTRIBUTE_NORMAL); if (isDir) ::RemoveDirectory(filepath); else ::DeleteFile(filepath); } } else ::CloseHandle(hFile); } } } } // Since the dialog has been closed, return FALSE so that we exit the // application, rather than start the application's message pump. return FALSE; }
BOOL CTortoiseProcApp::InitInstance() { EnableCrashHandler(); InitializeJumpList(); CheckUpgrade(); CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows)); CMFCButton::EnableWindowsTheming(); Gdiplus::GdiplusStartupInput gdiplusStartupInput; Gdiplus::GdiplusStartup(&m_gdiplusToken,&gdiplusStartupInput,NULL); if(!CheckMsysGitDir()) { UINT ret = CMessageBox::Show(NULL,_T("MSysGit (http://code.google.com/p/msysgit/) not found."), _T("TortoiseGit"), 3, IDI_HAND, _T("&Set MSysGit path"), _T("&Goto WebSite"), _T("&Abort")); if(ret == 2) { ShellExecute(NULL, NULL, _T("http://code.google.com/p/msysgit/"), NULL, NULL, SW_SHOW); } else if(ret == 1) { // open settings dialog CSettings dlg(IDS_PROC_SETTINGS_TITLE); dlg.SetTreeViewMode(TRUE, TRUE, TRUE); dlg.SetTreeWidth(220); dlg.DoModal(); dlg.HandleRestart(); } return FALSE; } //set the resource dll for the required language CRegDWORD loc = CRegDWORD(_T("Software\\TortoiseGit\\LanguageID"), 1033); long langId = loc; CString langDll; CStringA langpath = CStringA(CPathUtils::GetAppParentDirectory()); langpath += "Languages"; // bindtextdomain("subversion", (LPCSTR)langpath); // bind_textdomain_codeset("subversion", "UTF-8"); HINSTANCE hInst = NULL; do { langDll.Format(_T("..\\Languages\\TortoiseProc%d.dll"), langId); hInst = LoadLibrary(langDll); CString sVer = _T(STRPRODUCTVER); CString sFileVer = CPathUtils::GetVersionFromFile(langDll); if (sFileVer.Compare(sVer)!=0) { FreeLibrary(hInst); hInst = NULL; } if (hInst != NULL) { AfxSetResourceHandle(hInst); } else { DWORD lid = SUBLANGID(langId); lid--; if (lid > 0) { langId = MAKELANGID(PRIMARYLANGID(langId), lid); } else langId = 0; } } while ((hInst == NULL) && (langId != 0)); TCHAR buf[6]; _tcscpy_s(buf, _T("en")); langId = loc; CString sHelppath; sHelppath = this->m_pszHelpFilePath; sHelppath = sHelppath.MakeLower(); // MFC uses a help file with the same name as the application by default, // which means we have to change that default to our language specific help files sHelppath.Replace(_T("tortoiseproc.chm"), _T("TortoiseGit_en.chm")); free((void*)m_pszHelpFilePath); m_pszHelpFilePath=_tcsdup(sHelppath); sHelppath = CPathUtils::GetAppParentDirectory() + _T("Languages\\TortoiseGit_en.chm"); do { CString sLang = _T("_"); if (GetLocaleInfo(MAKELCID(langId, SORT_DEFAULT), LOCALE_SISO639LANGNAME, buf, _countof(buf))) { sLang += buf; sHelppath.Replace(_T("_en"), sLang); if (PathFileExists(sHelppath)) { free((void*)m_pszHelpFilePath); m_pszHelpFilePath=_tcsdup(sHelppath); break; } } sHelppath.Replace(sLang, _T("_en")); if (GetLocaleInfo(MAKELCID(langId, SORT_DEFAULT), LOCALE_SISO3166CTRYNAME, buf, _countof(buf))) { sLang += _T("_"); sLang += buf; sHelppath.Replace(_T("_en"), sLang); if (PathFileExists(sHelppath)) { free((void*)m_pszHelpFilePath); m_pszHelpFilePath=_tcsdup(sHelppath); break; } } sHelppath.Replace(sLang, _T("_en")); DWORD lid = SUBLANGID(langId); lid--; if (lid > 0) { langId = MAKELANGID(PRIMARYLANGID(langId), lid); } else langId = 0; } while (langId); setlocale(LC_ALL, ""); // InitCommonControls() is required on Windows XP if an application // manifest specifies use of ComCtl32.dll version 6 or later to enable // visual styles. Otherwise, any window creation will fail. INITCOMMONCONTROLSEX used = { sizeof(INITCOMMONCONTROLSEX), ICC_ANIMATE_CLASS | ICC_BAR_CLASSES | ICC_COOL_CLASSES | ICC_DATE_CLASSES | ICC_HOTKEY_CLASS | ICC_INTERNET_CLASSES | ICC_LISTVIEW_CLASSES | ICC_NATIVEFNTCTL_CLASS | ICC_PAGESCROLLER_CLASS | ICC_PROGRESS_CLASS | ICC_TAB_CLASSES | ICC_TREEVIEW_CLASSES | ICC_UPDOWN_CLASS | ICC_USEREX_CLASSES | ICC_WIN95_CLASSES }; InitCommonControlsEx(&used); AfxOleInit(); AfxEnableControlContainer(); AfxInitRichEdit2(); CWinAppEx::InitInstance(); SetRegistryKey(_T("TortoiseGit")); CCmdLineParser parser(AfxGetApp()->m_lpCmdLine); // if HKCU\Software\TortoiseGit\Debug is not 0, show our command line // in a message box if (CRegDWORD(_T("Software\\TortoiseGit\\Debug"), FALSE)==TRUE) AfxMessageBox(AfxGetApp()->m_lpCmdLine, MB_OK | MB_ICONINFORMATION); if ( parser.HasKey(_T("path")) && parser.HasKey(_T("pathfile"))) { CMessageBox::Show(NULL, IDS_ERR_INVALIDPATH, IDS_APPNAME, MB_ICONERROR); return FALSE; } CTGitPath cmdLinePath; CTGitPathList pathList; if ( parser.HasKey(_T("pathfile")) ) { CString sPathfileArgument = CPathUtils::GetLongPathname(parser.GetVal(_T("pathfile"))); cmdLinePath.SetFromUnknown(sPathfileArgument); if (pathList.LoadFromFile(cmdLinePath)==false) return FALSE; // no path specified! if ( parser.HasKey(_T("deletepathfile")) ) { // We can delete the temporary path file, now that we've loaded it ::DeleteFile(cmdLinePath.GetWinPath()); } // This was a path to a temporary file - it's got no meaning now, and // anybody who uses it again is in for a problem... cmdLinePath.Reset(); } else { CString sPathArgument = CPathUtils::GetLongPathname(parser.GetVal(_T("path"))); int asterisk = sPathArgument.Find('*'); cmdLinePath.SetFromUnknown(asterisk >= 0 ? sPathArgument.Left(asterisk) : sPathArgument); pathList.LoadFromAsteriskSeparatedString(sPathArgument); } if (pathList.GetCount() == 0) { pathList.AddPath(CTGitPath::CTGitPath(g_Git.m_CurrentDir)); } hWndExplorer = NULL; CString sVal = parser.GetVal(_T("hwnd")); if (!sVal.IsEmpty()) hWndExplorer = (HWND)_ttoi64(sVal); while (GetParent(hWndExplorer)!=NULL) hWndExplorer = GetParent(hWndExplorer); if (!IsWindow(hWndExplorer)) { hWndExplorer = NULL; } // Subversion sometimes writes temp files to the current directory! // Since TSVN doesn't need a specific CWD anyway, we just set it // to the users temp folder: that way, Subversion is guaranteed to // have write access to the CWD { DWORD len = GetCurrentDirectory(0, NULL); if (len) { TCHAR * originalCurrentDirectory = new TCHAR[len]; if (GetCurrentDirectory(len, originalCurrentDirectory)) { //sOrigCWD = originalCurrentDirectory; //sOrigCWD = CPathUtils::GetLongPathname(sOrigCWD); } delete [] originalCurrentDirectory; } TCHAR pathbuf[MAX_PATH]; GetTempPath(MAX_PATH, pathbuf); SetCurrentDirectory(pathbuf); } // check for newer versions if (CRegDWORD(_T("Software\\TortoiseGit\\CheckNewer"), TRUE) != FALSE) { time_t now; struct tm ptm; time(&now); if ((now != 0) && (localtime_s(&ptm, &now)==0)) { int week = 0; // we don't calculate the real 'week of the year' here // because just to decide if we should check for an update // that's not needed. week = ptm.tm_yday / 7; CRegDWORD oldweek = CRegDWORD(_T("Software\\TortoiseGit\\CheckNewerWeek"), (DWORD)-1); if (((DWORD)oldweek) == -1) oldweek = week; // first start of TortoiseProc, no update check needed else { if ((DWORD)week != oldweek) { oldweek = week; TCHAR com[MAX_PATH+100]; GetModuleFileName(NULL, com, MAX_PATH); _tcscat_s(com, MAX_PATH+100, _T(" /command:updatecheck")); CAppUtils::LaunchApplication(com, 0, false); } } } } if (parser.HasVal(_T("configdir"))) { // the user can override the location of the Subversion config directory here CString sConfigDir = parser.GetVal(_T("configdir")); // g_GitGlobal.SetConfigDir(sConfigDir); } // to avoid that SASL will look for and load its plugin dlls all around the // system, we set the path here. // Note that SASL doesn't have to be initialized yet for this to work // sasl_set_path(SASL_PATH_TYPE_PLUGIN, (LPSTR)(LPCSTR)CUnicodeUtils::GetUTF8(CPathUtils::GetAppDirectory().TrimRight('\\'))); HANDLE TSVNMutex = ::CreateMutex(NULL, FALSE, _T("TortoiseGitProc.exe")); if(!g_Git.SetCurrentDir(cmdLinePath.GetWinPathString())) { int i=0; for(i=0;i<pathList.GetCount();i++) if(g_Git.SetCurrentDir(pathList[i].GetWinPath())) break; } if(!g_Git.m_CurrentDir.IsEmpty()) SetCurrentDirectory(g_Git.m_CurrentDir); { CString err; try { // requires CWD to be set CGit::m_LogEncode = CAppUtils::GetLogOutputEncode(); } catch (char* msg) { err = CString(msg); } if (!err.IsEmpty()) { UINT choice = CMessageBox::Show(hWndExplorer, err, _T("TortoiseGit Error"), 1, IDI_ERROR, _T("&Edit .git/config"), _T("Edit &global .gitconfig"), _T("&Abort")); if (choice == 1) { // open the config file with alternative editor CString path = g_Git.m_CurrentDir; path += _T("\\.git\\config"); CAppUtils::LaunchAlternativeEditor(path); } else if (choice == 2) { // open the global config file with alternative editor TCHAR buf[MAX_PATH]; ExpandEnvironmentStrings(_T("%HOMEDRIVE%\\%HOMEPATH%\\.gitconfig"), buf, MAX_PATH); CAppUtils::LaunchAlternativeEditor(buf); } return FALSE; } } // execute the requested command CommandServer server; Command * cmd = server.GetCommand(parser.GetVal(_T("command"))); if (cmd) { cmd->SetExplorerHwnd(hWndExplorer); cmd->SetParser(parser); cmd->SetPaths(pathList, cmdLinePath); retSuccess = cmd->Execute(); delete cmd; } if (TSVNMutex) ::CloseHandle(TSVNMutex); // Look for temporary files left around by TortoiseSVN and // remove them. But only delete 'old' files because some // apps might still be needing the recent ones. { DWORD len = ::GetTempPath(0, NULL); TCHAR * path = new TCHAR[len + 100]; len = ::GetTempPath (len+100, path); if (len != 0) { CSimpleFileFind finder = CSimpleFileFind(path, _T("*svn*.*")); FILETIME systime_; ::GetSystemTimeAsFileTime(&systime_); __int64 systime = (((_int64)systime_.dwHighDateTime)<<32) | ((__int64)systime_.dwLowDateTime); while (finder.FindNextFileNoDirectories()) { CString filepath = finder.GetFilePath(); HANDLE hFile = ::CreateFile(filepath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL); if (hFile != INVALID_HANDLE_VALUE) { FILETIME createtime_; if (::GetFileTime(hFile, &createtime_, NULL, NULL)) { ::CloseHandle(hFile); __int64 createtime = (((_int64)createtime_.dwHighDateTime)<<32) | ((__int64)createtime_.dwLowDateTime); if ((createtime + 864000000000) < systime) //only delete files older than a day { ::SetFileAttributes(filepath, FILE_ATTRIBUTE_NORMAL); ::DeleteFile(filepath); } } else ::CloseHandle(hFile); } } } delete[] path; } // Since the dialog has been closed, return FALSE so that we exit the // application, rather than start the application's message pump. return FALSE; }
BOOL CTortoiseSIProcApp::ProcessCommandLine() { CCmdLineParser parser(AfxGetApp()->m_lpCmdLine); CString sVal = parser.GetVal(_T("hwnd")); if (!sVal.IsEmpty()) { m_hWndExplorer = (HWND)_wcstoui64(sVal, nullptr, 16); } while (GetParent(m_hWndExplorer) != NULL) { m_hWndExplorer = GetParent(m_hWndExplorer); } if (!IsWindow(m_hWndExplorer)) { m_hWndExplorer = NULL; } #if _DEBUG if (CRegDWORD(_T("Software\\TortoiseSI\\Debug"), FALSE) == TRUE) { AfxMessageBox(AfxGetApp()->m_lpCmdLine, MB_OK | MB_ICONINFORMATION); } #endif // The path and pathfile arguments are mutually exclusive if (parser.HasKey(_T("path")) && parser.HasKey(_T("pathfile"))) { CMessageBox::Show(NULL, IDS_ERR_INVALIDPATH, IDS_APPNAME, MB_ICONERROR); return FALSE; } CTGitPath cmdLinePath; CTGitPathList pathList; if (parser.HasKey(_T("pathfile"))) { // Process /pathfile argument CString sPathFileArgument = CPathUtils::GetLongPathname(parser.GetVal(_T("pathfile"))); cmdLinePath.SetFromUnknown(sPathFileArgument); if (pathList.LoadFromFile(cmdLinePath) == false) { // no path specified! return FALSE; } if (parser.HasKey(_T("deletepathfile"))) { // We can delete the temporary path file, now that we've loaded it ::DeleteFile(cmdLinePath.GetWinPath()); } // This was a path to a temporary file - it's got no meaning now, and // anybody who uses it again is in for a problem... cmdLinePath.Reset(); } else { // Process /path and /expaths argument // Build-uo /path value as /path:<value>*<arg1>*<arg2>... // Where <arg1>, <arg2> etc are extracted from /expath arguments. // Since all arguments are passed in the form of /parameter:<argument> // We process only those arguments which are not preceded by a /parameter: // This only includes arguments specified following /expaths (See comments below) CString sPathArgument = CPathUtils::GetLongPathname(parser.GetVal(_T("path"))); if (parser.HasKey(_T("expaths"))) { // An /expaths param means we are started via the buttons in our Win7 library // and that means the value of /expaths is the current directory and // the selected paths are then added as additional parameters but without a key, only a value // // e.g. /expaths:"D:\" "D:\Utils" // // Because of the "strange treatment of quotation marks and backslashes by CommandLineToArgvW", // we have to escape the backslashes first. Since we're only dealing with paths here, that's // a safe bet. Without this, a command line like: // // /command:commit /expaths:"D:\" "D:\Utils" // // would fail because the "D:\" is treated as the backslash being the escape char for the quotation // mark and we'd end up with: // // argv[1] = /command:commit // argv[2] = /expaths:D:" D:\Utils // // See here for more details: http://blogs.msdn.com/b/oldnewthing/archive/2010/09/17/10063629.aspx CString cmdLine = GetCommandLineW(); // Escape backslashes cmdLine.Replace(L"\\", L"\\\\"); int nArgs = 0; LPWSTR *szArgList = CommandLineToArgvW(cmdLine, &nArgs); if (szArgList) { // Argument 0 is the process path, so start with 1 for (int i = 1; i < nArgs; i++) { if (szArgList[i][0] != '/') { if (!sPathArgument.IsEmpty()) { sPathArgument += '*'; } sPathArgument += szArgList[i]; } } sPathArgument.Replace(L"\\\\", L"\\"); } LocalFree(szArgList); } if (sPathArgument.IsEmpty() && parser.HasKey(L"path")) { CMessageBox::Show(m_hWndExplorer, IDS_ERR_INVALIDPATH, IDS_APPNAME, MB_ICONERROR); return FALSE; } int asterisk = sPathArgument.Find('*'); cmdLinePath.SetFromUnknown(asterisk >= 0 ? sPathArgument.Left(asterisk) : sPathArgument); pathList.LoadFromAsteriskSeparatedString(sPathArgument); } if (pathList.IsEmpty()) { pathList.AddPath(CTGitPath::CTGitPath(g_Git.m_CurrentDir)); } // Set CWD to temporary dir, and restore it later { DWORD len = GetCurrentDirectory(0, NULL); if (len) { std::unique_ptr<TCHAR[]> originalCurrentDirectory(new TCHAR[len]); if (GetCurrentDirectory(len, originalCurrentDirectory.get())) { m_sOrigCWD = originalCurrentDirectory.get(); m_sOrigCWD = CPathUtils::GetLongPathname(m_sOrigCWD); } } TCHAR pathbuf[MAX_PATH] = { 0 }; GetTortoiseGitTempPath(MAX_PATH, pathbuf); SetCurrentDirectory(pathbuf); } if (!g_Git.m_CurrentDir.IsEmpty()) { m_sOrigCWD = g_Git.m_CurrentDir; SetCurrentDirectory(m_sOrigCWD); } // Execute the requested command CommandServer server; Command *cmd = server.GetCommand(parser.GetVal(_T("command"))); if (cmd) { cmd->SetExplorerHwnd(m_hWndExplorer); cmd->SetParser(parser); cmd->SetPaths(pathList, cmdLinePath); m_bRetSuccess = cmd->Execute(); delete cmd; } return TRUE; }