OSDN Git Service

7a4eedebbe850eee64bd657cd19b182d2c695e27
[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 \r
81 int CGit::Run(CString cmd, CString* output)\r
82 {\r
83         PROCESS_INFORMATION pi;\r
84         HANDLE hRead;\r
85         if(RunAsync(cmd,&pi,&hRead))\r
86                 return GIT_ERROR_CREATE_PROCESS;\r
87 \r
88         DWORD readnumber;\r
89         while(ReadFile(hRead,g_Buffer,1023,&readnumber,NULL))\r
90         {\r
91                 g_Buffer[readnumber]=0;\r
92                 StringAppend(output,g_Buffer);\r
93         }\r
94 \r
95         \r
96         CloseHandle(pi.hThread);\r
97 \r
98         WaitForSingleObject(pi.hProcess, INFINITE);\r
99         DWORD exitcode =0;\r
100 \r
101         if(!GetExitCodeProcess(pi.hProcess,&exitcode))\r
102         {\r
103                 return GIT_ERROR_GET_EXIT_CODE;\r
104         }\r
105 \r
106         CloseHandle(pi.hProcess);\r
107 \r
108         CloseHandle(hRead);\r
109         return exitcode;\r
110 }\r
111 \r
112 CString CGit::GetUserName(void)\r
113 {\r
114         CString UserName;\r
115         Run(_T("git.exe config user.name"),&UserName);\r
116         return UserName;\r
117 }\r
118 CString CGit::GetUserEmail(void)\r
119 {\r
120         CString UserName;\r
121         Run(_T("git.exe config user.email"),&UserName);\r
122         return UserName;\r
123 }\r
124 \r
125 CString CGit::GetCurrentBranch(void)\r
126 {\r
127         CString branch;\r
128         Run(_T("git.exe branch"),&branch);\r
129         if(branch.GetLength()>0)\r
130         {\r
131                 branch.Replace(_T('*'),_T(' '));\r
132                 branch.TrimLeft();\r
133                 return branch;\r
134         }\r
135         return CString("");\r
136 }\r
137 \r
138 int CGit::BuildOutputFormat(CString &format,bool IsFull)\r
139 {\r
140         CString log;\r
141         log.Format(_T("#<%c>%%n"),LOG_REV_ITEM_BEGIN);\r
142         format += log;\r
143         if(IsFull)\r
144         {\r
145                 log.Format(_T("#<%c>%%an%%n"),LOG_REV_AUTHOR_NAME);\r
146                 format += log;\r
147                 log.Format(_T("#<%c>%%ae%%n"),LOG_REV_AUTHOR_EMAIL);\r
148                 format += log;\r
149                 log.Format(_T("#<%c>%%ai%%n"),LOG_REV_AUTHOR_DATE);\r
150                 format += log;\r
151                 log.Format(_T("#<%c>%%cn%%n"),LOG_REV_COMMIT_NAME);\r
152                 format += log;\r
153                 log.Format(_T("#<%c>%%ce%%n"),LOG_REV_COMMIT_EMAIL);\r
154                 format += log;\r
155                 log.Format(_T("#<%c>%%ci%%n"),LOG_REV_COMMIT_DATE);\r
156                 format += log;\r
157                 log.Format(_T("#<%c>%%s%%n"),LOG_REV_COMMIT_SUBJECT);\r
158                 format += log;\r
159                 log.Format(_T("#<%c>%%b%%n"),LOG_REV_COMMIT_BODY);\r
160                 format += log;\r
161         }\r
162         log.Format(_T("#<%c>%%H%%n"),LOG_REV_COMMIT_HASH);\r
163         format += log;\r
164         log.Format(_T("#<%c>%%P%%n"),LOG_REV_COMMIT_PARENT);\r
165         format += log;\r
166 \r
167         if(IsFull)\r
168         {\r
169                 log.Format(_T("#<%c>%%n"),LOG_REV_COMMIT_FILE);\r
170                 format += log;\r
171         }\r
172         return 0;\r
173 }\r
174 \r
175 int CGit::GetLog(CString& logOut, CString &hash, int count)\r
176 {\r
177 \r
178         CString cmd;\r
179         CString log;\r
180         CString num;\r
181         CString since;\r
182         if(count>0)\r
183                 num.Format(_T("-n%d"),count);\r
184 \r
185         cmd.Format(_T("git.exe log %s -C --numstat --raw --pretty=format:\""),\r
186                                 num);\r
187         BuildOutputFormat(log);\r
188         cmd += log;\r
189         cmd += CString(_T("\"  "))+hash;\r
190         return Run(cmd,&logOut);\r
191 }\r
192 \r
193 \r
194 int CGit::GetShortLog(CString &logOut,CTGitPath * path, int count)\r
195 {\r
196         CString cmd;\r
197         CString log;\r
198         int n;\r
199         if(count<0)\r
200                 n=100;\r
201         else\r
202                 n=count;\r
203         cmd.Format(_T("git.exe log --topo-order -n%d --pretty=format:\""),n);\r
204         BuildOutputFormat(log,false);\r
205         cmd += log+_T("\"");\r
206         if (path)\r
207                 cmd+= _T("  -- \"")+path->GetGitPathString()+_T("\"");\r
208         //cmd += CString(_T("\" HEAD~40..HEAD"));\r
209         return Run(cmd,&logOut);\r
210 }\r
211 \r
212 #define BUFSIZE 512\r
213 void GetTempPath(CString &path)\r
214 {\r
215         TCHAR lpPathBuffer[BUFSIZE];\r
216         DWORD dwRetVal;\r
217         DWORD dwBufSize=BUFSIZE;\r
218         dwRetVal = GetTempPath(dwBufSize,     // length of the buffer\r
219                            lpPathBuffer); // buffer for path \r
220     if (dwRetVal > dwBufSize || (dwRetVal == 0))\r
221     {\r
222         path=_T("");\r
223     }\r
224         path.Format(_T("%s"),lpPathBuffer);\r
225 }\r
226 CString GetTempFile()\r
227 {\r
228         TCHAR lpPathBuffer[BUFSIZE];\r
229         DWORD dwRetVal;\r
230     DWORD dwBufSize=BUFSIZE;\r
231         TCHAR szTempName[BUFSIZE];  \r
232         UINT uRetVal;\r
233 \r
234         dwRetVal = GetTempPath(dwBufSize,     // length of the buffer\r
235                            lpPathBuffer); // buffer for path \r
236     if (dwRetVal > dwBufSize || (dwRetVal == 0))\r
237     {\r
238         return _T("");\r
239     }\r
240          // Create a temporary file. \r
241     uRetVal = GetTempFileName(lpPathBuffer, // directory for tmp files\r
242                               TEXT("Patch"),  // temp file name prefix \r
243                               0,            // create unique name \r
244                               szTempName);  // buffer for name \r
245 \r
246 \r
247     if (uRetVal == 0)\r
248     {\r
249         return _T("");\r
250     }\r
251 \r
252         return CString(szTempName);\r
253 \r
254 }\r
255 \r
256 int CGit::RunLogFile(CString cmd,CString &filename)\r
257 {\r
258         HANDLE hRead, hWrite;\r
259 \r
260         STARTUPINFO si;\r
261         PROCESS_INFORMATION pi;\r
262         si.cb=sizeof(STARTUPINFO);\r
263         GetStartupInfo(&si);\r
264 \r
265         SECURITY_ATTRIBUTES   psa={sizeof(psa),NULL,TRUE};;   \r
266         psa.bInheritHandle=TRUE;   \r
267     \r
268         HANDLE   houtfile=CreateFile(filename,GENERIC_WRITE,FILE_SHARE_READ   |   FILE_SHARE_WRITE,   \r
269                         &psa,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);   \r
270 \r
271 \r
272         si.wShowWindow=SW_HIDE;\r
273         si.dwFlags=STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;\r
274         si.hStdOutput   =   houtfile; \r
275         \r
276         if(!CreateProcess(NULL,(LPWSTR)cmd.GetString(), NULL,NULL,TRUE,NULL,NULL,(LPWSTR)m_CurrentDir.GetString(),&si,&pi))\r
277         {\r
278                 LPVOID lpMsgBuf;\r
279                 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,\r
280                         NULL,GetLastError(),MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),\r
281                         (LPTSTR)&lpMsgBuf,\r
282                         0,NULL);\r
283                 return GIT_ERROR_CREATE_PROCESS;\r
284         }\r
285         \r
286         WaitForSingleObject(pi.hProcess,INFINITE);   \r
287         \r
288         CloseHandle(pi.hThread);\r
289         CloseHandle(pi.hProcess);\r
290         CloseHandle(houtfile);\r
291         return GIT_SUCCESS;\r
292         return 0;\r
293 }\r
294 \r
295 git_revnum_t CGit::GetHash(CString &friendname)\r
296 {\r
297         CString cmd;\r
298         CString out;\r
299         cmd.Format(_T("git.exe rev-parse %s" ),friendname);\r
300         Run(cmd,&out);\r
301         int pos=out.ReverseFind(_T('\n'));\r
302         if(pos>0)\r
303                 return out.Left(pos);\r
304         return out;\r
305 }\r
306 \r
307 int CGit::GetTagList(STRING_VECTOR &list)\r
308 {\r
309         int ret;\r
310         CString cmd,output;\r
311         cmd=_T("git.exe tag -l");\r
312         int i=0;\r
313         ret=g_Git.Run(cmd,&output);\r
314         if(!ret)\r
315         {               \r
316                 int pos=0;\r
317                 CString one;\r
318                 while( pos>=0 )\r
319                 {\r
320                         i++;\r
321                         one=output.Tokenize(_T("\n"),pos);\r
322                         list.push_back(one);\r
323                 }\r
324         }\r
325         return ret;\r
326 }\r
327 \r
328 int CGit::GetBranchList(STRING_VECTOR &list,int *current,BRANCH_TYPE type)\r
329 {\r
330         int ret;\r
331         CString cmd,output;\r
332         cmd=_T("git.exe branch");\r
333 \r
334         if(type==(BRANCH_LOCAL|BRANCH_REMOTE))\r
335                 cmd+=_T(" -a");\r
336         else if(type==BRANCH_REMOTE)\r
337                 cmd+=_T(" -r");\r
338 \r
339         int i=0;\r
340         ret=g_Git.Run(cmd,&output);\r
341         if(!ret)\r
342         {               \r
343                 int pos=0;\r
344                 CString one;\r
345                 while( pos>=0 )\r
346                 {\r
347                         i++;\r
348                         one=output.Tokenize(_T("\n"),pos);\r
349                         list.push_back(one.Right(one.GetLength()-2));\r
350                         if(one[0] == _T('*'))\r
351                                 if(current)\r
352                                         *current=i;\r
353                 }\r
354         }\r
355         return ret;\r
356 }\r
357 \r
358 int CGit::GetRemoteList(STRING_VECTOR &list)\r
359 {\r
360         int ret;\r
361         CString cmd,output;\r
362         cmd=_T("git.exe config  --get-regexp remote.*.url");\r
363         ret=g_Git.Run(cmd,&output);\r
364         if(!ret)\r
365         {\r
366                 int pos=0;\r
367                 CString one;\r
368                 while( pos>=0 )\r
369                 {\r
370                         one=output.Tokenize(_T("\n"),pos);\r
371                         int start=one.Find(_T("."),0);\r
372                         if(start>0)\r
373                         {\r
374                                 CString url;\r
375                                 url=one.Right(one.GetLength()-start-1);\r
376                                 one=url;\r
377                                 one=one.Left(one.Find(_T("."),0));\r
378                                 list.push_back(one);\r
379                         }\r
380                 }\r
381         }\r
382         return ret;\r
383 }\r
384 \r
385 int CGit::GetMapHashToFriendName(MAP_HASH_NAME &map)\r
386 {\r
387         int ret;\r
388         CString cmd,output;\r
389         cmd=_T("git show-ref");\r
390         ret=g_Git.Run(cmd,&output);\r
391         if(!ret)\r
392         {\r
393                 int pos=0;\r
394                 CString one;\r
395                 while( pos>=0 )\r
396                 {\r
397                         one=output.Tokenize(_T("\n"),pos);\r
398                         int start=one.Find(_T(" "),0);\r
399                         if(start>0)\r
400                         {\r
401                                 CString name;\r
402                                 name=one.Right(one.GetLength()-start-1);\r
403 \r
404                                 CString hash;\r
405                                 hash=one.Left(start);\r
406 \r
407                                 map[hash].push_back(name);\r
408                         }\r
409                 }\r
410         }\r
411         return ret;\r
412 }