OSDN Git Service

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