5 #include "registry.h"
\r
6 #include "GitConfig.h"
\r
8 #define MAX_DIRBUFFER 1000
\r
9 CString CGit::ms_LastMsysGitDir;
\r
13 GetCurrentDirectory(MAX_DIRBUFFER,m_CurrentDir.GetBuffer(MAX_DIRBUFFER));
\r
20 static char g_Buffer[4096];
\r
22 int CGit::RunAsync(CString cmd,PROCESS_INFORMATION *piOut,HANDLE *hReadOut,CString *StdioFile)
\r
24 SECURITY_ATTRIBUTES sa;
\r
25 HANDLE hRead, hWrite;
\r
26 HANDLE hStdioFile = NULL;
\r
28 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
29 sa.lpSecurityDescriptor=NULL;
\r
30 sa.bInheritHandle=TRUE;
\r
31 if(!CreatePipe(&hRead,&hWrite,&sa,0))
\r
33 return GIT_ERROR_OPEN_PIP;
\r
38 hStdioFile=CreateFile(*StdioFile,GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE,
\r
39 &sa,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
\r
43 PROCESS_INFORMATION pi;
\r
44 si.cb=sizeof(STARTUPINFO);
\r
45 GetStartupInfo(&si);
\r
47 si.hStdError=hWrite;
\r
49 si.hStdOutput=hStdioFile;
\r
51 si.hStdOutput=hWrite;
\r
53 si.wShowWindow=SW_HIDE;
\r
54 si.dwFlags=STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
\r
56 if(!CreateProcess(NULL,(LPWSTR)cmd.GetString(), NULL,NULL,TRUE,NULL,NULL,(LPWSTR)m_CurrentDir.GetString(),&si,&pi))
\r
59 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
\r
60 NULL,GetLastError(),MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
\r
63 return GIT_ERROR_CREATE_PROCESS;
\r
66 CloseHandle(hWrite);
\r
75 //Must use sperate function to convert ANSI str to union code string
\r
76 //Becuase A2W use stack as internal convert buffer.
\r
77 void CGit::StringAppend(CString *str,BYTE *p,int code,int length)
\r
80 //str->Append(A2W_CP((LPCSTR)p,code));
\r
85 len= strlen((const char*)p);
\r
90 //buf = new WCHAR[len*4 + 1];
\r
91 buf = str->GetBuffer(len*4+1+str->GetLength())+str->GetLength();
\r
92 SecureZeroMemory(buf, (len*4 + 1)*sizeof(WCHAR));
\r
93 MultiByteToWideChar(code, 0, (LPCSTR)p, len, buf, len*4);
\r
94 str->ReleaseBuffer();
\r
98 BOOL CGit::IsInitRepos()
\r
102 if(g_Git.Run(_T("git.exe rev-parse --revs-only HEAD"),&cmdout,CP_UTF8))
\r
104 // CMessageBox::Show(NULL,cmdout,_T("TortoiseGit"),MB_OK);
\r
107 if(cmdout.IsEmpty())
\r
112 int CGit::Run(CString cmd,BYTE_VECTOR *vector)
\r
114 PROCESS_INFORMATION pi;
\r
116 if(RunAsync(cmd,&pi,&hRead))
\r
117 return GIT_ERROR_CREATE_PROCESS;
\r
121 while(ReadFile(hRead,&data,1,&readnumber,NULL))
\r
123 //g_Buffer[readnumber]=0;
\r
124 vector->push_back(data);
\r
125 // StringAppend(output,g_Buffer,codes);
\r
129 CloseHandle(pi.hThread);
\r
131 WaitForSingleObject(pi.hProcess, INFINITE);
\r
134 if(!GetExitCodeProcess(pi.hProcess,&exitcode))
\r
136 return GIT_ERROR_GET_EXIT_CODE;
\r
139 CloseHandle(pi.hProcess);
\r
141 CloseHandle(hRead);
\r
145 int CGit::Run(CString cmd, CString* output,int code)
\r
147 BYTE_VECTOR vector;
\r
149 ret=Run(cmd,&vector);
\r
154 vector.push_back(0);
\r
156 StringAppend(output,&(vector[0]),code);
\r
160 CString CGit::GetUserName(void)
\r
163 Run(_T("git.exe config user.name"),&UserName,CP_UTF8);
\r
166 CString CGit::GetUserEmail(void)
\r
169 Run(_T("git.exe config user.email"),&UserName,CP_UTF8);
\r
173 CString CGit::GetCurrentBranch(void)
\r
176 //Run(_T("git.exe branch"),&branch);
\r
178 int ret=g_Git.Run(_T("git.exe branch"),&output,CP_UTF8);
\r
186 one=output.Tokenize(_T("\n"),pos);
\r
187 //list.push_back(one.Right(one.GetLength()-2));
\r
188 if(one[0] == _T('*'))
\r
189 return one.Right(one.GetLength()-2);
\r
192 return CString("");
\r
195 int CGit::BuildOutputFormat(CString &format,bool IsFull)
\r
198 log.Format(_T("#<%c>%%x00"),LOG_REV_ITEM_BEGIN);
\r
202 log.Format(_T("#<%c>%%an%%x00"),LOG_REV_AUTHOR_NAME);
\r
204 log.Format(_T("#<%c>%%ae%%x00"),LOG_REV_AUTHOR_EMAIL);
\r
206 log.Format(_T("#<%c>%%ai%%x00"),LOG_REV_AUTHOR_DATE);
\r
208 log.Format(_T("#<%c>%%cn%%x00"),LOG_REV_COMMIT_NAME);
\r
210 log.Format(_T("#<%c>%%ce%%x00"),LOG_REV_COMMIT_EMAIL);
\r
212 log.Format(_T("#<%c>%%ci%%x00"),LOG_REV_COMMIT_DATE);
\r
214 log.Format(_T("#<%c>%%s%%x00"),LOG_REV_COMMIT_SUBJECT);
\r
216 log.Format(_T("#<%c>%%b%%x00"),LOG_REV_COMMIT_BODY);
\r
219 log.Format(_T("#<%c>%%m%%H%%x00"),LOG_REV_COMMIT_HASH);
\r
221 log.Format(_T("#<%c>%%P%%x00"),LOG_REV_COMMIT_PARENT);
\r
226 log.Format(_T("#<%c>%%x00"),LOG_REV_COMMIT_FILE);
\r
232 int CGit::GetLog(BYTE_VECTOR& logOut, CString &hash, CTGitPath *path ,int count,int mask)
\r
243 file.Format(_T(" -- \"%s\""),path->GetGitPathString());
\r
246 num.Format(_T("-n%d"),count);
\r
250 if(mask& LOG_INFO_STAT )
\r
251 param += _T(" --numstat ");
\r
252 if(mask& LOG_INFO_FILESTATE)
\r
253 param += _T(" --raw ");
\r
255 if(mask& LOG_INFO_FULLHISTORY)
\r
256 param += _T(" --full-history ");
\r
258 if(mask& LOG_INFO_BOUNDARY)
\r
259 param += _T(" --left-right --boundary ");
\r
261 if(mask& CGit::LOG_INFO_ALL_BRANCH)
\r
262 param += _T(" --all ");
\r
264 if(mask& CGit::LOG_INFO_DETECT_COPYRENAME)
\r
265 param += _T(" -C ");
\r
267 if(mask& CGit::LOG_INFO_DETECT_RENAME )
\r
268 param += _T(" -M ");
\r
270 if(mask& CGit::LOG_INFO_FIRST_PARENT )
\r
271 param += _T(" --first-parent ");
\r
273 if(mask& CGit::LOG_INFO_NO_MERGE )
\r
274 param += _T(" --no-merges ");
\r
276 if(mask& CGit::LOG_INFO_FOLLOW)
\r
277 param += _T(" --follow ");
\r
281 cmd.Format(_T("git.exe log %s -z --topo-order %s --parents --pretty=format:\""),
\r
284 BuildOutputFormat(log,!(mask&CGit::LOG_INFO_ONLY_HASH));
\r
287 cmd += CString(_T("\" "))+hash+file;
\r
289 return Run(cmd,&logOut);
\r
293 int CGit::GetShortLog(CString &logOut,CTGitPath * path, int count)
\r
302 cmd.Format(_T("git.exe log --left-right --boundary --topo-order -n%d --pretty=format:\""),n);
\r
303 BuildOutputFormat(log,false);
\r
304 cmd += log+_T("\"");
\r
306 cmd+= _T(" -- \"")+path->GetGitPathString()+_T("\"");
\r
307 //cmd += CString(_T("\" HEAD~40..HEAD"));
\r
308 return Run(cmd,&logOut);
\r
312 #define BUFSIZE 512
\r
313 void GetTempPath(CString &path)
\r
315 TCHAR lpPathBuffer[BUFSIZE];
\r
317 DWORD dwBufSize=BUFSIZE;
\r
318 dwRetVal = GetTempPath(dwBufSize, // length of the buffer
\r
319 lpPathBuffer); // buffer for path
\r
320 if (dwRetVal > dwBufSize || (dwRetVal == 0))
\r
324 path.Format(_T("%s"),lpPathBuffer);
\r
326 CString GetTempFile()
\r
328 TCHAR lpPathBuffer[BUFSIZE];
\r
330 DWORD dwBufSize=BUFSIZE;
\r
331 TCHAR szTempName[BUFSIZE];
\r
334 dwRetVal = GetTempPath(dwBufSize, // length of the buffer
\r
335 lpPathBuffer); // buffer for path
\r
336 if (dwRetVal > dwBufSize || (dwRetVal == 0))
\r
340 // Create a temporary file.
\r
341 uRetVal = GetTempFileName(lpPathBuffer, // directory for tmp files
\r
342 TEXT("Patch"), // temp file name prefix
\r
343 0, // create unique name
\r
344 szTempName); // buffer for name
\r
352 return CString(szTempName);
\r
356 int CGit::RunLogFile(CString cmd,CString &filename)
\r
359 PROCESS_INFORMATION pi;
\r
360 si.cb=sizeof(STARTUPINFO);
\r
361 GetStartupInfo(&si);
\r
363 SECURITY_ATTRIBUTES psa={sizeof(psa),NULL,TRUE};;
\r
364 psa.bInheritHandle=TRUE;
\r
366 HANDLE houtfile=CreateFile(filename,GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE,
\r
367 &psa,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
\r
370 si.wShowWindow=SW_HIDE;
\r
371 si.dwFlags=STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
\r
372 si.hStdOutput = houtfile;
\r
374 if(!CreateProcess(NULL,(LPWSTR)cmd.GetString(), NULL,NULL,TRUE,NULL,NULL,(LPWSTR)m_CurrentDir.GetString(),&si,&pi))
\r
377 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
\r
378 NULL,GetLastError(),MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
\r
381 return GIT_ERROR_CREATE_PROCESS;
\r
384 WaitForSingleObject(pi.hProcess,INFINITE);
\r
386 CloseHandle(pi.hThread);
\r
387 CloseHandle(pi.hProcess);
\r
388 CloseHandle(houtfile);
\r
389 return GIT_SUCCESS;
\r
393 git_revnum_t CGit::GetHash(CString &friendname)
\r
397 cmd.Format(_T("git.exe rev-parse %s" ),friendname);
\r
398 Run(cmd,&out,CP_UTF8);
\r
399 int pos=out.ReverseFind(_T('\n'));
\r
401 return out.Left(pos);
\r
405 int CGit::GetTagList(STRING_VECTOR &list)
\r
408 CString cmd,output;
\r
409 cmd=_T("git.exe tag -l");
\r
411 ret=g_Git.Run(cmd,&output,CP_UTF8);
\r
419 one=output.Tokenize(_T("\n"),pos);
\r
420 list.push_back(one);
\r
426 int CGit::GetBranchList(STRING_VECTOR &list,int *current,BRANCH_TYPE type)
\r
429 CString cmd,output;
\r
430 cmd=_T("git.exe branch");
\r
432 if(type==(BRANCH_LOCAL|BRANCH_REMOTE))
\r
434 else if(type==BRANCH_REMOTE)
\r
438 ret=g_Git.Run(cmd,&output,CP_UTF8);
\r
446 one=output.Tokenize(_T("\n"),pos);
\r
447 list.push_back(one.Right(one.GetLength()-2));
\r
448 if(one[0] == _T('*'))
\r
456 int CGit::GetRemoteList(STRING_VECTOR &list)
\r
459 CString cmd,output;
\r
460 cmd=_T("git.exe config --get-regexp remote.*.url");
\r
461 ret=g_Git.Run(cmd,&output,CP_UTF8);
\r
468 one=output.Tokenize(_T("\n"),pos);
\r
469 int start=one.Find(_T("."),0);
\r
473 url=one.Right(one.GetLength()-start-1);
\r
475 one=one.Left(one.Find(_T("."),0));
\r
476 list.push_back(one);
\r
483 int CGit::GetMapHashToFriendName(MAP_HASH_NAME &map)
\r
486 CString cmd,output;
\r
487 cmd=_T("git show-ref -d");
\r
488 ret=g_Git.Run(cmd,&output,CP_UTF8);
\r
495 one=output.Tokenize(_T("\n"),pos);
\r
496 int start=one.Find(_T(" "),0);
\r
500 name=one.Right(one.GetLength()-start-1);
\r
503 hash=one.Left(start);
\r
505 map[hash].push_back(name);
\r
512 BOOL CGit::CheckMsysGitDir()
\r
514 CRegString msysdir=CRegString(REG_MSYSGIT_PATH,_T(""),FALSE,HKEY_LOCAL_MACHINE);
\r
515 CString str=msysdir;
\r
518 CRegString msysinstalldir=CRegString(REG_MSYSGIT_INSTALL,_T(""),FALSE,HKEY_LOCAL_MACHINE);
\r
519 str=msysinstalldir;
\r
520 // check it has a trailing blank
\r
521 if (str.Right(1) != _T("\\"))
\r
530 //CGit::m_MsysGitPath=str;
\r
532 TCHAR *oldpath,*home;
\r
535 _tdupenv_s(&home,&size,_T("HOME"));
\r
539 _tdupenv_s(&home,&size,_T("USERPROFILE"));
\r
540 _tputenv_s(_T("HOME"),home);
\r
545 _tdupenv_s(&oldpath,&size,_T("PATH"));
\r
548 CString unterminated_path = str; // path to msysgit without semicolon
\r
549 CString oldpath_s = oldpath;
\r
550 path.Format(_T("%s;"),str);
\r
551 // check msysgit not already in path
\r
552 if ( oldpath_s.Find( path ) < 0 && oldpath_s.Right( unterminated_path.GetLength() ) != unterminated_path )
\r
554 // not already there, see if we have to take out one we added last time
\r
555 if ( ms_LastMsysGitDir != _T("") )
\r
557 // we have added one so take it out
\r
558 int index = oldpath_s.Find( ms_LastMsysGitDir );
\r
561 oldpath_s = oldpath_s.Left( index ) +
\r
562 oldpath_s.Right( oldpath_s.GetLength() - (index+ms_LastMsysGitDir.GetLength()) );
\r
565 // save the new msysdir path that we are about to add
\r
566 ms_LastMsysGitDir = path;
\r
567 // add the new one on the front of the existing path
\r
569 _tputenv_s(_T("PATH"),path);
\r
574 cmd=_T("git.exe --version");
\r
575 if(g_Git.Run(cmd,&out,CP_UTF8))
\r