OSDN Git Service

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