OSDN Git Service

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