2 #include "ATLComTime.h"
6 #include "UnicodeUtils.h"
8 class CException
; //Just in case afx.h is not included (cannot be included in every project which uses this file)
10 // provide an ASSERT macro for when compiled without MFC
12 // Don't use _asm here, it isn't supported by x64 version of compiler. In fact, MFC's ASSERT() is the same with _ASSERTE().
13 #define ASSERT(x) _ASSERTE(x)
22 // fetch local machine timezone info
23 if ( GetTimeZoneInformation( &m_TimeZone
) == TIME_ZONE_ID_INVALID
)
34 GitRev::GitRev(GitRev
& rev
)
37 GitRev
& GitRev::operator=(GitRev
&rev
)
45 this->m_Files
.Clear();
47 this->m_ParentHash
.clear();
48 m_CommitterName
.Empty();
49 m_CommitterEmail
.Empty();
58 int GitRev::CopyFrom(GitRev
&rev
,bool OmitParentAndMark
)
60 m_AuthorName
=rev
.m_AuthorName
;
61 m_AuthorEmail
=rev
.m_AuthorEmail
;
62 m_AuthorDate
=rev
.m_AuthorDate
;
63 m_CommitterName
=rev
.m_CommitterName
;
64 m_CommitterEmail
=rev
.m_CommitterEmail
;
65 m_CommitterDate
=rev
.m_CommitterDate
;
66 m_Subject
=rev
.m_Subject
;
68 m_CommitHash
=rev
.m_CommitHash
;
69 m_Files
=rev
.m_Files
;
70 m_Action
=rev
.m_Action
;
71 m_IsFull
=rev
.m_IsFull
;
73 if(!OmitParentAndMark
)
75 m_ParentHash
=rev
.m_ParentHash
;
80 int GitRev::ParserFromLog(BYTE_VECTOR
&log
,int start
)
89 this->m_Files
.Clear();
94 while( pos
< log
.size() && pos
>=0)
97 //one=log.Tokenize(_T("\n"),pos);
98 if(log
[pos
]==_T('#') && log
[pos
+1] == _T('<') && log
[pos
+3] == _T('>'))
100 //text = one.Right(one.GetLength()-4);
103 g_Git
.StringAppend(&text
,&log
[pos
+4],CGit::m_LogEncode
);
109 case LOG_REV_ITEM_BEGIN
:
116 case LOG_REV_AUTHOR_NAME
:
117 this->m_AuthorName
= text
;
119 case LOG_REV_AUTHOR_EMAIL
:
120 this->m_AuthorEmail
= text
;
122 case LOG_REV_AUTHOR_DATE
:
123 this->m_AuthorDate
=ConverFromString(text
);
125 case LOG_REV_COMMIT_NAME
:
126 this->m_CommitterName
= text
;
128 case LOG_REV_COMMIT_EMAIL
:
129 this->m_CommitterEmail
= text
;
131 case LOG_REV_COMMIT_DATE
:
132 this->m_CommitterDate
=ConverFromString(text
);
134 case LOG_REV_COMMIT_SUBJECT
:
135 this->m_Subject
= text
;
137 case LOG_REV_COMMIT_BODY
:
138 this->m_Body
= text
+_T("\n");
140 case LOG_REV_COMMIT_HASH
:
141 this->m_CommitHash
= text
.Right(40);
142 if(text
.GetLength()>40)
144 this->m_Mark
=text
[0];
147 case LOG_REV_COMMIT_PARENT
:
148 while(text
.GetLength()>0)
150 this->m_ParentHash
.insert(this->m_ParentHash
.end(),text
.Left(40));
151 if(text
.GetLength()>40)
152 text
=text
.Right(text
.GetLength()-41);
156 if(m_ParentHash
.size()>1)
161 case LOG_REV_COMMIT_FILE
:
168 // case LOG_REV_COMMIT_BODY:
169 // this->m_Body += one+_T("\n");
171 case LOG_REV_COMMIT_FILE
:
172 //filelist += one +_T("\n");
173 //filelist.append(log,pos,log.find(0,pos));
185 //find next string start
186 pos
=log
.findNextString(pos
);
192 filelist
.append(log
,filebegin
,pos
);
193 this->m_Files
.ParserFromLog(filelist
);
194 this->m_Action
=this->m_Files
.GetAction();
199 CTime
GitRev::ConverFromString(CString input
)
201 // pick up date from string
204 COleDateTime
tm(_wtoi(input
.Mid(0,4)),
205 _wtoi(input
.Mid(5,2)),
206 _wtoi(input
.Mid(8,2)),
207 _wtoi(input
.Mid(11,2)),
208 _wtoi(input
.Mid(14,2)),
209 _wtoi(input
.Mid(17,2)));
210 if( tm
.GetStatus() != COleDateTime::valid
)
211 return CTime();//Error parsing time-string
213 // pick up utc offset
214 CString sign
= input
.Mid(20,1); // + or -
215 int hoursOffset
= _wtoi(input
.Mid(21,2));
216 int minsOffset
= _wtoi(input
.Mid(23,2));
217 // convert to a fraction of a day
218 double offset
= (hoursOffset
*60 + minsOffset
) / 1440.0; // 1440 mins = 1 day
223 // we have to subtract this from the time given to get UTC
225 // get utc time as a SYSTEMTIME
227 tm
.GetAsSystemTime( sysTime
);
228 // and convert to users local time
230 if ( SystemTimeToTzSpecificLocalTime( &m_TimeZone
, &sysTime
, &local
) )
236 ASSERT(false); // this should not happen but leave time in utc if it does
238 // convert to CTime and return
239 return CTime( sysTime
, -1 );;
243 //Probably the date was something like 1970-01-01 00:00:00. _mktime64() doesnt like this.
244 //Dont let the application crash on this exception
246 #ifdef _AFX //CException classes are only defined when afx.h is included.
247 //When afx.h is not included, the exception is leaked.
248 //This will probably never happen because when CException is not defined, it cannot be thrown.
252 return CTime(); //Return an invalid time
255 int GitRev::SafeFetchFullInfo(CGit
*git
)
257 if(InterlockedExchange(&m_IsUpdateing
,TRUE
) == FALSE
)
262 TCHAR oldmark
=this->m_Mark
;
263 CString commithash
= m_CommitHash
;
264 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
);
265 CString oldhash
=m_CommitHash
;
266 GIT_REV_LIST oldlist
=this->m_ParentHash
;
267 ParserFromLog(onelog
);
269 //ASSERT(oldhash==m_CommitHash);
271 this->m_Mark
=oldmark
; //parser full log will cause old mark overwrited.
272 //So we need keep old bound mark.
273 this->m_ParentHash
=oldlist
;
274 InterlockedExchange(&m_IsUpdateing
,FALSE
);
275 InterlockedExchange(&m_IsFull
,TRUE
);
278 this->m_Files
.Clear();
279 git
->CheckAndInitDll();
281 GIT_COMMIT_LIST list
;
283 memset(&commit
,0,sizeof(GIT_COMMIT
));
285 if(git_get_commit_from_hash(&commit
, this->m_CommitHash
.m_hash
))
289 bool isRoot
= this->m_ParentHash
.size()==0;
290 git_get_commit_first_parent(&commit
,&list
);
291 while(git_get_commit_next_parent(&list
,parent
) == 0 || isRoot
)
296 git_root_diff(git
->GetGitDiff(), this->m_CommitHash
.m_hash
, &file
, &count
);
298 git_diff(git
->GetGitDiff(),parent
,commit
.m_hash
,&file
,&count
);
306 for(int j
=0;j
<count
;j
++)
315 int mode
,IsBin
,inc
,dec
;
316 git_get_diff_file(git
->GetGitDiff(),file
,j
,&newname
,&oldname
,
317 &mode
,&IsBin
,&inc
,&dec
);
319 git
->StringAppend(&strnewname
,(BYTE
*)newname
,CP_ACP
);
320 git
->StringAppend(&stroldname
,(BYTE
*)oldname
,CP_ACP
);
323 path
.SetFromGit(strnewname
,&stroldname
);
324 path
.ParserAction((BYTE
)mode
);
326 this->m_Action
|=path
.m_Action
;
330 path
.m_StatAdd
=_T("-");
331 path
.m_StatDel
=_T("-");
334 path
.m_StatAdd
.Format(_T("%d"),inc
);
335 path
.m_StatDel
.Format(_T("%d"),dec
);
337 m_Files
.AddPath(path
);
339 git_diff_flush(git
->GetGitDiff());
344 InterlockedExchange(&m_IsUpdateing
,FALSE
);
345 InterlockedExchange(&m_IsFull
,TRUE
);
346 git_free_commit(&commit
);
352 int GitRev::ParserParentFromCommit(GIT_COMMIT
*commit
)
354 this->m_ParentHash
.clear();
355 GIT_COMMIT_LIST list
;
358 git_get_commit_first_parent(commit
,&list
);
359 while(git_get_commit_next_parent(&list
,parent
)==0)
361 m_ParentHash
.push_back(CGitHash((char *)parent
));
366 int GitRev::ParserFromCommit(GIT_COMMIT
*commit
)
370 if(commit
->m_Encode
!= 0 && commit
->m_EncodeSize
!= 0)
373 g_Git
.StringAppend(&str
, (BYTE
*)commit
->m_Encode
, CP_UTF8
, commit
->m_EncodeSize
);
374 encode
= CUnicodeUtils::GetCPCode(str
);
377 this->m_AuthorDate
= commit
->m_Author
.Date
;
379 this->m_AuthorEmail
.Empty();
380 g_Git
.StringAppend(&m_AuthorEmail
,(BYTE
*)commit
->m_Author
.Email
,CP_UTF8
,commit
->m_Author
.EmailSize
);
382 this->m_AuthorName
.Empty();
383 g_Git
.StringAppend(&m_AuthorName
,(BYTE
*)commit
->m_Author
.Name
,CP_UTF8
,commit
->m_Author
.NameSize
);
385 this->m_Body
.Empty();
386 g_Git
.StringAppend(&m_Body
,(BYTE
*)commit
->m_Body
,encode
,commit
->m_BodySize
);
388 this->m_CommitterDate
= commit
->m_Committer
.Date
;
390 this->m_CommitterEmail
.Empty();
391 g_Git
.StringAppend(&m_CommitterEmail
, (BYTE
*)commit
->m_Committer
.Email
,CP_UTF8
, commit
->m_Committer
.EmailSize
);
393 this->m_CommitterName
.Empty();
394 g_Git
.StringAppend(&m_CommitterName
, (BYTE
*)commit
->m_Committer
.Name
,CP_UTF8
, commit
->m_Committer
.NameSize
);
396 this->m_Subject
.Empty();
397 g_Git
.StringAppend(&m_Subject
, (BYTE
*)commit
->m_Subject
,encode
,commit
->m_SubjectSize
);
402 #define TRACE(x) 1?0:(x)
404 void GitRev::DbgPrint()
406 TRACE(_T("Commit %s\r\n"), this->m_CommitHash
.ToString());
407 for(int i
=0;i
<this->m_ParentHash
.size();i
++)
409 TRACE(_T("Parent %i %s"),i
, m_ParentHash
[i
].ToString());
414 int GitRev::GetCommitFromHash(CGitHash
&hash
)
416 g_Git
.CheckAndInitDll();
419 if(git_get_commit_from_hash( &commit
, hash
.m_hash
))
422 this->ParserFromCommit(&commit
);
423 git_free_commit(&commit
);
425 this->m_CommitHash
=hash
;
431 int GitRev::GetCommit(CString
&refname
)
433 g_Git
.CheckAndInitDll();
435 if(refname
.GetLength() >= 8)
436 if(refname
.Find(_T("00000000")) == 0)
438 this->m_CommitHash
.Empty();
439 this->m_Subject
=_T("Working Copy");
443 rev
= CUnicodeUtils::GetUTF8(refname
);
446 if(git_get_sha1(rev
.GetBuffer(),sha
))
449 GetCommitFromHash(CGitHash((char*)sha
));