OSDN Git Service

Fix File List Del\Add switch problem and enable prevdiff command
[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,CTGitPath * path, int count)\r
186 {\r
187         CString cmd;\r
188         CString log;\r
189         int n;\r
190         if(count<0)\r
191                 n=100;\r
192         else\r
193                 n=count;\r
194         cmd.Format(_T("git.exe log --topo-order -n%d --pretty=format:\""),n);\r
195         BuildOutputFormat(log,false);\r
196         cmd += log+_T("\"");\r
197         if (path)\r
198                 cmd+= _T("  -- \"")+path->GetGitPathString()+_T("\"");\r
199         //cmd += CString(_T("\" HEAD~40..HEAD"));\r
200         return Run(cmd,&logOut);\r
201 }\r
202 \r
203 #define BUFSIZE 512\r
204 void GetTempPath(CString &path)\r
205 {\r
206         TCHAR lpPathBuffer[BUFSIZE];\r
207         DWORD dwRetVal;\r
208         DWORD dwBufSize=BUFSIZE;\r
209         dwRetVal = GetTempPath(dwBufSize,     // length of the buffer\r
210                            lpPathBuffer); // buffer for path \r
211     if (dwRetVal > dwBufSize || (dwRetVal == 0))\r
212     {\r
213         path=_T("");\r
214     }\r
215         path.Format(_T("%s"),lpPathBuffer);\r
216 }\r
217 CString GetTempFile()\r
218 {\r
219         TCHAR lpPathBuffer[BUFSIZE];\r
220         DWORD dwRetVal;\r
221     DWORD dwBufSize=BUFSIZE;\r
222         TCHAR szTempName[BUFSIZE];  \r
223         UINT uRetVal;\r
224 \r
225         dwRetVal = GetTempPath(dwBufSize,     // length of the buffer\r
226                            lpPathBuffer); // buffer for path \r
227     if (dwRetVal > dwBufSize || (dwRetVal == 0))\r
228     {\r
229         return _T("");\r
230     }\r
231          // Create a temporary file. \r
232     uRetVal = GetTempFileName(lpPathBuffer, // directory for tmp files\r
233                               TEXT("Patch"),  // temp file name prefix \r
234                               0,            // create unique name \r
235                               szTempName);  // buffer for name \r
236 \r
237 \r
238     if (uRetVal == 0)\r
239     {\r
240         return _T("");\r
241     }\r
242 \r
243         return CString(szTempName);\r
244 \r
245 }\r
246 \r
247 int CGit::RunLogFile(CString cmd,CString &filename)\r
248 {\r
249         HANDLE hRead, hWrite;\r
250 \r
251         STARTUPINFO si;\r
252         PROCESS_INFORMATION pi;\r
253         si.cb=sizeof(STARTUPINFO);\r
254         GetStartupInfo(&si);\r
255 \r
256         SECURITY_ATTRIBUTES   psa={sizeof(psa),NULL,TRUE};;   \r
257         psa.bInheritHandle=TRUE;   \r
258     \r
259         HANDLE   houtfile=CreateFile(filename,GENERIC_WRITE,FILE_SHARE_READ   |   FILE_SHARE_WRITE,   \r
260                         &psa,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);   \r
261 \r
262 \r
263         si.wShowWindow=SW_HIDE;\r
264         si.dwFlags=STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;\r
265         si.hStdOutput   =   houtfile; \r
266         \r
267         if(!CreateProcess(NULL,(LPWSTR)cmd.GetString(), NULL,NULL,TRUE,NULL,NULL,(LPWSTR)m_CurrentDir.GetString(),&si,&pi))\r
268         {\r
269                 LPVOID lpMsgBuf;\r
270                 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,\r
271                         NULL,GetLastError(),MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),\r
272                         (LPTSTR)&lpMsgBuf,\r
273                         0,NULL);\r
274                 return GIT_ERROR_CREATE_PROCESS;\r
275         }\r
276         \r
277         WaitForSingleObject(pi.hProcess,INFINITE);   \r
278         \r
279         CloseHandle(pi.hThread);\r
280         CloseHandle(pi.hProcess);\r
281         CloseHandle(houtfile);\r
282         return GIT_SUCCESS;\r
283         return 0;\r
284 }\r
285 \r
286 git_revnum_t CGit::GetHash(CString &friendname)\r
287 {\r
288         CString cmd;\r
289         CString out;\r
290         cmd.Format(_T("git.exe rev-parse %s" ),friendname);\r
291         Run(cmd,&out);\r
292         int pos=out.ReverseFind(_T('\n'));\r
293         if(pos>0)\r
294                 return out.Left(pos);\r
295         return out;\r
296 }\r
297 \r
298 int CGit::GetTagList(STRING_VECTOR &list)\r
299 {\r
300         int ret;\r
301         CString cmd,output;\r
302         cmd=_T("git.exe tag -l");\r
303         int i=0;\r
304         ret=g_Git.Run(cmd,&output);\r
305         if(!ret)\r
306         {               \r
307                 int pos=0;\r
308                 CString one;\r
309                 while( pos>=0 )\r
310                 {\r
311                         i++;\r
312                         one=output.Tokenize(_T("\n"),pos);\r
313                         list.push_back(one);\r
314                 }\r
315         }\r
316         return ret;\r
317 }\r
318 \r
319 int CGit::GetBranchList(STRING_VECTOR &list,int *current,BRANCH_TYPE type)\r
320 {\r
321         int ret;\r
322         CString cmd,output;\r
323         cmd=_T("git.exe branch");\r
324 \r
325         if(type==(BRANCH_LOCAL|BRANCH_REMOTE))\r
326                 cmd+=_T(" -a");\r
327         else if(type==BRANCH_REMOTE)\r
328                 cmd+=_T(" -r");\r
329 \r
330         int i=0;\r
331         ret=g_Git.Run(cmd,&output);\r
332         if(!ret)\r
333         {               \r
334                 int pos=0;\r
335                 CString one;\r
336                 while( pos>=0 )\r
337                 {\r
338                         i++;\r
339                         one=output.Tokenize(_T("\n"),pos);\r
340                         list.push_back(one.Right(one.GetLength()-2));\r
341                         if(one[0] == _T('*'))\r
342                                 if(current)\r
343                                         *current=i;\r
344                 }\r
345         }\r
346         return ret;\r
347 }\r
348 \r
349 int CGit::GetRemoteList(STRING_VECTOR &list)\r
350 {\r
351         int ret;\r
352         CString cmd,output;\r
353         cmd=_T("git.exe config  --get-regexp remote.*.url");\r
354         ret=g_Git.Run(cmd,&output);\r
355         if(!ret)\r
356         {\r
357                 int pos=0;\r
358                 CString one;\r
359                 while( pos>=0 )\r
360                 {\r
361                         one=output.Tokenize(_T("\n"),pos);\r
362                         int start=one.Find(_T("."),0);\r
363                         if(start>0)\r
364                         {\r
365                                 CString url;\r
366                                 url=one.Right(one.GetLength()-start-1);\r
367                                 one=url;\r
368                                 one=one.Left(one.Find(_T("."),0));\r
369                                 list.push_back(one);\r
370                         }\r
371                 }\r
372         }\r
373         return ret;\r
374 }\r
375 \r
376 int CGit::GetMapHashToFriendName(MAP_HASH_NAME &map)\r
377 {\r
378         int ret;\r
379         CString cmd,output;\r
380         cmd=_T("git show-ref");\r
381         ret=g_Git.Run(cmd,&output);\r
382         if(!ret)\r
383         {\r
384                 int pos=0;\r
385                 CString one;\r
386                 while( pos>=0 )\r
387                 {\r
388                         one=output.Tokenize(_T("\n"),pos);\r
389                         int start=one.Find(_T(" "),0);\r
390                         if(start>0)\r
391                         {\r
392                                 CString name;\r
393                                 name=one.Right(one.GetLength()-start-1);\r
394 \r
395                                 CString hash;\r
396                                 hash=one.Left(start);\r
397 \r
398                                 map[hash].push_back(name);\r
399                         }\r
400                 }\r
401         }\r
402         return ret;\r
403 }