OSDN Git Service

Add show one file log at dialog box.
[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_CP(p,CP_UTF8));\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         if(mask& LOG_INFO_BOUNDARY)\r
225                 param += _T(" --left-right --boundary ");\r
226 \r
227         if(mask& CGit::LOG_INFO_ALL_BRANCH)\r
228                 param += _T(" --all ");\r
229 \r
230         if(mask& CGit::LOG_INFO_DETECT_COPYRENAME)\r
231                 param += _T(" -C ");\r
232         \r
233         if(mask& CGit::LOG_INFO_DETECT_RENAME )\r
234                 param += _T(" -M ");\r
235 \r
236         param+=hash;\r
237 \r
238         cmd.Format(_T("git.exe log %s --topo-order --parents %s --pretty=format:\""),\r
239                                 num,param);\r
240 \r
241         BuildOutputFormat(log,!(mask&CGit::LOG_INFO_ONLY_HASH));\r
242 \r
243         cmd += log;\r
244         cmd += CString(_T("\"  "))+hash+file;\r
245 \r
246         return Run(cmd,&logOut);\r
247 }\r
248 \r
249 #if 0\r
250 int CGit::GetShortLog(CString &logOut,CTGitPath * path, int count)\r
251 {\r
252         CString cmd;\r
253         CString log;\r
254         int n;\r
255         if(count<0)\r
256                 n=100;\r
257         else\r
258                 n=count;\r
259         cmd.Format(_T("git.exe log --left-right --boundary --topo-order -n%d --pretty=format:\""),n);\r
260         BuildOutputFormat(log,false);\r
261         cmd += log+_T("\"");\r
262         if (path)\r
263                 cmd+= _T("  -- \"")+path->GetGitPathString()+_T("\"");\r
264         //cmd += CString(_T("\" HEAD~40..HEAD"));\r
265         return Run(cmd,&logOut);\r
266 }\r
267 #endif\r
268 \r
269 #define BUFSIZE 512\r
270 void GetTempPath(CString &path)\r
271 {\r
272         TCHAR lpPathBuffer[BUFSIZE];\r
273         DWORD dwRetVal;\r
274         DWORD dwBufSize=BUFSIZE;\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         path=_T("");\r
280     }\r
281         path.Format(_T("%s"),lpPathBuffer);\r
282 }\r
283 CString GetTempFile()\r
284 {\r
285         TCHAR lpPathBuffer[BUFSIZE];\r
286         DWORD dwRetVal;\r
287     DWORD dwBufSize=BUFSIZE;\r
288         TCHAR szTempName[BUFSIZE];  \r
289         UINT uRetVal;\r
290 \r
291         dwRetVal = GetTempPath(dwBufSize,     // length of the buffer\r
292                            lpPathBuffer); // buffer for path \r
293     if (dwRetVal > dwBufSize || (dwRetVal == 0))\r
294     {\r
295         return _T("");\r
296     }\r
297          // Create a temporary file. \r
298     uRetVal = GetTempFileName(lpPathBuffer, // directory for tmp files\r
299                               TEXT("Patch"),  // temp file name prefix \r
300                               0,            // create unique name \r
301                               szTempName);  // buffer for name \r
302 \r
303 \r
304     if (uRetVal == 0)\r
305     {\r
306         return _T("");\r
307     }\r
308 \r
309         return CString(szTempName);\r
310 \r
311 }\r
312 \r
313 int CGit::RunLogFile(CString cmd,CString &filename)\r
314 {\r
315         HANDLE hRead, hWrite;\r
316 \r
317         STARTUPINFO si;\r
318         PROCESS_INFORMATION pi;\r
319         si.cb=sizeof(STARTUPINFO);\r
320         GetStartupInfo(&si);\r
321 \r
322         SECURITY_ATTRIBUTES   psa={sizeof(psa),NULL,TRUE};;   \r
323         psa.bInheritHandle=TRUE;   \r
324     \r
325         HANDLE   houtfile=CreateFile(filename,GENERIC_WRITE,FILE_SHARE_READ   |   FILE_SHARE_WRITE,   \r
326                         &psa,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);   \r
327 \r
328 \r
329         si.wShowWindow=SW_HIDE;\r
330         si.dwFlags=STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;\r
331         si.hStdOutput   =   houtfile; \r
332         \r
333         if(!CreateProcess(NULL,(LPWSTR)cmd.GetString(), NULL,NULL,TRUE,NULL,NULL,(LPWSTR)m_CurrentDir.GetString(),&si,&pi))\r
334         {\r
335                 LPVOID lpMsgBuf;\r
336                 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,\r
337                         NULL,GetLastError(),MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),\r
338                         (LPTSTR)&lpMsgBuf,\r
339                         0,NULL);\r
340                 return GIT_ERROR_CREATE_PROCESS;\r
341         }\r
342         \r
343         WaitForSingleObject(pi.hProcess,INFINITE);   \r
344         \r
345         CloseHandle(pi.hThread);\r
346         CloseHandle(pi.hProcess);\r
347         CloseHandle(houtfile);\r
348         return GIT_SUCCESS;\r
349         return 0;\r
350 }\r
351 \r
352 git_revnum_t CGit::GetHash(CString &friendname)\r
353 {\r
354         CString cmd;\r
355         CString out;\r
356         cmd.Format(_T("git.exe rev-parse %s" ),friendname);\r
357         Run(cmd,&out);\r
358         int pos=out.ReverseFind(_T('\n'));\r
359         if(pos>0)\r
360                 return out.Left(pos);\r
361         return out;\r
362 }\r
363 \r
364 int CGit::GetTagList(STRING_VECTOR &list)\r
365 {\r
366         int ret;\r
367         CString cmd,output;\r
368         cmd=_T("git.exe tag -l");\r
369         int i=0;\r
370         ret=g_Git.Run(cmd,&output);\r
371         if(!ret)\r
372         {               \r
373                 int pos=0;\r
374                 CString one;\r
375                 while( pos>=0 )\r
376                 {\r
377                         i++;\r
378                         one=output.Tokenize(_T("\n"),pos);\r
379                         list.push_back(one);\r
380                 }\r
381         }\r
382         return ret;\r
383 }\r
384 \r
385 int CGit::GetBranchList(STRING_VECTOR &list,int *current,BRANCH_TYPE type)\r
386 {\r
387         int ret;\r
388         CString cmd,output;\r
389         cmd=_T("git.exe branch");\r
390 \r
391         if(type==(BRANCH_LOCAL|BRANCH_REMOTE))\r
392                 cmd+=_T(" -a");\r
393         else if(type==BRANCH_REMOTE)\r
394                 cmd+=_T(" -r");\r
395 \r
396         int i=0;\r
397         ret=g_Git.Run(cmd,&output);\r
398         if(!ret)\r
399         {               \r
400                 int pos=0;\r
401                 CString one;\r
402                 while( pos>=0 )\r
403                 {\r
404                         i++;\r
405                         one=output.Tokenize(_T("\n"),pos);\r
406                         list.push_back(one.Right(one.GetLength()-2));\r
407                         if(one[0] == _T('*'))\r
408                                 if(current)\r
409                                         *current=i;\r
410                 }\r
411         }\r
412         return ret;\r
413 }\r
414 \r
415 int CGit::GetRemoteList(STRING_VECTOR &list)\r
416 {\r
417         int ret;\r
418         CString cmd,output;\r
419         cmd=_T("git.exe config  --get-regexp remote.*.url");\r
420         ret=g_Git.Run(cmd,&output);\r
421         if(!ret)\r
422         {\r
423                 int pos=0;\r
424                 CString one;\r
425                 while( pos>=0 )\r
426                 {\r
427                         one=output.Tokenize(_T("\n"),pos);\r
428                         int start=one.Find(_T("."),0);\r
429                         if(start>0)\r
430                         {\r
431                                 CString url;\r
432                                 url=one.Right(one.GetLength()-start-1);\r
433                                 one=url;\r
434                                 one=one.Left(one.Find(_T("."),0));\r
435                                 list.push_back(one);\r
436                         }\r
437                 }\r
438         }\r
439         return ret;\r
440 }\r
441 \r
442 int CGit::GetMapHashToFriendName(MAP_HASH_NAME &map)\r
443 {\r
444         int ret;\r
445         CString cmd,output;\r
446         cmd=_T("git show-ref -d");\r
447         ret=g_Git.Run(cmd,&output);\r
448         if(!ret)\r
449         {\r
450                 int pos=0;\r
451                 CString one;\r
452                 while( pos>=0 )\r
453                 {\r
454                         one=output.Tokenize(_T("\n"),pos);\r
455                         int start=one.Find(_T(" "),0);\r
456                         if(start>0)\r
457                         {\r
458                                 CString name;\r
459                                 name=one.Right(one.GetLength()-start-1);\r
460 \r
461                                 CString hash;\r
462                                 hash=one.Left(start);\r
463 \r
464                                 map[hash].push_back(name);\r
465                         }\r
466                 }\r
467         }\r
468         return ret;\r
469 }\r
470 \r
471 BOOL CGit::CheckMsysGitDir()\r
472 {\r
473         CRegString msysdir=CRegString(_T("Software\\TortoiseGit\\MSysGit"),_T(""),FALSE,HKEY_LOCAL_MACHINE);\r
474         CString str=msysdir;\r
475         if(str.IsEmpty())\r
476         {\r
477                 CRegString msysinstalldir=CRegString(_T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Git_is1\\InstallLocation"),_T(""),FALSE,HKEY_LOCAL_MACHINE);\r
478                 str=msysinstalldir;\r
479                 str+="\\bin";\r
480                 msysdir=str;\r
481                 msysdir.write();\r
482 \r
483         }\r
484         //CGit::m_MsysGitPath=str;\r
485 \r
486         TCHAR *oldpath,*home;\r
487         size_t size;\r
488 \r
489         _tdupenv_s(&home,&size,_T("HOME")); \r
490         \r
491         if(home == NULL)\r
492         {               \r
493                 _tdupenv_s(&home,&size,_T("USERPROFILE")); \r
494                 _tputenv_s(_T("HOME"),home);\r
495                 free(home);\r
496         }\r
497         //set path\r
498         _tdupenv_s(&oldpath,&size,_T("PATH")); \r
499 \r
500         CString path;\r
501         path.Format(_T("%s;"),str);\r
502         path+=oldpath;\r
503 \r
504         _tputenv_s(_T("PATH"),path);\r
505 \r
506         free(oldpath);\r
507 \r
508         CString cmd,out;\r
509         cmd=_T("git.exe --version");\r
510         if(g_Git.Run(cmd,&out))\r
511         {\r
512                 return false;\r
513         }\r
514         else\r
515                 return true;\r
516 \r
517 }