OSDN Git Service

Add pull and fetch document
[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 \r
6 class CException; //Just in case afx.h is not included (cannot be included in every project which uses this file)\r
7 \r
8 // provide an ASSERT macro for when compiled without MFC\r
9 #if !defined ASSERT\r
10         // 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
11         #define ASSERT(x) _ASSERTE(x)\r
12 #endif\r
13 \r
14 \r
15 GitRev::GitRev(void)\r
16 {\r
17         m_Action=0;\r
18         m_IsFull = 0;\r
19         m_IsUpdateing = 0;\r
20         // fetch local machine timezone info\r
21         if ( GetTimeZoneInformation( &m_TimeZone ) == TIME_ZONE_ID_INVALID )\r
22         {\r
23                 ASSERT(false);\r
24         }\r
25 }\r
26 \r
27 GitRev::~GitRev(void)\r
28 {\r
29 }\r
30 \r
31 #if 0\r
32 GitRev::GitRev(GitRev & rev)\r
33 {\r
34 }\r
35 GitRev& GitRev::operator=(GitRev &rev)\r
36 {\r
37         return *this;\r
38 }\r
39 #endif\r
40 void GitRev::Clear()\r
41 {\r
42         this->m_Action=0;\r
43         this->m_Files.Clear();\r
44         this->m_Action=0;\r
45         this->m_ParentHash.clear();\r
46         m_CommitterName.Empty();\r
47         m_CommitterEmail.Empty();\r
48         m_Body.Empty();\r
49         m_Subject.Empty();\r
50         m_CommitHash.Empty();\r
51         m_Mark=0;\r
52 \r
53 }\r
54 int GitRev::CopyFrom(GitRev &rev,bool OmitParentAndMark)\r
55 {\r
56         m_AuthorName    =rev.m_AuthorName       ;\r
57         m_AuthorEmail   =rev.m_AuthorEmail      ;\r
58         m_AuthorDate    =rev.m_AuthorDate       ;\r
59         m_CommitterName =rev.m_CommitterName    ;\r
60         m_CommitterEmail=rev.m_CommitterEmail;\r
61         m_CommitterDate =rev.m_CommitterDate    ;\r
62         m_Subject               =rev.m_Subject          ;\r
63         m_Body                  =rev.m_Body                     ;\r
64         m_CommitHash    =rev.m_CommitHash       ;\r
65         m_Files                 =rev.m_Files                    ;       \r
66         m_Action                =rev.m_Action           ;\r
67 \r
68         if(!OmitParentAndMark)\r
69         {\r
70                 m_ParentHash    =rev.m_ParentHash       ;\r
71                 m_Mark                  =rev.m_Mark;\r
72         }\r
73         return 0;\r
74 }\r
75 int GitRev::ParserFromLog(BYTE_VECTOR &log,int start)\r
76 {\r
77         int pos=start;\r
78         CString one;\r
79         CString key;\r
80         CString text;\r
81         BYTE_VECTOR filelist;\r
82         BYTE mode=0;\r
83         CTGitPath  path;\r
84         this->m_Files.Clear();\r
85     m_Action=0;\r
86         int begintime=0;\r
87         int filebegin=-1;\r
88 \r
89         while( pos < log.size() && pos>=0)\r
90         {\r
91                 \r
92                 //one=log.Tokenize(_T("\n"),pos);\r
93                 if(log[pos]==_T('#') && log[pos+1] == _T('<') && log[pos+3] == _T('>'))\r
94                 {\r
95                         //text = one.Right(one.GetLength()-4);\r
96                         text.Empty();\r
97                         g_Git.StringAppend(&text,&log[pos+4],CGit::m_LogEncode);\r
98                         mode = log[pos+2];\r
99                         \r
100                         switch(mode)\r
101                         {\r
102                         case LOG_REV_ITEM_BEGIN:\r
103                                 begintime++;\r
104                                 if(begintime>1)\r
105                                         break;\r
106                                 else\r
107                                         this->Clear();\r
108                                 break;\r
109                         case LOG_REV_AUTHOR_NAME:\r
110                                 this->m_AuthorName = text;\r
111                                 break;\r
112                         case LOG_REV_AUTHOR_EMAIL:\r
113                                 this->m_AuthorEmail = text;\r
114                                 break;\r
115                         case LOG_REV_AUTHOR_DATE:\r
116                                 this->m_AuthorDate =ConverFromString(text);\r
117                                 break;\r
118                         case LOG_REV_COMMIT_NAME:\r
119                                 this->m_CommitterName = text;\r
120                                 break;\r
121                         case LOG_REV_COMMIT_EMAIL:\r
122                                 this->m_CommitterEmail = text;\r
123                                 break;\r
124                         case LOG_REV_COMMIT_DATE:\r
125                                 this->m_CommitterDate =ConverFromString(text);\r
126                                 break;\r
127                         case LOG_REV_COMMIT_SUBJECT:\r
128                                 this->m_Subject = text;\r
129                                 break;\r
130                         case LOG_REV_COMMIT_BODY:\r
131                                 this->m_Body = text +_T("\n");\r
132                                 break;\r
133                         case LOG_REV_COMMIT_HASH:\r
134                                 this->m_CommitHash = text.Right(40);\r
135                                 if(text.GetLength()>40)\r
136                                 {\r
137                                         this->m_Mark=text[0];\r
138                                 }\r
139                                 break;\r
140                         case LOG_REV_COMMIT_PARENT:\r
141                                 while(text.GetLength()>0)\r
142                                 {\r
143                                         this->m_ParentHash.insert(this->m_ParentHash.end(),text.Left(40));\r
144                                         if(text.GetLength()>40)\r
145                                                 text=text.Right(text.GetLength()-41);\r
146                                         else\r
147                                                 break;\r
148                                 }\r
149                                 if(m_ParentHash.size()>1)\r
150                                 {\r
151                                         int a=1;\r
152                                 }\r
153                                 break;\r
154                         case LOG_REV_COMMIT_FILE:\r
155                                 break;\r
156                         }\r
157                 }else\r
158                 {\r
159                         switch(mode)\r
160                         {\r
161 //                      case LOG_REV_COMMIT_BODY:\r
162 //                              this->m_Body += one+_T("\n");\r
163 //                              break;\r
164                         case LOG_REV_COMMIT_FILE:\r
165                                 //filelist += one +_T("\n");\r
166                                 //filelist.append(log,pos,log.find(0,pos));\r
167                                 if(filebegin<0)\r
168                                         filebegin=pos;\r
169                                 break;\r
170                         }\r
171                 }\r
172                 \r
173                 if(begintime>1)\r
174                 {\r
175                         break;\r
176                 }\r
177 \r
178                 //find next string start \r
179                 pos=log.findNextString(pos);\r
180         }\r
181         \r
182         if(filebegin>=0)\r
183         {\r
184                 \r
185                 filelist.append(log,filebegin,pos);     \r
186                 this->m_Files.ParserFromLog(filelist);\r
187                 this->m_Action=this->m_Files.GetAction();\r
188         }\r
189         return pos;\r
190 }\r
191 \r
192 CTime GitRev::ConverFromString(CString input)\r
193 {\r
194         // pick up date from string\r
195         try\r
196         {\r
197                 COleDateTime tm(_wtoi(input.Mid(0,4)),\r
198                                  _wtoi(input.Mid(5,2)),\r
199                                  _wtoi(input.Mid(8,2)),\r
200                                  _wtoi(input.Mid(11,2)),\r
201                                  _wtoi(input.Mid(14,2)),\r
202                                  _wtoi(input.Mid(17,2)));\r
203                 if( tm.GetStatus() != COleDateTime::valid )\r
204                         return CTime();//Error parsing time-string\r
205 \r
206                 // pick up utc offset\r
207                 CString sign = input.Mid(20,1);         // + or -\r
208                 int hoursOffset =  _wtoi(input.Mid(21,2));\r
209                 int minsOffset = _wtoi(input.Mid(23,2));\r
210                 // convert to a fraction of a day\r
211                 double offset = (hoursOffset*60 + minsOffset) / 1440.0;         // 1440 mins = 1 day\r
212                 if ( sign == "-" )\r
213                 {\r
214                         offset = -offset;\r
215                 }\r
216                 // we have to subtract this from the time given to get UTC\r
217                 tm -= offset;\r
218                 // get utc time as a SYSTEMTIME\r
219                 SYSTEMTIME sysTime;\r
220                 tm.GetAsSystemTime( sysTime );\r
221                 // and convert to users local time\r
222                 SYSTEMTIME local;\r
223                 if ( SystemTimeToTzSpecificLocalTime( &m_TimeZone, &sysTime, &local ) )\r
224                 {\r
225                         sysTime = local;\r
226                 }\r
227                 else\r
228                 {\r
229                         ASSERT(false);  // this should not happen but leave time in utc if it does\r
230                 }\r
231                 // convert to CTime and return\r
232                 return CTime( sysTime, -1 );;\r
233         }\r
234         catch(CException* e)\r
235         {\r
236                 //Probably the date was something like 1970-01-01 00:00:00. _mktime64() doesnt like this.\r
237                 //Dont let the application crash on this exception\r
238 \r
239 #ifdef _AFX //CException classes are only defined when afx.h is included.\r
240                         //When afx.h is not included, the exception is leaked.\r
241                         //This will probably never happen because when CException is not defined, it cannot be thrown.\r
242                 e->Delete();\r
243 #endif //ifdef _AFX\r
244         }\r
245         return CTime(); //Return an invalid time\r
246 }\r
247 \r
248 int GitRev::SafeFetchFullInfo(CGit *git)\r
249 {\r
250         if(InterlockedExchange(&m_IsUpdateing,TRUE) == FALSE)\r
251         {\r
252                 //GitRev rev;\r
253                 BYTE_VECTOR onelog;\r
254                 TCHAR oldmark=this->m_Mark;\r
255         \r
256                 git->GetLog(onelog,m_CommitHash,NULL,1,CGit::LOG_INFO_STAT|CGit::LOG_INFO_FILESTATE|CGit::LOG_INFO_DETECT_COPYRENAME|CGit::LOG_INFO_SHOW_MERGEDFILE);\r
257                 CString oldhash=m_CommitHash;\r
258                 GIT_REV_LIST oldlist=this->m_ParentHash;\r
259                 ParserFromLog(onelog);\r
260                 \r
261                 //ASSERT(oldhash==m_CommitHash);\r
262                 if(oldmark!=0)\r
263                         this->m_Mark=oldmark;  //parser full log will cause old mark overwrited. \r
264                                                                //So we need keep old bound mark.\r
265                 this->m_ParentHash=oldlist;\r
266                 InterlockedExchange(&m_IsUpdateing,FALSE);\r
267                 InterlockedExchange(&m_IsFull,TRUE);\r
268                 return 0;\r
269         }\r
270         return -1;\r
271 }