OSDN Git Service

Share resource file between TortoiseGitBlame and TortoiseProc
[tortoisegit/TortoiseGitJp.git] / src / Git / Git.cpp
1 #include "StdAfx.h"\r
2 #include "Git.h"\r
3 #include "atlconv.h"\r
4 #include "GitRev.h"\r
5 #include "registry.h"\r
6 \r
7 #define MAX_DIRBUFFER 1000\r
8 CGit g_Git;\r
9 CGit::CGit(void)\r
10 {\r
11         GetCurrentDirectory(MAX_DIRBUFFER,m_CurrentDir.GetBuffer(MAX_DIRBUFFER));\r
12 }\r
13 \r
14 CGit::~CGit(void)\r
15 {\r
16 }\r
17 \r
18 static char g_Buffer[4096];\r
19 \r
20 int CGit::RunAsync(CString cmd,PROCESS_INFORMATION *piOut,HANDLE *hReadOut,CString *StdioFile)\r
21 {\r
22         SECURITY_ATTRIBUTES sa;\r
23         HANDLE hRead, hWrite;\r
24         HANDLE hStdioFile;\r
25 \r
26         sa.nLength = sizeof(SECURITY_ATTRIBUTES);\r
27         sa.lpSecurityDescriptor=NULL;\r
28         sa.bInheritHandle=TRUE;\r
29         if(!CreatePipe(&hRead,&hWrite,&sa,0))\r
30         {\r
31                 return GIT_ERROR_OPEN_PIP;\r
32         }\r
33         \r
34         if(StdioFile)\r
35         {\r
36                 hStdioFile=CreateFile(*StdioFile,GENERIC_WRITE,FILE_SHARE_READ   |   FILE_SHARE_WRITE,   \r
37                         &sa,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);  \r
38         }\r
39 \r
40         STARTUPINFO si;\r
41         PROCESS_INFORMATION pi;\r
42         si.cb=sizeof(STARTUPINFO);\r
43         GetStartupInfo(&si);\r
44 \r
45         si.hStdError=hWrite;\r
46         if(StdioFile)\r
47                 si.hStdOutput=hStdioFile;\r
48         else\r
49                 si.hStdOutput=hWrite;\r
50 \r
51         si.wShowWindow=SW_HIDE;\r
52         si.dwFlags=STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;\r
53 \r
54         if(!CreateProcess(NULL,(LPWSTR)cmd.GetString(), NULL,NULL,TRUE,NULL,NULL,(LPWSTR)m_CurrentDir.GetString(),&si,&pi))\r
55         {\r
56                 LPVOID lpMsgBuf;\r
57                 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,\r
58                         NULL,GetLastError(),MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),\r
59                         (LPTSTR)&lpMsgBuf,\r
60                         0,NULL);\r
61                 return GIT_ERROR_CREATE_PROCESS;\r
62         }\r
63         \r
64         CloseHandle(hWrite);\r
65         if(piOut)\r
66                 *piOut=pi;\r
67         if(hReadOut)\r
68                 *hReadOut=hRead;\r
69         \r
70         return 0;\r
71 \r
72 }\r
73 //Must use sperate function to convert ANSI str to union code string\r
74 //Becuase A2W use stack as internal convert buffer. \r
75 void CGit::StringAppend(CString *str,char *p)\r
76 {\r
77        USES_CONVERSION;\r
78        str->Append(A2W(p));\r
79 \r
80 }       \r
81 BOOL CGit::IsInitRepos()\r
82 {\r
83         CString cmdout;\r
84         cmdout.Empty();\r
85         if(g_Git.Run(_T("git.exe rev-parse --revs-only HEAD"),&cmdout))\r
86         {\r
87         //      CMessageBox::Show(NULL,cmdout,_T("TortoiseGit"),MB_OK);\r
88                 return TRUE;\r
89         }\r
90         if(cmdout.IsEmpty())\r
91                 return TRUE;\r
92 \r
93         return FALSE;\r
94 }\r
95 int CGit::Run(CString cmd, CString* output)\r
96 {\r
97         PROCESS_INFORMATION pi;\r
98         HANDLE hRead;\r
99         if(RunAsync(cmd,&pi,&hRead))\r
100                 return GIT_ERROR_CREATE_PROCESS;\r
101 \r
102         DWORD readnumber;\r
103         while(ReadFile(hRead,g_Buffer,1023,&readnumber,NULL))\r
104         {\r
105                 g_Buffer[readnumber]=0;\r
106                 StringAppend(output,g_Buffer);\r
107         }\r
108 \r
109         \r
110         CloseHandle(pi.hThread);\r
111 \r
112         WaitForSingleObject(pi.hProcess, INFINITE);\r
113         DWORD exitcode =0;\r
114 \r
115         if(!GetExitCodeProcess(pi.hProcess,&exitcode))\r
116         {\r
117                 return GIT_ERROR_GET_EXIT_CODE;\r
118         }\r
119 \r
120         CloseHandle(pi.hProcess);\r
121 \r
122         CloseHandle(hRead);\r
123         return exitcode;\r
124 }\r
125 \r
126 CString CGit::GetUserName(void)\r
127 {\r
128         CString UserName;\r
129         Run(_T("git.exe config user.name"),&UserName);\r
130         return UserName;\r
131 }\r
132 CString CGit::GetUserEmail(void)\r
133 {\r
134         CString UserName;\r
135         Run(_T("git.exe config user.email"),&UserName);\r
136         return UserName;\r
137 }\r
138 \r
139 CString CGit::GetCurrentBranch(void)\r
140 {\r
141         CString output;\r
142         //Run(_T("git.exe branch"),&branch);\r
143 \r
144         int ret=g_Git.Run(_T("git.exe branch"),&output);\r
145         if(!ret)\r
146         {               \r
147                 int pos=0;\r
148                 CString one;\r
149                 while( pos>=0 )\r
150                 {\r
151                         //i++;\r
152                         one=output.Tokenize(_T("\n"),pos);\r
153                         //list.push_back(one.Right(one.GetLength()-2));\r
154                         if(one[0] == _T('*'))\r
155                                 return one.Right(one.GetLength()-2);\r
156                 }\r
157         }\r
158         return CString("");\r
159 }\r
160 \r
161 int CGit::BuildOutputFormat(CString &format,bool IsFull)\r
162 {\r
163         CString log;\r
164         log.Format(_T("#<%c>%%n"),LOG_REV_ITEM_BEGIN);\r
165         format += log;\r
166         if(IsFull)\r
167         {\r
168                 log.Format(_T("#<%c>%%an%%n"),LOG_REV_AUTHOR_NAME);\r
169                 format += log;\r
170                 log.Format(_T("#<%c>%%ae%%n"),LOG_REV_AUTHOR_EMAIL);\r
171                 format += log;\r
172                 log.Format(_T("#<%c>%%ai%%n"),LOG_REV_AUTHOR_DATE);\r
173                 format += log;\r
174                 log.Format(_T("#<%c>%%cn%%n"),LOG_REV_COMMIT_NAME);\r
175                 format += log;\r
176                 log.Format(_T("#<%c>%%ce%%n"),LOG_REV_COMMIT_EMAIL);\r
177                 format += log;\r
178                 log.Format(_T("#<%c>%%ci%%n"),LOG_REV_COMMIT_DATE);\r
179                 format += log;\r
180                 log.Format(_T("#<%c>%%s%%n"),LOG_REV_COMMIT_SUBJECT);\r
181                 format += log;\r
182                 log.Format(_T("#<%c>%%b%%n"),LOG_REV_COMMIT_BODY);\r
183                 format += log;\r
184         }\r
185         log.Format(_T("#<%c>%%m%%H%%n"),LOG_REV_COMMIT_HASH);\r
186         format += log;\r
187         log.Format(_T("#<%c>%%P%%n"),LOG_REV_COMMIT_PARENT);\r
188         format += log;\r
189 \r
190         if(IsFull)\r
191         {\r
192                 log.Format(_T("#<%c>%%n"),LOG_REV_COMMIT_FILE);\r
193                 format += log;\r
194         }\r
195         return 0;\r
196 }\r
197 \r
198 int CGit::GetLog(CString& logOut, CString &hash,  CTGitPath *path ,int count,int mask)\r
199 {\r
200 \r
201         CString cmd;\r
202         CString log;\r
203         CString num;\r
204         CString since;\r
205 \r
206         CString file;\r
207 \r
208         if(path)\r
209                 file.Format(_T(" -- \"%s\""),path->GetGitPathString());\r
210         \r
211         if(count>0)\r
212                 num.Format(_T("-n%d"),count);\r
213 \r
214         CString param;\r
215 \r
216         if(mask& LOG_INFO_STAT )\r
217                 param += _T(" --numstat ");\r
218         if(mask& LOG_INFO_FILESTATE)\r
219                 param += _T(" --raw ");\r
220 \r
221         if(mask& LOG_INFO_FULLHISTORY)\r
222                 param += _T(" --full-history ");\r
223 \r
224         cmd.Format(_T("git.exe log %s -C --left-right --boundary --topo-order --parents %s --pretty=format:\""),\r
225                                 num,param);\r
226 \r
227         BuildOutputFormat(log);\r
228         cmd += log;\r
229         cmd += CString(_T("\"  "))+hash+file;\r
230 \r
231         return Run(cmd,&logOut);\r
232 }\r
233 \r
234 \r
235 int CGit::GetShortLog(CString &logOut,CTGitPath * path, int count)\r
236 {\r
237         CString cmd;\r
238         CString log;\r
239         int n;\r
240         if(count<0)\r
241                 n=100;\r
242         else\r
243                 n=count;\r
244         cmd.Format(_T("git.exe log --left-right --boundary --topo-order -n%d --pretty=format:\""),n);\r
245         BuildOutputFormat(log,false);\r
246         cmd += log+_T("\"");\r
247         if (path)\r
248                 cmd+= _T("  -- \"")+path->GetGitPathString()+_T("\"");\r
249         //cmd += CString(_T("\" HEAD~40..HEAD"));\r
250         return Run(cmd,&logOut);\r
251 }\r
252 \r
253 #define BUFSIZE 512\r
254 void GetTempPath(CString &path)\r
255 {\r
256         TCHAR lpPathBuffer[BUFSIZE];\r
257         DWORD dwRetVal;\r
258         DWORD dwBufSize=BUFSIZE;\r
259         dwRetVal = GetTempPath(dwBufSize,     // length of the buffer\r
260                            lpPathBuffer); // buffer for path \r
261     if (dwRetVal > dwBufSize || (dwRetVal == 0))\r
262     {\r
263         path=_T("");\r
264     }\r
265         path.Format(_T("%s"),lpPathBuffer);\r
266 }\r
267 CString GetTempFile()\r
268 {\r
269         TCHAR lpPathBuffer[BUFSIZE];\r
270         DWORD dwRetVal;\r
271     DWORD dwBufSize=BUFSIZE;\r
272         TCHAR szTempName[BUFSIZE];  \r
273         UINT uRetVal;\r
274 \r
275         dwRetVal = GetTempPath(dwBufSize,     // length of the buffer\r
276                            lpPathBuffer); // buffer for path \r
277     if (dwRetVal > dwBufSize || (dwRetVal == 0))\r
278     {\r
279         return _T("");\r
280     }\r
281          // Create a temporary file. \r
282     uRetVal = GetTempFileName(lpPathBuffer, // directory for tmp files\r
283                               TEXT("Patch"),  // temp file name prefix \r
284                               0,            // create unique name \r
285                               szTempName);  // buffer for name \r
286 \r
287 \r
288     if (uRetVal == 0)\r
289     {\r
290         return _T("");\r
291     }\r
292 \r
293         return CString(szTempName);\r
294 \r
295 }\r
296 \r
297 int CGit::RunLogFile(CString cmd,CString &filename)\r
298 {\r
299         HANDLE hRead, hWrite;\r
300 \r
301         STARTUPINFO si;\r
302         PROCESS_INFORMATION pi;\r
303         si.cb=sizeof(STARTUPINFO);\r
304         GetStartupInfo(&si);\r
305 \r
306         SECURITY_ATTRIBUTES   psa={sizeof(psa),NULL,TRUE};;   \r
307         psa.bInheritHandle=TRUE;   \r
308     \r
309         HANDLE   houtfile=CreateFile(filename,GENERIC_WRITE,FILE_SHARE_READ   |   FILE_SHARE_WRITE,   \r
310                         &psa,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);   \r
311 \r
312 \r
313         si.wShowWindow=SW_HIDE;\r
314         si.dwFlags=STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;\r
315         si.hStdOutput   =   houtfile; \r
316         \r
317         if(!CreateProcess(NULL,(LPWSTR)cmd.GetString(), NULL,NULL,TRUE,NULL,NULL,(LPWSTR)m_CurrentDir.GetString(),&si,&pi))\r
318         {\r
319                 LPVOID lpMsgBuf;\r
320                 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,\r
321                         NULL,GetLastError(),MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),\r
322                         (LPTSTR)&lpMsgBuf,\r
323                         0,NULL);\r
324                 return GIT_ERROR_CREATE_PROCESS;\r
325         }\r
326         \r
327         WaitForSingleObject(pi.hProcess,INFINITE);   \r
328         \r
329         CloseHandle(pi.hThread);\r
330         CloseHandle(pi.hProcess);\r
331         CloseHandle(houtfile);\r
332         return GIT_SUCCESS;\r
333         return 0;\r
334 }\r
335 \r
336 git_revnum_t CGit::GetHash(CString &friendname)\r
337 {\r
338         CString cmd;\r
339         CString out;\r
340         cmd.Format(_T("git.exe rev-parse %s" ),friendname);\r
341         Run(cmd,&out);\r
342         int pos=out.ReverseFind(_T('\n'));\r
343         if(pos>0)\r
344                 return out.Left(pos);\r
345         return out;\r
346 }\r
347 \r
348 int CGit::GetTagList(STRING_VECTOR &list)\r
349 {\r
350         int ret;\r
351         CString cmd,output;\r
352         cmd=_T("git.exe tag -l");\r
353         int i=0;\r
354         ret=g_Git.Run(cmd,&output);\r
355         if(!ret)\r
356         {               \r
357                 int pos=0;\r
358                 CString one;\r
359                 while( pos>=0 )\r
360                 {\r
361                         i++;\r
362                         one=output.Tokenize(_T("\n"),pos);\r
363                         list.push_back(one);\r
364                 }\r
365         }\r
366         return ret;\r
367 }\r
368 \r
369 int CGit::GetBranchList(STRING_VECTOR &list,int *current,BRANCH_TYPE type)\r
370 {\r
371         int ret;\r
372         CString cmd,output;\r
373         cmd=_T("git.exe branch");\r
374 \r
375         if(type==(BRANCH_LOCAL|BRANCH_REMOTE))\r
376                 cmd+=_T(" -a");\r
377         else if(type==BRANCH_REMOTE)\r
378                 cmd+=_T(" -r");\r
379 \r
380         int i=0;\r
381         ret=g_Git.Run(cmd,&output);\r
382         if(!ret)\r
383         {               \r
384                 int pos=0;\r
385                 CString one;\r
386                 while( pos>=0 )\r
387                 {\r
388                         i++;\r
389                         one=output.Tokenize(_T("\n"),pos);\r
390                         list.push_back(one.Right(one.GetLength()-2));\r
391                         if(one[0] == _T('*'))\r
392                                 if(current)\r
393                                         *current=i;\r
394                 }\r
395         }\r
396         return ret;\r
397 }\r
398 \r
399 int CGit::GetRemoteList(STRING_VECTOR &list)\r
400 {\r
401         int ret;\r
402         CString cmd,output;\r
403         cmd=_T("git.exe config  --get-regexp remote.*.url");\r
404         ret=g_Git.Run(cmd,&output);\r
405         if(!ret)\r
406         {\r
407                 int pos=0;\r
408                 CString one;\r
409                 while( pos>=0 )\r
410                 {\r
411                         one=output.Tokenize(_T("\n"),pos);\r
412                         int start=one.Find(_T("."),0);\r
413                         if(start>0)\r
414                         {\r
415                                 CString url;\r
416                                 url=one.Right(one.GetLength()-start-1);\r
417                                 one=url;\r
418                                 one=one.Left(one.Find(_T("."),0));\r
419                                 list.push_back(one);\r
420                         }\r
421                 }\r
422         }\r
423         return ret;\r
424 }\r
425 \r
426 int CGit::GetMapHashToFriendName(MAP_HASH_NAME &map)\r
427 {\r
428         int ret;\r
429         CString cmd,output;\r
430         cmd=_T("git show-ref -d");\r
431         ret=g_Git.Run(cmd,&output);\r
432         if(!ret)\r
433         {\r
434                 int pos=0;\r
435                 CString one;\r
436                 while( pos>=0 )\r
437                 {\r
438                         one=output.Tokenize(_T("\n"),pos);\r
439                         int start=one.Find(_T(" "),0);\r
440                         if(start>0)\r
441                         {\r
442                                 CString name;\r
443                                 name=one.Right(one.GetLength()-start-1);\r
444 \r
445                                 CString hash;\r
446                                 hash=one.Left(start);\r
447 \r
448                                 map[hash].push_back(name);\r
449                         }\r
450                 }\r
451         }\r
452         return ret;\r
453 }\r
454 \r
455 BOOL CGit::CheckMsysGitDir()\r
456 {\r
457         CRegString msysdir=CRegString(_T("Software\\TortoiseGit\\MSysGit"),_T(""),FALSE,HKEY_LOCAL_MACHINE);\r
458         CString str=msysdir;\r
459         if(str.IsEmpty())\r
460         {\r
461                 CRegString msysinstalldir=CRegString(_T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Git_is1\\InstallLocation"),_T(""),FALSE,HKEY_LOCAL_MACHINE);\r
462                 str=msysinstalldir;\r
463                 str+="\\bin";\r
464                 msysdir=str;\r
465                 msysdir.write();\r
466 \r
467         }\r
468         //CGit::m_MsysGitPath=str;\r
469 \r
470         TCHAR *oldpath,*home;\r
471         size_t size;\r
472 \r
473         _tdupenv_s(&home,&size,_T("HOME")); \r
474         \r
475         if(home == NULL)\r
476         {               \r
477                 _tdupenv_s(&home,&size,_T("USERPROFILE")); \r
478                 _tputenv_s(_T("HOME"),home);\r
479                 free(home);\r
480         }\r
481         //set path\r
482         _tdupenv_s(&oldpath,&size,_T("PATH")); \r
483 \r
484         CString path;\r
485         path.Format(_T("%s;"),str);\r
486         path+=oldpath;\r
487 \r
488         _tputenv_s(_T("PATH"),path);\r
489 \r
490         free(oldpath);\r
491 \r
492         CString cmd,out;\r
493         cmd=_T("git.exe --version");\r
494         if(g_Git.Run(cmd,&out))\r
495         {\r
496                 return false;\r
497         }\r
498         else\r
499                 return true;\r
500 \r
501 }