Fix memory leak when add colorpages
[TortoiseGit.git] / src / Git / Git.cpp
blobc2afaaf74c7ce3e1aceba1fe9b6abe37f2869546
1 #include "StdAfx.h"
2 #include "Git.h"
3 #include "atlconv.h"
4 #include "GitRev.h"
5 #include "registry.h"
6 #include "GitConfig.h"
8 #define MAX_DIRBUFFER 1000
9 CGit g_Git;
10 CGit::CGit(void)
12 GetCurrentDirectory(MAX_DIRBUFFER,m_CurrentDir.GetBuffer(MAX_DIRBUFFER));
15 CGit::~CGit(void)
19 static char g_Buffer[4096];
21 int CGit::RunAsync(CString cmd,PROCESS_INFORMATION *piOut,HANDLE *hReadOut,CString *StdioFile)
23 SECURITY_ATTRIBUTES sa;
24 HANDLE hRead, hWrite;
25 HANDLE hStdioFile;
27 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
28 sa.lpSecurityDescriptor=NULL;
29 sa.bInheritHandle=TRUE;
30 if(!CreatePipe(&hRead,&hWrite,&sa,0))
32 return GIT_ERROR_OPEN_PIP;
35 if(StdioFile)
37 hStdioFile=CreateFile(*StdioFile,GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE,
38 &sa,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
41 STARTUPINFO si;
42 PROCESS_INFORMATION pi;
43 si.cb=sizeof(STARTUPINFO);
44 GetStartupInfo(&si);
46 si.hStdError=hWrite;
47 if(StdioFile)
48 si.hStdOutput=hStdioFile;
49 else
50 si.hStdOutput=hWrite;
52 si.wShowWindow=SW_HIDE;
53 si.dwFlags=STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
55 if(!CreateProcess(NULL,(LPWSTR)cmd.GetString(), NULL,NULL,TRUE,NULL,NULL,(LPWSTR)m_CurrentDir.GetString(),&si,&pi))
57 LPVOID lpMsgBuf;
58 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
59 NULL,GetLastError(),MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
60 (LPTSTR)&lpMsgBuf,
61 0,NULL);
62 return GIT_ERROR_CREATE_PROCESS;
65 CloseHandle(hWrite);
66 if(piOut)
67 *piOut=pi;
68 if(hReadOut)
69 *hReadOut=hRead;
71 return 0;
74 //Must use sperate function to convert ANSI str to union code string
75 //Becuase A2W use stack as internal convert buffer.
76 void CGit::StringAppend(CString *str,BYTE *p,int code)
78 USES_CONVERSION;
79 str->Append(A2W_CP((LPCSTR)p,code));
82 BOOL CGit::IsInitRepos()
84 CString cmdout;
85 cmdout.Empty();
86 if(g_Git.Run(_T("git.exe rev-parse --revs-only HEAD"),&cmdout,CP_UTF8))
88 // CMessageBox::Show(NULL,cmdout,_T("TortoiseGit"),MB_OK);
89 return TRUE;
91 if(cmdout.IsEmpty())
92 return TRUE;
94 return FALSE;
96 int CGit::Run(CString cmd,BYTE_VECTOR *vector)
98 PROCESS_INFORMATION pi;
99 HANDLE hRead;
100 if(RunAsync(cmd,&pi,&hRead))
101 return GIT_ERROR_CREATE_PROCESS;
103 DWORD readnumber;
104 BYTE data;
105 while(ReadFile(hRead,&data,1,&readnumber,NULL))
107 //g_Buffer[readnumber]=0;
108 vector->push_back(data);
109 // StringAppend(output,g_Buffer,codes);
113 CloseHandle(pi.hThread);
115 WaitForSingleObject(pi.hProcess, INFINITE);
116 DWORD exitcode =0;
118 if(!GetExitCodeProcess(pi.hProcess,&exitcode))
120 return GIT_ERROR_GET_EXIT_CODE;
123 CloseHandle(pi.hProcess);
125 CloseHandle(hRead);
126 return exitcode;
129 int CGit::Run(CString cmd, CString* output,int code)
131 BYTE_VECTOR vector;
132 int ret;
133 ret=Run(cmd,&vector);
135 if(ret)
136 return ret;
138 vector.push_back(0);
139 StringAppend(output,&(vector[0]),code);
140 return 0;
143 CString CGit::GetUserName(void)
145 CString UserName;
146 Run(_T("git.exe config user.name"),&UserName,CP_UTF8);
147 return UserName;
149 CString CGit::GetUserEmail(void)
151 CString UserName;
152 Run(_T("git.exe config user.email"),&UserName,CP_UTF8);
153 return UserName;
156 CString CGit::GetCurrentBranch(void)
158 CString output;
159 //Run(_T("git.exe branch"),&branch);
161 int ret=g_Git.Run(_T("git.exe branch"),&output,CP_UTF8);
162 if(!ret)
164 int pos=0;
165 CString one;
166 while( pos>=0 )
168 //i++;
169 one=output.Tokenize(_T("\n"),pos);
170 //list.push_back(one.Right(one.GetLength()-2));
171 if(one[0] == _T('*'))
172 return one.Right(one.GetLength()-2);
175 return CString("");
178 int CGit::BuildOutputFormat(CString &format,bool IsFull)
180 CString log;
181 log.Format(_T("#<%c>%%x00"),LOG_REV_ITEM_BEGIN);
182 format += log;
183 if(IsFull)
185 log.Format(_T("#<%c>%%an%%x00"),LOG_REV_AUTHOR_NAME);
186 format += log;
187 log.Format(_T("#<%c>%%ae%%x00"),LOG_REV_AUTHOR_EMAIL);
188 format += log;
189 log.Format(_T("#<%c>%%ai%%x00"),LOG_REV_AUTHOR_DATE);
190 format += log;
191 log.Format(_T("#<%c>%%cn%%x00"),LOG_REV_COMMIT_NAME);
192 format += log;
193 log.Format(_T("#<%c>%%ce%%x00"),LOG_REV_COMMIT_EMAIL);
194 format += log;
195 log.Format(_T("#<%c>%%ci%%x00"),LOG_REV_COMMIT_DATE);
196 format += log;
197 log.Format(_T("#<%c>%%s%%x00"),LOG_REV_COMMIT_SUBJECT);
198 format += log;
199 log.Format(_T("#<%c>%%b%%x00"),LOG_REV_COMMIT_BODY);
200 format += log;
202 log.Format(_T("#<%c>%%m%%H%%x00"),LOG_REV_COMMIT_HASH);
203 format += log;
204 log.Format(_T("#<%c>%%P%%x00"),LOG_REV_COMMIT_PARENT);
205 format += log;
207 if(IsFull)
209 log.Format(_T("#<%c>%%x00"),LOG_REV_COMMIT_FILE);
210 format += log;
212 return 0;
215 int CGit::GetLog(BYTE_VECTOR& logOut, CString &hash, CTGitPath *path ,int count,int mask)
218 CString cmd;
219 CString log;
220 CString num;
221 CString since;
223 CString file;
225 if(path)
226 file.Format(_T(" -- \"%s\""),path->GetGitPathString());
228 if(count>0)
229 num.Format(_T("-n%d"),count);
231 CString param;
233 if(mask& LOG_INFO_STAT )
234 param += _T(" --numstat ");
235 if(mask& LOG_INFO_FILESTATE)
236 param += _T(" --raw ");
238 if(mask& LOG_INFO_FULLHISTORY)
239 param += _T(" --full-history ");
241 if(mask& LOG_INFO_BOUNDARY)
242 param += _T(" --left-right --boundary ");
244 if(mask& CGit::LOG_INFO_ALL_BRANCH)
245 param += _T(" --all ");
247 if(mask& CGit::LOG_INFO_DETECT_COPYRENAME)
248 param += _T(" -C ");
250 if(mask& CGit::LOG_INFO_DETECT_RENAME )
251 param += _T(" -M ");
253 param+=hash;
255 cmd.Format(_T("git.exe log %s -z --topo-order --parents %s --pretty=format:\""),
256 num,param);
258 BuildOutputFormat(log,!(mask&CGit::LOG_INFO_ONLY_HASH));
260 cmd += log;
261 cmd += CString(_T("\" "))+hash+file;
263 return Run(cmd,&logOut);
266 #if 0
267 int CGit::GetShortLog(CString &logOut,CTGitPath * path, int count)
269 CString cmd;
270 CString log;
271 int n;
272 if(count<0)
273 n=100;
274 else
275 n=count;
276 cmd.Format(_T("git.exe log --left-right --boundary --topo-order -n%d --pretty=format:\""),n);
277 BuildOutputFormat(log,false);
278 cmd += log+_T("\"");
279 if (path)
280 cmd+= _T(" -- \"")+path->GetGitPathString()+_T("\"");
281 //cmd += CString(_T("\" HEAD~40..HEAD"));
282 return Run(cmd,&logOut);
284 #endif
286 #define BUFSIZE 512
287 void GetTempPath(CString &path)
289 TCHAR lpPathBuffer[BUFSIZE];
290 DWORD dwRetVal;
291 DWORD dwBufSize=BUFSIZE;
292 dwRetVal = GetTempPath(dwBufSize, // length of the buffer
293 lpPathBuffer); // buffer for path
294 if (dwRetVal > dwBufSize || (dwRetVal == 0))
296 path=_T("");
298 path.Format(_T("%s"),lpPathBuffer);
300 CString GetTempFile()
302 TCHAR lpPathBuffer[BUFSIZE];
303 DWORD dwRetVal;
304 DWORD dwBufSize=BUFSIZE;
305 TCHAR szTempName[BUFSIZE];
306 UINT uRetVal;
308 dwRetVal = GetTempPath(dwBufSize, // length of the buffer
309 lpPathBuffer); // buffer for path
310 if (dwRetVal > dwBufSize || (dwRetVal == 0))
312 return _T("");
314 // Create a temporary file.
315 uRetVal = GetTempFileName(lpPathBuffer, // directory for tmp files
316 TEXT("Patch"), // temp file name prefix
317 0, // create unique name
318 szTempName); // buffer for name
321 if (uRetVal == 0)
323 return _T("");
326 return CString(szTempName);
330 int CGit::RunLogFile(CString cmd,CString &filename)
332 HANDLE hRead, hWrite;
334 STARTUPINFO si;
335 PROCESS_INFORMATION pi;
336 si.cb=sizeof(STARTUPINFO);
337 GetStartupInfo(&si);
339 SECURITY_ATTRIBUTES psa={sizeof(psa),NULL,TRUE};;
340 psa.bInheritHandle=TRUE;
342 HANDLE houtfile=CreateFile(filename,GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE,
343 &psa,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
346 si.wShowWindow=SW_HIDE;
347 si.dwFlags=STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
348 si.hStdOutput = houtfile;
350 if(!CreateProcess(NULL,(LPWSTR)cmd.GetString(), NULL,NULL,TRUE,NULL,NULL,(LPWSTR)m_CurrentDir.GetString(),&si,&pi))
352 LPVOID lpMsgBuf;
353 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
354 NULL,GetLastError(),MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
355 (LPTSTR)&lpMsgBuf,
356 0,NULL);
357 return GIT_ERROR_CREATE_PROCESS;
360 WaitForSingleObject(pi.hProcess,INFINITE);
362 CloseHandle(pi.hThread);
363 CloseHandle(pi.hProcess);
364 CloseHandle(houtfile);
365 return GIT_SUCCESS;
366 return 0;
369 git_revnum_t CGit::GetHash(CString &friendname)
371 CString cmd;
372 CString out;
373 cmd.Format(_T("git.exe rev-parse %s" ),friendname);
374 Run(cmd,&out,CP_UTF8);
375 int pos=out.ReverseFind(_T('\n'));
376 if(pos>0)
377 return out.Left(pos);
378 return out;
381 int CGit::GetTagList(STRING_VECTOR &list)
383 int ret;
384 CString cmd,output;
385 cmd=_T("git.exe tag -l");
386 int i=0;
387 ret=g_Git.Run(cmd,&output,CP_UTF8);
388 if(!ret)
390 int pos=0;
391 CString one;
392 while( pos>=0 )
394 i++;
395 one=output.Tokenize(_T("\n"),pos);
396 list.push_back(one);
399 return ret;
402 int CGit::GetBranchList(STRING_VECTOR &list,int *current,BRANCH_TYPE type)
404 int ret;
405 CString cmd,output;
406 cmd=_T("git.exe branch");
408 if(type==(BRANCH_LOCAL|BRANCH_REMOTE))
409 cmd+=_T(" -a");
410 else if(type==BRANCH_REMOTE)
411 cmd+=_T(" -r");
413 int i=0;
414 ret=g_Git.Run(cmd,&output,CP_UTF8);
415 if(!ret)
417 int pos=0;
418 CString one;
419 while( pos>=0 )
421 i++;
422 one=output.Tokenize(_T("\n"),pos);
423 list.push_back(one.Right(one.GetLength()-2));
424 if(one[0] == _T('*'))
425 if(current)
426 *current=i;
429 return ret;
432 int CGit::GetRemoteList(STRING_VECTOR &list)
434 int ret;
435 CString cmd,output;
436 cmd=_T("git.exe config --get-regexp remote.*.url");
437 ret=g_Git.Run(cmd,&output,CP_UTF8);
438 if(!ret)
440 int pos=0;
441 CString one;
442 while( pos>=0 )
444 one=output.Tokenize(_T("\n"),pos);
445 int start=one.Find(_T("."),0);
446 if(start>0)
448 CString url;
449 url=one.Right(one.GetLength()-start-1);
450 one=url;
451 one=one.Left(one.Find(_T("."),0));
452 list.push_back(one);
456 return ret;
459 int CGit::GetMapHashToFriendName(MAP_HASH_NAME &map)
461 int ret;
462 CString cmd,output;
463 cmd=_T("git show-ref -d");
464 ret=g_Git.Run(cmd,&output,CP_UTF8);
465 if(!ret)
467 int pos=0;
468 CString one;
469 while( pos>=0 )
471 one=output.Tokenize(_T("\n"),pos);
472 int start=one.Find(_T(" "),0);
473 if(start>0)
475 CString name;
476 name=one.Right(one.GetLength()-start-1);
478 CString hash;
479 hash=one.Left(start);
481 map[hash].push_back(name);
485 return ret;
488 BOOL CGit::CheckMsysGitDir()
490 CRegString msysdir=CRegString(REG_MSYSGIT_PATH,_T(""),FALSE,HKEY_LOCAL_MACHINE);
491 CString str=msysdir;
492 if(str.IsEmpty())
494 CRegString msysinstalldir=CRegString(REG_MSYSGIT_INSTALL,_T(""),FALSE,HKEY_LOCAL_MACHINE);
495 str=msysinstalldir;
496 str+="\\bin";
497 msysdir=str;
498 msysdir.write();
501 //CGit::m_MsysGitPath=str;
503 TCHAR *oldpath,*home;
504 size_t size;
506 _tdupenv_s(&home,&size,_T("HOME"));
508 if(home == NULL)
510 _tdupenv_s(&home,&size,_T("USERPROFILE"));
511 _tputenv_s(_T("HOME"),home);
512 free(home);
514 //set path
515 _tdupenv_s(&oldpath,&size,_T("PATH"));
517 CString path;
518 path.Format(_T("%s;"),str);
519 path+=oldpath;
521 _tputenv_s(_T("PATH"),path);
523 free(oldpath);
525 CString cmd,out;
526 cmd=_T("git.exe --version");
527 if(g_Git.Run(cmd,&out,CP_UTF8))
529 return false;
531 else
532 return true;