Add show one file log at dialog box.
[TortoiseGit.git] / src / Git / Git.cpp
blobd81542bb5e284f5e6cda65dd95569ce7282ad5d3
1 #include "StdAfx.h"
2 #include "Git.h"
3 #include "atlconv.h"
4 #include "GitRev.h"
5 #include "registry.h"
7 #define MAX_DIRBUFFER 1000
8 CGit g_Git;
9 CGit::CGit(void)
11 GetCurrentDirectory(MAX_DIRBUFFER,m_CurrentDir.GetBuffer(MAX_DIRBUFFER));
14 CGit::~CGit(void)
18 static char g_Buffer[4096];
20 int CGit::RunAsync(CString cmd,PROCESS_INFORMATION *piOut,HANDLE *hReadOut,CString *StdioFile)
22 SECURITY_ATTRIBUTES sa;
23 HANDLE hRead, hWrite;
24 HANDLE hStdioFile;
26 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
27 sa.lpSecurityDescriptor=NULL;
28 sa.bInheritHandle=TRUE;
29 if(!CreatePipe(&hRead,&hWrite,&sa,0))
31 return GIT_ERROR_OPEN_PIP;
34 if(StdioFile)
36 hStdioFile=CreateFile(*StdioFile,GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE,
37 &sa,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
40 STARTUPINFO si;
41 PROCESS_INFORMATION pi;
42 si.cb=sizeof(STARTUPINFO);
43 GetStartupInfo(&si);
45 si.hStdError=hWrite;
46 if(StdioFile)
47 si.hStdOutput=hStdioFile;
48 else
49 si.hStdOutput=hWrite;
51 si.wShowWindow=SW_HIDE;
52 si.dwFlags=STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
54 if(!CreateProcess(NULL,(LPWSTR)cmd.GetString(), NULL,NULL,TRUE,NULL,NULL,(LPWSTR)m_CurrentDir.GetString(),&si,&pi))
56 LPVOID lpMsgBuf;
57 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
58 NULL,GetLastError(),MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
59 (LPTSTR)&lpMsgBuf,
60 0,NULL);
61 return GIT_ERROR_CREATE_PROCESS;
64 CloseHandle(hWrite);
65 if(piOut)
66 *piOut=pi;
67 if(hReadOut)
68 *hReadOut=hRead;
70 return 0;
73 //Must use sperate function to convert ANSI str to union code string
74 //Becuase A2W use stack as internal convert buffer.
75 void CGit::StringAppend(CString *str,char *p)
77 USES_CONVERSION;
78 str->Append(A2W_CP(p,CP_UTF8));
81 BOOL CGit::IsInitRepos()
83 CString cmdout;
84 cmdout.Empty();
85 if(g_Git.Run(_T("git.exe rev-parse --revs-only HEAD"),&cmdout))
87 // CMessageBox::Show(NULL,cmdout,_T("TortoiseGit"),MB_OK);
88 return TRUE;
90 if(cmdout.IsEmpty())
91 return TRUE;
93 return FALSE;
95 int CGit::Run(CString cmd, CString* output)
97 PROCESS_INFORMATION pi;
98 HANDLE hRead;
99 if(RunAsync(cmd,&pi,&hRead))
100 return GIT_ERROR_CREATE_PROCESS;
102 DWORD readnumber;
103 while(ReadFile(hRead,g_Buffer,1023,&readnumber,NULL))
105 g_Buffer[readnumber]=0;
106 StringAppend(output,g_Buffer);
110 CloseHandle(pi.hThread);
112 WaitForSingleObject(pi.hProcess, INFINITE);
113 DWORD exitcode =0;
115 if(!GetExitCodeProcess(pi.hProcess,&exitcode))
117 return GIT_ERROR_GET_EXIT_CODE;
120 CloseHandle(pi.hProcess);
122 CloseHandle(hRead);
123 return exitcode;
126 CString CGit::GetUserName(void)
128 CString UserName;
129 Run(_T("git.exe config user.name"),&UserName);
130 return UserName;
132 CString CGit::GetUserEmail(void)
134 CString UserName;
135 Run(_T("git.exe config user.email"),&UserName);
136 return UserName;
139 CString CGit::GetCurrentBranch(void)
141 CString output;
142 //Run(_T("git.exe branch"),&branch);
144 int ret=g_Git.Run(_T("git.exe branch"),&output);
145 if(!ret)
147 int pos=0;
148 CString one;
149 while( pos>=0 )
151 //i++;
152 one=output.Tokenize(_T("\n"),pos);
153 //list.push_back(one.Right(one.GetLength()-2));
154 if(one[0] == _T('*'))
155 return one.Right(one.GetLength()-2);
158 return CString("");
161 int CGit::BuildOutputFormat(CString &format,bool IsFull)
163 CString log;
164 log.Format(_T("#<%c>%%n"),LOG_REV_ITEM_BEGIN);
165 format += log;
166 if(IsFull)
168 log.Format(_T("#<%c>%%an%%n"),LOG_REV_AUTHOR_NAME);
169 format += log;
170 log.Format(_T("#<%c>%%ae%%n"),LOG_REV_AUTHOR_EMAIL);
171 format += log;
172 log.Format(_T("#<%c>%%ai%%n"),LOG_REV_AUTHOR_DATE);
173 format += log;
174 log.Format(_T("#<%c>%%cn%%n"),LOG_REV_COMMIT_NAME);
175 format += log;
176 log.Format(_T("#<%c>%%ce%%n"),LOG_REV_COMMIT_EMAIL);
177 format += log;
178 log.Format(_T("#<%c>%%ci%%n"),LOG_REV_COMMIT_DATE);
179 format += log;
180 log.Format(_T("#<%c>%%s%%n"),LOG_REV_COMMIT_SUBJECT);
181 format += log;
182 log.Format(_T("#<%c>%%b%%n"),LOG_REV_COMMIT_BODY);
183 format += log;
185 log.Format(_T("#<%c>%%m%%H%%n"),LOG_REV_COMMIT_HASH);
186 format += log;
187 log.Format(_T("#<%c>%%P%%n"),LOG_REV_COMMIT_PARENT);
188 format += log;
190 if(IsFull)
192 log.Format(_T("#<%c>%%n"),LOG_REV_COMMIT_FILE);
193 format += log;
195 return 0;
198 int CGit::GetLog(CString& logOut, CString &hash, CTGitPath *path ,int count,int mask)
201 CString cmd;
202 CString log;
203 CString num;
204 CString since;
206 CString file;
208 if(path)
209 file.Format(_T(" -- \"%s\""),path->GetGitPathString());
211 if(count>0)
212 num.Format(_T("-n%d"),count);
214 CString param;
216 if(mask& LOG_INFO_STAT )
217 param += _T(" --numstat ");
218 if(mask& LOG_INFO_FILESTATE)
219 param += _T(" --raw ");
221 if(mask& LOG_INFO_FULLHISTORY)
222 param += _T(" --full-history ");
224 if(mask& LOG_INFO_BOUNDARY)
225 param += _T(" --left-right --boundary ");
227 if(mask& CGit::LOG_INFO_ALL_BRANCH)
228 param += _T(" --all ");
230 if(mask& CGit::LOG_INFO_DETECT_COPYRENAME)
231 param += _T(" -C ");
233 if(mask& CGit::LOG_INFO_DETECT_RENAME )
234 param += _T(" -M ");
236 param+=hash;
238 cmd.Format(_T("git.exe log %s --topo-order --parents %s --pretty=format:\""),
239 num,param);
241 BuildOutputFormat(log,!(mask&CGit::LOG_INFO_ONLY_HASH));
243 cmd += log;
244 cmd += CString(_T("\" "))+hash+file;
246 return Run(cmd,&logOut);
249 #if 0
250 int CGit::GetShortLog(CString &logOut,CTGitPath * path, int count)
252 CString cmd;
253 CString log;
254 int n;
255 if(count<0)
256 n=100;
257 else
258 n=count;
259 cmd.Format(_T("git.exe log --left-right --boundary --topo-order -n%d --pretty=format:\""),n);
260 BuildOutputFormat(log,false);
261 cmd += log+_T("\"");
262 if (path)
263 cmd+= _T(" -- \"")+path->GetGitPathString()+_T("\"");
264 //cmd += CString(_T("\" HEAD~40..HEAD"));
265 return Run(cmd,&logOut);
267 #endif
269 #define BUFSIZE 512
270 void GetTempPath(CString &path)
272 TCHAR lpPathBuffer[BUFSIZE];
273 DWORD dwRetVal;
274 DWORD dwBufSize=BUFSIZE;
275 dwRetVal = GetTempPath(dwBufSize, // length of the buffer
276 lpPathBuffer); // buffer for path
277 if (dwRetVal > dwBufSize || (dwRetVal == 0))
279 path=_T("");
281 path.Format(_T("%s"),lpPathBuffer);
283 CString GetTempFile()
285 TCHAR lpPathBuffer[BUFSIZE];
286 DWORD dwRetVal;
287 DWORD dwBufSize=BUFSIZE;
288 TCHAR szTempName[BUFSIZE];
289 UINT uRetVal;
291 dwRetVal = GetTempPath(dwBufSize, // length of the buffer
292 lpPathBuffer); // buffer for path
293 if (dwRetVal > dwBufSize || (dwRetVal == 0))
295 return _T("");
297 // Create a temporary file.
298 uRetVal = GetTempFileName(lpPathBuffer, // directory for tmp files
299 TEXT("Patch"), // temp file name prefix
300 0, // create unique name
301 szTempName); // buffer for name
304 if (uRetVal == 0)
306 return _T("");
309 return CString(szTempName);
313 int CGit::RunLogFile(CString cmd,CString &filename)
315 HANDLE hRead, hWrite;
317 STARTUPINFO si;
318 PROCESS_INFORMATION pi;
319 si.cb=sizeof(STARTUPINFO);
320 GetStartupInfo(&si);
322 SECURITY_ATTRIBUTES psa={sizeof(psa),NULL,TRUE};;
323 psa.bInheritHandle=TRUE;
325 HANDLE houtfile=CreateFile(filename,GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE,
326 &psa,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
329 si.wShowWindow=SW_HIDE;
330 si.dwFlags=STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
331 si.hStdOutput = houtfile;
333 if(!CreateProcess(NULL,(LPWSTR)cmd.GetString(), NULL,NULL,TRUE,NULL,NULL,(LPWSTR)m_CurrentDir.GetString(),&si,&pi))
335 LPVOID lpMsgBuf;
336 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
337 NULL,GetLastError(),MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
338 (LPTSTR)&lpMsgBuf,
339 0,NULL);
340 return GIT_ERROR_CREATE_PROCESS;
343 WaitForSingleObject(pi.hProcess,INFINITE);
345 CloseHandle(pi.hThread);
346 CloseHandle(pi.hProcess);
347 CloseHandle(houtfile);
348 return GIT_SUCCESS;
349 return 0;
352 git_revnum_t CGit::GetHash(CString &friendname)
354 CString cmd;
355 CString out;
356 cmd.Format(_T("git.exe rev-parse %s" ),friendname);
357 Run(cmd,&out);
358 int pos=out.ReverseFind(_T('\n'));
359 if(pos>0)
360 return out.Left(pos);
361 return out;
364 int CGit::GetTagList(STRING_VECTOR &list)
366 int ret;
367 CString cmd,output;
368 cmd=_T("git.exe tag -l");
369 int i=0;
370 ret=g_Git.Run(cmd,&output);
371 if(!ret)
373 int pos=0;
374 CString one;
375 while( pos>=0 )
377 i++;
378 one=output.Tokenize(_T("\n"),pos);
379 list.push_back(one);
382 return ret;
385 int CGit::GetBranchList(STRING_VECTOR &list,int *current,BRANCH_TYPE type)
387 int ret;
388 CString cmd,output;
389 cmd=_T("git.exe branch");
391 if(type==(BRANCH_LOCAL|BRANCH_REMOTE))
392 cmd+=_T(" -a");
393 else if(type==BRANCH_REMOTE)
394 cmd+=_T(" -r");
396 int i=0;
397 ret=g_Git.Run(cmd,&output);
398 if(!ret)
400 int pos=0;
401 CString one;
402 while( pos>=0 )
404 i++;
405 one=output.Tokenize(_T("\n"),pos);
406 list.push_back(one.Right(one.GetLength()-2));
407 if(one[0] == _T('*'))
408 if(current)
409 *current=i;
412 return ret;
415 int CGit::GetRemoteList(STRING_VECTOR &list)
417 int ret;
418 CString cmd,output;
419 cmd=_T("git.exe config --get-regexp remote.*.url");
420 ret=g_Git.Run(cmd,&output);
421 if(!ret)
423 int pos=0;
424 CString one;
425 while( pos>=0 )
427 one=output.Tokenize(_T("\n"),pos);
428 int start=one.Find(_T("."),0);
429 if(start>0)
431 CString url;
432 url=one.Right(one.GetLength()-start-1);
433 one=url;
434 one=one.Left(one.Find(_T("."),0));
435 list.push_back(one);
439 return ret;
442 int CGit::GetMapHashToFriendName(MAP_HASH_NAME &map)
444 int ret;
445 CString cmd,output;
446 cmd=_T("git show-ref -d");
447 ret=g_Git.Run(cmd,&output);
448 if(!ret)
450 int pos=0;
451 CString one;
452 while( pos>=0 )
454 one=output.Tokenize(_T("\n"),pos);
455 int start=one.Find(_T(" "),0);
456 if(start>0)
458 CString name;
459 name=one.Right(one.GetLength()-start-1);
461 CString hash;
462 hash=one.Left(start);
464 map[hash].push_back(name);
468 return ret;
471 BOOL CGit::CheckMsysGitDir()
473 CRegString msysdir=CRegString(_T("Software\\TortoiseGit\\MSysGit"),_T(""),FALSE,HKEY_LOCAL_MACHINE);
474 CString str=msysdir;
475 if(str.IsEmpty())
477 CRegString msysinstalldir=CRegString(_T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Git_is1\\InstallLocation"),_T(""),FALSE,HKEY_LOCAL_MACHINE);
478 str=msysinstalldir;
479 str+="\\bin";
480 msysdir=str;
481 msysdir.write();
484 //CGit::m_MsysGitPath=str;
486 TCHAR *oldpath,*home;
487 size_t size;
489 _tdupenv_s(&home,&size,_T("HOME"));
491 if(home == NULL)
493 _tdupenv_s(&home,&size,_T("USERPROFILE"));
494 _tputenv_s(_T("HOME"),home);
495 free(home);
497 //set path
498 _tdupenv_s(&oldpath,&size,_T("PATH"));
500 CString path;
501 path.Format(_T("%s;"),str);
502 path+=oldpath;
504 _tputenv_s(_T("PATH"),path);
506 free(oldpath);
508 CString cmd,out;
509 cmd=_T("git.exe --version");
510 if(g_Git.Run(cmd,&out))
512 return false;
514 else
515 return true;