OSDN Git Service

Git log basic work but graph tree is wrong when scroll
[tortoisegit/TortoiseGitJp.git] / src / Git / GitRev.cpp
1 #include "StdAfx.h"\r
2 #include "ATLComTime.h"\r
3 #include "GitRev.h"\r
4 #include "Git.h"\r
5 #include "GitDLL.h"\r
6 \r
7 class CException; //Just in case afx.h is not included (cannot be included in every project which uses this file)\r
8 \r
9 // provide an ASSERT macro for when compiled without MFC\r
10 #if !defined ASSERT\r
11         // Don't use _asm here, it isn't supported by x64 version of compiler. In fact, MFC's ASSERT() is the same with _ASSERTE().\r
12         #define ASSERT(x) _ASSERTE(x)\r
13 #endif\r
14 \r
15 \r
16 GitRev::GitRev(void)\r
17 {\r
18         m_Action=0;\r
19         m_IsFull = 0;\r
20         m_IsUpdateing = 0;\r
21         // fetch local machine timezone info\r
22         if ( GetTimeZoneInformation( &m_TimeZone ) == TIME_ZONE_ID_INVALID )\r
23         {\r
24                 ASSERT(false);\r
25         }\r
26 }\r
27 \r
28 GitRev::~GitRev(void)\r
29 {\r
30 }\r
31 \r
32 #if 0\r
33 GitRev::GitRev(GitRev & rev)\r
34 {\r
35 }\r
36 GitRev& GitRev::operator=(GitRev &rev)\r
37 {\r
38         return *this;\r
39 }\r
40 #endif\r
41 void GitRev::Clear()\r
42 {\r
43         this->m_Action=0;\r
44         this->m_Files.Clear();\r
45         this->m_Action=0;\r
46         this->m_ParentHash.clear();\r
47         m_CommitterName.Empty();\r
48         m_CommitterEmail.Empty();\r
49         m_Body.Empty();\r
50         m_Subject.Empty();\r
51         m_CommitHash.Empty();\r
52         m_Ref.Empty();\r
53         m_RefAction.Empty();\r
54         m_Mark=0;\r
55 \r
56 }\r
57 int GitRev::CopyFrom(GitRev &rev,bool OmitParentAndMark)\r
58 {\r
59         m_AuthorName    =rev.m_AuthorName       ;\r
60         m_AuthorEmail   =rev.m_AuthorEmail      ;\r
61         m_AuthorDate    =rev.m_AuthorDate       ;\r
62         m_CommitterName =rev.m_CommitterName    ;\r
63         m_CommitterEmail=rev.m_CommitterEmail;\r
64         m_CommitterDate =rev.m_CommitterDate    ;\r
65         m_Subject               =rev.m_Subject          ;\r
66         m_Body                  =rev.m_Body                     ;\r
67         m_CommitHash    =rev.m_CommitHash       ;\r
68         m_Files                 =rev.m_Files                    ;       \r
69         m_Action                =rev.m_Action           ;\r
70         m_IsFull                =rev.m_IsFull;\r
71 \r
72         if(!OmitParentAndMark)\r
73         {\r
74                 m_ParentHash    =rev.m_ParentHash       ;\r
75                 m_Mark                  =rev.m_Mark;\r
76         }\r
77         return 0;\r
78 }\r
79 int GitRev::ParserFromLog(BYTE_VECTOR &log,int start)\r
80 {\r
81         int pos=start;\r
82         CString one;\r
83         CString key;\r
84         CString text;\r
85         BYTE_VECTOR filelist;\r
86         BYTE mode=0;\r
87         CTGitPath  path;\r
88         this->m_Files.Clear();\r
89     m_Action=0;\r
90         int begintime=0;\r
91         int filebegin=-1;\r
92 \r
93         while( pos < log.size() && pos>=0)\r
94         {\r
95                 \r
96                 //one=log.Tokenize(_T("\n"),pos);\r
97                 if(log[pos]==_T('#') && log[pos+1] == _T('<') && log[pos+3] == _T('>'))\r
98                 {\r
99                         //text = one.Right(one.GetLength()-4);\r
100                         text.Empty();\r
101                         g_Git.StringAppend(&text,&log[pos+4],CGit::m_LogEncode);\r
102                         mode = log[pos+2];\r
103                         \r
104                         switch(mode)\r
105                         {\r
106                         case LOG_REV_ITEM_BEGIN:\r
107                                 begintime++;\r
108                                 if(begintime>1)\r
109                                         break;\r
110                                 else\r
111                                         this->Clear();\r
112                                 break;\r
113                         case LOG_REV_AUTHOR_NAME:\r
114                                 this->m_AuthorName = text;\r
115                                 break;\r
116                         case LOG_REV_AUTHOR_EMAIL:\r
117                                 this->m_AuthorEmail = text;\r
118                                 break;\r
119                         case LOG_REV_AUTHOR_DATE:\r
120                                 this->m_AuthorDate =ConverFromString(text);\r
121                                 break;\r
122                         case LOG_REV_COMMIT_NAME:\r
123                                 this->m_CommitterName = text;\r
124                                 break;\r
125                         case LOG_REV_COMMIT_EMAIL:\r
126                                 this->m_CommitterEmail = text;\r
127                                 break;\r
128                         case LOG_REV_COMMIT_DATE:\r
129                                 this->m_CommitterDate =ConverFromString(text);\r
130                                 break;\r
131                         case LOG_REV_COMMIT_SUBJECT:\r
132                                 this->m_Subject = text;\r
133                                 break;\r
134                         case LOG_REV_COMMIT_BODY:\r
135                                 this->m_Body = text +_T("\n");\r
136                                 break;\r
137                         case LOG_REV_COMMIT_HASH:\r
138                                 this->m_CommitHash = text.Right(40);\r
139                                 if(text.GetLength()>40)\r
140                                 {\r
141                                         this->m_Mark=text[0];\r
142                                 }\r
143                                 break;\r
144                         case LOG_REV_COMMIT_PARENT:\r
145                                 while(text.GetLength()>0)\r
146                                 {\r
147                                         this->m_ParentHash.insert(this->m_ParentHash.end(),text.Left(40));\r
148                                         if(text.GetLength()>40)\r
149                                                 text=text.Right(text.GetLength()-41);\r
150                                         else\r
151                                                 break;\r
152                                 }\r
153                                 if(m_ParentHash.size()>1)\r
154                                 {\r
155                                         int a=1;\r
156                                 }\r
157                                 break;\r
158                         case LOG_REV_COMMIT_FILE:\r
159                                 break;\r
160                         }\r
161                 }else\r
162                 {\r
163                         switch(mode)\r
164                         {\r
165 //                      case LOG_REV_COMMIT_BODY:\r
166 //                              this->m_Body += one+_T("\n");\r
167 //                              break;\r
168                         case LOG_REV_COMMIT_FILE:\r
169                                 //filelist += one +_T("\n");\r
170                                 //filelist.append(log,pos,log.find(0,pos));\r
171                                 if(filebegin<0)\r
172                                         filebegin=pos;\r
173                                 break;\r
174                         }\r
175                 }\r
176                 \r
177                 if(begintime>1)\r
178                 {\r
179                         break;\r
180                 }\r
181 \r
182                 //find next string start \r
183                 pos=log.findNextString(pos);\r
184         }\r
185         \r
186         if(filebegin>=0)\r
187         {\r
188                 \r
189                 filelist.append(log,filebegin,pos);     \r
190                 this->m_Files.ParserFromLog(filelist);\r
191                 this->m_Action=this->m_Files.GetAction();\r
192         }\r
193         return pos;\r
194 }\r
195 \r
196 CTime GitRev::ConverFromString(CString input)\r
197 {\r
198         // pick up date from string\r
199         try\r
200         {\r
201                 COleDateTime tm(_wtoi(input.Mid(0,4)),\r
202                                  _wtoi(input.Mid(5,2)),\r
203                                  _wtoi(input.Mid(8,2)),\r
204                                  _wtoi(input.Mid(11,2)),\r
205                                  _wtoi(input.Mid(14,2)),\r
206                                  _wtoi(input.Mid(17,2)));\r
207                 if( tm.GetStatus() != COleDateTime::valid )\r
208                         return CTime();//Error parsing time-string\r
209 \r
210                 // pick up utc offset\r
211                 CString sign = input.Mid(20,1);         // + or -\r
212                 int hoursOffset =  _wtoi(input.Mid(21,2));\r
213                 int minsOffset = _wtoi(input.Mid(23,2));\r
214                 // convert to a fraction of a day\r
215                 double offset = (hoursOffset*60 + minsOffset) / 1440.0;         // 1440 mins = 1 day\r
216                 if ( sign == "-" )\r
217                 {\r
218                         offset = -offset;\r
219                 }\r
220                 // we have to subtract this from the time given to get UTC\r
221                 tm -= offset;\r
222                 // get utc time as a SYSTEMTIME\r
223                 SYSTEMTIME sysTime;\r
224                 tm.GetAsSystemTime( sysTime );\r
225                 // and convert to users local time\r
226                 SYSTEMTIME local;\r
227                 if ( SystemTimeToTzSpecificLocalTime( &m_TimeZone, &sysTime, &local ) )\r
228                 {\r
229                         sysTime = local;\r
230                 }\r
231                 else\r
232                 {\r
233                         ASSERT(false);  // this should not happen but leave time in utc if it does\r
234                 }\r
235                 // convert to CTime and return\r
236                 return CTime( sysTime, -1 );;\r
237         }\r
238         catch(CException* e)\r
239         {\r
240                 //Probably the date was something like 1970-01-01 00:00:00. _mktime64() doesnt like this.\r
241                 //Dont let the application crash on this exception\r
242 \r
243 #ifdef _AFX //CException classes are only defined when afx.h is included.\r
244                         //When afx.h is not included, the exception is leaked.\r
245                         //This will probably never happen because when CException is not defined, it cannot be thrown.\r
246                 e->Delete();\r
247 #endif //ifdef _AFX\r
248         }\r
249         return CTime(); //Return an invalid time\r
250 }\r
251 \r
252 int GitRev::SafeFetchFullInfo(CGit *git)\r
253 {\r
254         if(InterlockedExchange(&m_IsUpdateing,TRUE) == FALSE)\r
255         {\r
256 #if 0\r
257                 //GitRev rev;\r
258                 BYTE_VECTOR onelog;\r
259                 TCHAR oldmark=this->m_Mark;\r
260                 CString commithash = m_CommitHash;\r
261                 git->GetLog(onelog,commithash,NULL,1,CGit::LOG_INFO_FULL_DIFF|CGit::LOG_INFO_STAT|CGit::LOG_INFO_FILESTATE|CGit::LOG_INFO_DETECT_COPYRENAME|CGit::LOG_INFO_SHOW_MERGEDFILE);\r
262                 CString oldhash=m_CommitHash;\r
263                 GIT_REV_LIST oldlist=this->m_ParentHash;\r
264                 ParserFromLog(onelog);\r
265                 \r
266                 //ASSERT(oldhash==m_CommitHash);\r
267                 if(oldmark!=0)\r
268                         this->m_Mark=oldmark;  //parser full log will cause old mark overwrited. \r
269                                                                //So we need keep old bound mark.\r
270                 this->m_ParentHash=oldlist;\r
271                 InterlockedExchange(&m_IsUpdateing,FALSE);\r
272                 InterlockedExchange(&m_IsFull,TRUE);\r
273                 return 0;\r
274 #endif\r
275                 this->m_Files.Clear();\r
276                 git->CheckAndInitDll();\r
277                 GIT_COMMIT commit;\r
278                 GIT_COMMIT_LIST list;\r
279                 GIT_HASH   parent;\r
280                 if(git_get_commit_from_hash(&commit, this->m_CommitHash.m_hash))\r
281                         return -1;\r
282 \r
283                 int i=0;\r
284                 git_get_commit_first_parent(&commit,&list);\r
285                 while(git_get_commit_next_parent(&list,parent) == 0)\r
286                 {\r
287                         GIT_FILE file;\r
288                         int count;\r
289                         git_diff(git->GetGitDiff(),parent,commit.m_hash,&file,&count);\r
290                         CTGitPath path;\r
291                         CString strnewname;\r
292                         CString stroldname;\r
293                         \r
294                         for(int j=0;j<count;j++)\r
295                         {\r
296                                 path.Reset();\r
297                                 char *newname;\r
298                                 char *oldname;\r
299                                 \r
300                                 strnewname.Empty();\r
301                                 stroldname.Empty();\r
302 \r
303                                 int mode,IsBin,inc,dec;\r
304                                 git_get_diff_file(git->GetGitDiff(),file,j,&newname,&oldname,\r
305                                                 &mode,&IsBin,&inc,&dec);\r
306                                 \r
307                                 git->StringAppend(&strnewname,(BYTE*)newname,CP_ACP);\r
308                                 git->StringAppend(&stroldname,(BYTE*)oldname,CP_ACP);\r
309 \r
310                                 path.m_ParentNo = i;\r
311                                 path.SetFromGit(strnewname,&stroldname);\r
312                                 path.ParserAction((BYTE)mode);\r
313 \r
314                                 this->m_Action|=path.m_Action;\r
315 \r
316                                 if(IsBin)\r
317                                 {\r
318                                         path.m_StatAdd=_T("-");\r
319                                         path.m_StatDel=_T("-");\r
320                                 }else\r
321                                 {\r
322                                         path.m_StatAdd.Format(_T("%d"),inc);\r
323                                         path.m_StatDel.Format(_T("%d"),dec);\r
324                                 }\r
325                                 m_Files.AddPath(path);\r
326                         }\r
327                         git_diff_flush(git->GetGitDiff());\r
328                         i++;\r
329                 }\r
330 \r
331                 InterlockedExchange(&m_IsUpdateing,FALSE);\r
332                 InterlockedExchange(&m_IsFull,TRUE);\r
333 \r
334         }\r
335         return -1;\r
336 }\r
337 \r
338 int GitRev::ParserParentFromCommit(GIT_COMMIT *commit)\r
339 {\r
340         this->m_ParentHash.clear();\r
341         GIT_COMMIT_LIST list;\r
342         GIT_HASH   parent;\r
343         \r
344         git_get_commit_first_parent(commit,&list);\r
345         while(git_get_commit_next_parent(&list,parent)==0)\r
346         {\r
347                 m_ParentHash.push_back(CGitHash((char *)parent));\r
348         }\r
349         return 0;\r
350 }\r
351 \r
352 int GitRev::ParserFromCommit(GIT_COMMIT *commit)\r
353 {\r
354         this->m_AuthorDate = commit->m_Author.Date;\r
355         \r
356         this->m_AuthorEmail.Empty();\r
357         g_Git.StringAppend(&m_AuthorEmail,(BYTE*)commit->m_Author.Email,CP_ACP,commit->m_Author.EmailSize);\r
358 \r
359         this->m_AuthorName.Empty();\r
360         g_Git.StringAppend(&m_AuthorName,(BYTE*)commit->m_Author.Name,CP_ACP,commit->m_Author.NameSize);\r
361         \r
362         this->m_Body.Empty();\r
363         g_Git.StringAppend(&m_Body,(BYTE*)commit->m_Body,CP_ACP,commit->m_BodySize);\r
364 \r
365         this->m_CommitterDate = commit->m_Committer.Date;\r
366         \r
367         this->m_CommitterEmail.Empty();\r
368         g_Git.StringAppend(&m_CommitterEmail, (BYTE*)commit->m_Committer.Email,CP_ACP, commit->m_Committer.EmailSize);\r
369 \r
370         this->m_CommitterName.Empty();\r
371         g_Git.StringAppend(&m_CommitterName, (BYTE*)commit->m_Committer.Name,CP_ACP, commit->m_Committer.NameSize);\r
372 \r
373         this->m_Subject.Empty();\r
374         g_Git.StringAppend(&m_Subject, (BYTE*)commit->m_Subject,CP_ACP,commit->m_SubjectSize);\r
375         \r
376         return 0;\r
377 }