OSDN Git Service

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