OSDN Git Service

Add Revert to Version feature.
[tortoisegit/TortoiseGitJp.git] / src / Git / GitRev.cpp
1 #include "StdAfx.h"\r
2 #include "GitRev.h"\r
3 #include "Git.h"\r
4 \r
5 // provide an ASSERT macro for when compiled without MFC\r
6 #if !defined ASSERT\r
7         // 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
8         #define ASSERT(x) _ASSERTE(x)\r
9 #endif\r
10 \r
11 \r
12 GitRev::GitRev(void)\r
13 {\r
14         m_Action=0;\r
15         m_IsFull = 0;\r
16         m_IsUpdateing = 0;\r
17         // fetch local machine timezone info\r
18         if ( GetTimeZoneInformation( &m_TimeZone ) == TIME_ZONE_ID_INVALID )\r
19         {\r
20                 ASSERT(false);\r
21         }\r
22 }\r
23 \r
24 GitRev::~GitRev(void)\r
25 {\r
26 }\r
27 \r
28 #if 0\r
29 GitRev::GitRev(GitRev & rev)\r
30 {\r
31 }\r
32 GitRev& GitRev::operator=(GitRev &rev)\r
33 {\r
34         return *this;\r
35 }\r
36 #endif\r
37 void GitRev::Clear()\r
38 {\r
39         this->m_Action=0;\r
40         this->m_Files.Clear();\r
41         this->m_Action=0;\r
42         this->m_ParentHash.clear();\r
43         m_CommitterName.Empty();\r
44         m_CommitterEmail.Empty();\r
45         m_Body.Empty();\r
46         m_Subject.Empty();\r
47         m_CommitHash.Empty();\r
48         m_Mark=0;\r
49 \r
50 }\r
51 int GitRev::CopyFrom(GitRev &rev,bool OmitParentAndMark)\r
52 {\r
53         m_AuthorName    =rev.m_AuthorName       ;\r
54         m_AuthorEmail   =rev.m_AuthorEmail      ;\r
55         m_AuthorDate    =rev.m_AuthorDate       ;\r
56         m_CommitterName =rev.m_CommitterName    ;\r
57         m_CommitterEmail=rev.m_CommitterEmail;\r
58         m_CommitterDate =rev.m_CommitterDate    ;\r
59         m_Subject               =rev.m_Subject          ;\r
60         m_Body                  =rev.m_Body                     ;\r
61         m_CommitHash    =rev.m_CommitHash       ;\r
62         m_Files                 =rev.m_Files                    ;       \r
63         m_Action                =rev.m_Action           ;\r
64 \r
65         if(!OmitParentAndMark)\r
66         {\r
67                 m_ParentHash    =rev.m_ParentHash       ;\r
68                 m_Mark                  =rev.m_Mark;\r
69         }\r
70         return 0;\r
71 }\r
72 int GitRev::ParserFromLog(BYTE_VECTOR &log,int start)\r
73 {\r
74         int pos=start;\r
75         CString one;\r
76         CString key;\r
77         CString text;\r
78         BYTE_VECTOR filelist;\r
79         BYTE mode=0;\r
80         CTGitPath  path;\r
81         this->m_Files.Clear();\r
82     m_Action=0;\r
83         int begintime=0;\r
84         int filebegin=-1;\r
85 \r
86         while( pos < log.size() && pos>=0)\r
87         {\r
88                 \r
89                 //one=log.Tokenize(_T("\n"),pos);\r
90                 if(log[pos]==_T('#') && log[pos+1] == _T('<') && log[pos+3] == _T('>'))\r
91                 {\r
92                         //text = one.Right(one.GetLength()-4);\r
93                         text.Empty();\r
94                         g_Git.StringAppend(&text,&log[pos+4],CP_UTF8);\r
95                         mode = log[pos+2];\r
96                         \r
97                         switch(mode)\r
98                         {\r
99                         case LOG_REV_ITEM_BEGIN:\r
100                                 begintime++;\r
101                                 if(begintime>1)\r
102                                         break;\r
103                                 else\r
104                                         this->Clear();\r
105                                 break;\r
106                         case LOG_REV_AUTHOR_NAME:\r
107                                 this->m_AuthorName = text;\r
108                                 break;\r
109                         case LOG_REV_AUTHOR_EMAIL:\r
110                                 this->m_AuthorEmail = text;\r
111                                 break;\r
112                         case LOG_REV_AUTHOR_DATE:\r
113                                 this->m_AuthorDate =ConverFromString(text);\r
114                                 break;\r
115                         case LOG_REV_COMMIT_NAME:\r
116                                 this->m_CommitterName = text;\r
117                                 break;\r
118                         case LOG_REV_COMMIT_EMAIL:\r
119                                 this->m_CommitterEmail = text;\r
120                                 break;\r
121                         case LOG_REV_COMMIT_DATE:\r
122                                 this->m_CommitterDate =ConverFromString(text);\r
123                                 break;\r
124                         case LOG_REV_COMMIT_SUBJECT:\r
125                                 this->m_Subject = text;\r
126                                 break;\r
127                         case LOG_REV_COMMIT_BODY:\r
128                                 this->m_Body = text +_T("\n");\r
129                                 break;\r
130                         case LOG_REV_COMMIT_HASH:\r
131                                 this->m_CommitHash = text.Right(40);\r
132                                 if(text.GetLength()>40)\r
133                                 {\r
134                                         this->m_Mark=text[0];\r
135                                 }\r
136                                 break;\r
137                         case LOG_REV_COMMIT_PARENT:\r
138                                 while(text.GetLength()>0)\r
139                                 {\r
140                                         this->m_ParentHash.insert(this->m_ParentHash.end(),text.Left(40));\r
141                                         if(text.GetLength()>40)\r
142                                                 text=text.Right(text.GetLength()-41);\r
143                                         else\r
144                                                 break;\r
145                                 }\r
146                                 break;\r
147                         case LOG_REV_COMMIT_FILE:\r
148                                 break;\r
149                         }\r
150                 }else\r
151                 {\r
152                         switch(mode)\r
153                         {\r
154 //                      case LOG_REV_COMMIT_BODY:\r
155 //                              this->m_Body += one+_T("\n");\r
156 //                              break;\r
157                         case LOG_REV_COMMIT_FILE:\r
158                                 //filelist += one +_T("\n");\r
159                                 //filelist.append(log,pos,log.find(0,pos));\r
160                                 if(filebegin<0)\r
161                                         filebegin=pos;\r
162                                 break;\r
163                         }\r
164                 }\r
165                 \r
166                 if(begintime>1)\r
167                 {\r
168                         break;\r
169                 }\r
170 \r
171                 //find next string start \r
172                 pos=log.findNextString(pos);\r
173         }\r
174         \r
175         if(filebegin>=0)\r
176         {\r
177                 filelist.append(log,filebegin,pos);     \r
178                 this->m_Files.ParserFromLog(filelist);\r
179                 this->m_Action=this->m_Files.GetAction();\r
180         }\r
181         return pos;\r
182 }\r
183 \r
184 CTime GitRev::ConverFromString(CString input)\r
185 {\r
186         // pick up date from string\r
187         CTime tm(_wtoi(input.Mid(0,4)),\r
188                          _wtoi(input.Mid(5,2)),\r
189                          _wtoi(input.Mid(8,2)),\r
190                          _wtoi(input.Mid(11,2)),\r
191                          _wtoi(input.Mid(14,2)),\r
192                          _wtoi(input.Mid(17,2)),\r
193                          0);\r
194         // pick up utc offset\r
195         CString sign = input.Mid(20,1);         // + or -\r
196         int hoursOffset =  _wtoi(input.Mid(21,2));\r
197         int minsOffset = _wtoi(input.Mid(23,2));\r
198         if ( sign == "-" )\r
199         {\r
200                 hoursOffset = -hoursOffset;\r
201                 minsOffset = -minsOffset;\r
202         }\r
203         // make a timespan object with this value\r
204         CTimeSpan offset( 0, hoursOffset, minsOffset, 0 );\r
205         // we have to subtract this from the time given to get UTC\r
206         tm -= offset;\r
207         // get local timezone\r
208         SYSTEMTIME sysTime;\r
209         tm.GetAsSystemTime( sysTime );\r
210         SYSTEMTIME local;\r
211         if ( SystemTimeToTzSpecificLocalTime( &m_TimeZone, &sysTime, &local ) )\r
212         {\r
213                 sysTime = local;\r
214         }\r
215         else\r
216         {\r
217                 ASSERT(false);\r
218         }\r
219         tm = CTime( sysTime, 0 );\r
220         return tm;\r
221 }\r
222 \r
223 int GitRev::SafeFetchFullInfo(CGit *git)\r
224 {\r
225         if(InterlockedExchange(&m_IsUpdateing,TRUE) == FALSE)\r
226         {\r
227                 //GitRev rev;\r
228                 BYTE_VECTOR onelog;\r
229                 TCHAR oldmark=this->m_Mark;\r
230         \r
231                 git->GetLog(onelog,m_CommitHash,NULL,1,CGit::LOG_INFO_STAT|CGit::LOG_INFO_FILESTATE|CGit::LOG_INFO_DETECT_COPYRENAME);\r
232                 CString oldhash=m_CommitHash;\r
233                 GIT_REV_LIST oldlist=this->m_ParentHash;\r
234                 ParserFromLog(onelog);\r
235                 \r
236                 //ASSERT(oldhash==m_CommitHash);\r
237                 if(oldmark!=0)\r
238                         this->m_Mark=oldmark;  //parser full log will cause old mark overwrited. \r
239                                                                //So we need keep old bound mark.\r
240                 this->m_ParentHash=oldlist;\r
241                 InterlockedExchange(&m_IsUpdateing,FALSE);\r
242                 InterlockedExchange(&m_IsFull,TRUE);\r
243                 return 0;\r
244         }\r
245         return -1;\r
246 }