Constify and staticify methods
[TortoiseGit.git] / src / Git / GitRev.cpp
blobba304e553cd4ee37e1f97c2ed471468cac9bced7
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2014 - TortoiseGit
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "stdafx.h"
21 #include <ATLComTime.h>
22 #include "GitRev.h"
23 #include "Git.h"
24 #include "gitdll.h"
25 #include "UnicodeUtils.h"
27 class CException; //Just in case afx.h is not included (cannot be included in every project which uses this file)
29 // provide an ASSERT macro for when compiled without MFC
30 #if !defined ASSERT
31 // Don't use _asm here, it isn't supported by x64 version of compiler. In fact, MFC's ASSERT() is the same with _ASSERTE().
32 #define ASSERT(x) _ASSERTE(x)
33 #endif
35 typedef CComCritSecLock<CComCriticalSection> CAutoLocker;
37 GitRev::GitRev(void)
39 m_Action=0;
40 m_RebaseAction = 0;
41 m_IsFull = 0;
42 m_IsUpdateing = 0;
43 m_IsCommitParsed = 0;
44 m_IsDiffFiles = 0;
45 m_CallDiffAsync = NULL;
46 m_IsSimpleListReady =0;
47 m_Mark = 0;
49 memset(&this->m_GitCommit,0,sizeof(GIT_COMMIT));
51 // fetch local machine timezone info
52 if ( GetTimeZoneInformation( &m_TimeZone ) == TIME_ZONE_ID_INVALID )
54 ASSERT(false);
58 GitRev::~GitRev(void)
62 #if 0
63 GitRev::GitRev(GitRev & rev)
66 GitRev& GitRev::operator=(GitRev &rev)
68 return *this;
70 #endif
71 void GitRev::Clear()
73 this->m_Action=0;
74 this->m_Files.Clear();
75 this->m_Action=0;
76 this->m_ParentHash.clear();
77 m_CommitterName.Empty();
78 m_CommitterEmail.Empty();
79 m_Body.Empty();
80 m_Subject.Empty();
81 m_CommitHash.Empty();
82 m_Ref.Empty();
83 m_RefAction.Empty();
84 m_Mark=0;
87 int GitRev::CopyFrom(GitRev &rev,bool OmitParentAndMark)
89 m_AuthorName =rev.m_AuthorName;
90 m_AuthorEmail =rev.m_AuthorEmail;
91 m_AuthorDate =rev.m_AuthorDate;
92 m_CommitterName =rev.m_CommitterName;
93 m_CommitterEmail=rev.m_CommitterEmail;
94 m_CommitterDate =rev.m_CommitterDate;
95 m_Subject =rev.m_Subject;
96 m_Body =rev.m_Body;
97 m_CommitHash =rev.m_CommitHash;
98 m_Files =rev.m_Files;
99 m_Action =rev.m_Action;
100 m_IsFull =rev.m_IsFull;
102 if(!OmitParentAndMark)
104 m_ParentHash =rev.m_ParentHash;
105 m_Mark =rev.m_Mark;
107 return 0;
110 CTime GitRev::ConverFromString(CString input)
112 // pick up date from string
115 COleDateTime tm(_wtoi(input.Mid(0,4)),
116 _wtoi(input.Mid(5,2)),
117 _wtoi(input.Mid(8,2)),
118 _wtoi(input.Mid(11,2)),
119 _wtoi(input.Mid(14,2)),
120 _wtoi(input.Mid(17,2)));
121 if( tm.GetStatus() != COleDateTime::valid )
122 return CTime();//Error parsing time-string
124 // pick up utc offset
125 CString sign = input.Mid(20,1); // + or -
126 int hoursOffset = _wtoi(input.Mid(21,2));
127 int minsOffset = _wtoi(input.Mid(23,2));
128 // convert to a fraction of a day
129 double offset = (hoursOffset*60 + minsOffset) / 1440.0; // 1440 mins = 1 day
130 if ( sign == "-" )
132 offset = -offset;
134 // we have to subtract this from the time given to get UTC
135 tm -= offset;
136 // get utc time as a SYSTEMTIME
137 SYSTEMTIME sysTime;
138 tm.GetAsSystemTime( sysTime );
139 // and convert to users local time
140 SYSTEMTIME local;
141 if ( SystemTimeToTzSpecificLocalTime( &m_TimeZone, &sysTime, &local ) )
143 sysTime = local;
145 else
147 ASSERT(false); // this should not happen but leave time in utc if it does
149 // convert to CTime and return
150 return CTime( sysTime, -1 );
152 catch(CException* e)
154 //Probably the date was something like 1970-01-01 00:00:00. _mktime64() doesnt like this.
155 //Dont let the application crash on this exception
157 #ifdef _AFX //CException classes are only defined when afx.h is included.
158 //When afx.h is not included, the exception is leaked.
159 //This will probably never happen because when CException is not defined, it cannot be thrown.
160 e->Delete();
161 #else
162 UNREFERENCED_PARAMETER(e);
163 #endif //ifdef _AFX
165 return CTime(); //Return an invalid time
168 int GitRev::SafeGetSimpleList(CGit *git)
170 if(InterlockedExchange(&m_IsUpdateing,TRUE) == FALSE)
172 m_SimpleFileList.clear();
173 git->CheckAndInitDll();
174 GIT_COMMIT commit;
175 GIT_COMMIT_LIST list;
176 GIT_HASH parent;
177 memset(&commit,0,sizeof(GIT_COMMIT));
179 CAutoLocker lock(g_Git.m_critGitDllSec);
183 if(git_get_commit_from_hash(&commit, this->m_CommitHash.m_hash))
184 return -1;
186 catch (char *)
188 return -1;
191 int i=0;
192 bool isRoot = this->m_ParentHash.empty();
193 git_get_commit_first_parent(&commit,&list);
194 while(git_get_commit_next_parent(&list,parent) == 0 || isRoot)
196 GIT_FILE file=0;
197 int count=0;
200 if(isRoot)
201 git_root_diff(git->GetGitSimpleListDiff(), commit.m_hash, &file, &count, 0);
202 else
203 git_do_diff(git->GetGitSimpleListDiff(), parent, commit.m_hash, &file, &count, 0);
205 catch (char *)
207 return -1;
210 isRoot = false;
212 CTGitPath path;
213 CString strnewname;
214 CString stroldname;
216 for (int j = 0; j < count; ++j)
218 path.Reset();
219 char *newname;
220 char *oldname;
222 strnewname.Empty();
223 stroldname.Empty();
225 int mode,IsBin,inc,dec;
228 git_get_diff_file(git->GetGitSimpleListDiff(), file, j, &newname, &oldname, &mode, &IsBin, &inc, &dec);
230 catch (char *)
232 return -1;
235 git->StringAppend(&strnewname, (BYTE*)newname, CP_UTF8);
237 m_SimpleFileList.push_back(strnewname);
240 git_diff_flush(git->GetGitSimpleListDiff());
241 ++i;
244 InterlockedExchange(&m_IsUpdateing,FALSE);
245 InterlockedExchange(&m_IsSimpleListReady, TRUE);
246 git_free_commit(&commit);
249 return 0;
251 int GitRev::SafeFetchFullInfo(CGit *git)
253 if(InterlockedExchange(&m_IsUpdateing,TRUE) == FALSE)
255 this->m_Files.Clear();
256 git->CheckAndInitDll();
257 GIT_COMMIT commit;
258 GIT_COMMIT_LIST list;
259 GIT_HASH parent;
260 memset(&commit,0,sizeof(GIT_COMMIT));
262 CAutoLocker lock(g_Git.m_critGitDllSec);
266 if (git_get_commit_from_hash(&commit, this->m_CommitHash.m_hash))
267 return -1;
269 catch (char *)
271 return -1;
274 int i=0;
276 git_get_commit_first_parent(&commit,&list);
277 bool isRoot = (list==NULL);
279 while(git_get_commit_next_parent(&list,parent) == 0 || isRoot)
281 GIT_FILE file=0;
282 int count=0;
286 if (isRoot)
287 git_root_diff(git->GetGitDiff(), this->m_CommitHash.m_hash, &file, &count, 1);
288 else
289 git_do_diff(git->GetGitDiff(), parent, commit.m_hash, &file, &count, 1);
291 catch (char *)
293 git_free_commit(&commit);
294 return -1;
296 isRoot = false;
298 CTGitPath path;
299 CString strnewname;
300 CString stroldname;
302 for (int j = 0; j < count; ++j)
304 path.Reset();
305 char *newname;
306 char *oldname;
308 strnewname.Empty();
309 stroldname.Empty();
311 int mode,IsBin,inc,dec;
312 git_get_diff_file(git->GetGitDiff(),file,j,&newname,&oldname,
313 &mode,&IsBin,&inc,&dec);
315 git->StringAppend(&strnewname, (BYTE*)newname, CP_UTF8);
316 git->StringAppend(&stroldname, (BYTE*)oldname, CP_UTF8);
318 path.SetFromGit(strnewname,&stroldname);
319 path.ParserAction((BYTE)mode);
320 path.m_ParentNo = i;
322 this->m_Action|=path.m_Action;
324 if(IsBin)
326 path.m_StatAdd=_T("-");
327 path.m_StatDel=_T("-");
329 else
331 path.m_StatAdd.Format(_T("%d"),inc);
332 path.m_StatDel.Format(_T("%d"),dec);
334 m_Files.AddPath(path);
336 git_diff_flush(git->GetGitDiff());
337 ++i;
341 InterlockedExchange(&m_IsUpdateing,FALSE);
342 InterlockedExchange(&m_IsFull,TRUE);
343 git_free_commit(&commit);
346 return 0;
349 int GitRev::ParserParentFromCommit(GIT_COMMIT *commit)
351 this->m_ParentHash.clear();
352 GIT_COMMIT_LIST list;
353 GIT_HASH parent;
355 git_get_commit_first_parent(commit,&list);
356 while(git_get_commit_next_parent(&list,parent)==0)
358 m_ParentHash.push_back(CGitHash((char *)parent));
360 return 0;
363 int GitRev::ParserFromCommit(GIT_COMMIT *commit)
365 int encode =CP_UTF8;
367 if(commit->m_Encode != 0 && commit->m_EncodeSize != 0)
369 CString str;
370 g_Git.StringAppend(&str, (BYTE*)commit->m_Encode, CP_UTF8, commit->m_EncodeSize);
371 encode = CUnicodeUtils::GetCPCode(str);
374 this->m_CommitHash = commit->m_hash;
376 this->m_AuthorDate = commit->m_Author.Date;
378 this->m_AuthorEmail.Empty();
379 g_Git.StringAppend(&m_AuthorEmail,(BYTE*)commit->m_Author.Email,encode,commit->m_Author.EmailSize);
381 this->m_AuthorName.Empty();
382 g_Git.StringAppend(&m_AuthorName,(BYTE*)commit->m_Author.Name,encode,commit->m_Author.NameSize);
384 this->m_Body.Empty();
385 g_Git.StringAppend(&m_Body,(BYTE*)commit->m_Body,encode,commit->m_BodySize);
387 this->m_CommitterDate = commit->m_Committer.Date;
389 this->m_CommitterEmail.Empty();
390 g_Git.StringAppend(&m_CommitterEmail, (BYTE*)commit->m_Committer.Email,encode, commit->m_Committer.EmailSize);
392 this->m_CommitterName.Empty();
393 g_Git.StringAppend(&m_CommitterName, (BYTE*)commit->m_Committer.Name,encode, commit->m_Committer.NameSize);
395 this->m_Subject.Empty();
396 g_Git.StringAppend(&m_Subject, (BYTE*)commit->m_Subject,encode,commit->m_SubjectSize);
398 return 0;
400 void GitRev::DbgPrint()
402 ATLTRACE(_T("Commit %s\r\n"), this->m_CommitHash.ToString());
403 for (unsigned int i = 0; i < this->m_ParentHash.size(); ++i)
405 ATLTRACE(_T("Parent %i %s"), i, m_ParentHash[i].ToString());
407 ATLTRACE(_T("\n"));
410 int GitRev::GetParentFromHash(CGitHash &hash)
412 CAutoLocker lock(g_Git.m_critGitDllSec);
414 g_Git.CheckAndInitDll();
416 GIT_COMMIT commit;
417 if(git_get_commit_from_hash( &commit, hash.m_hash))
418 return -1;
420 this->ParserParentFromCommit(&commit);
421 git_free_commit(&commit);
423 this->m_CommitHash=hash;
425 return 0;
427 int GitRev::GetCommitFromHash(CGitHash &hash)
429 CAutoLocker lock(g_Git.m_critGitDllSec);
431 g_Git.CheckAndInitDll();
433 return GetCommitFromHash_withoutLock(hash);
436 int GitRev::GetCommitFromHash_withoutLock(CGitHash &hash)
438 GIT_COMMIT commit;
441 if (git_get_commit_from_hash(&commit, hash.m_hash))
442 return -1;
444 catch (char * msg)
446 MessageBox(NULL, _T("Could not get commit \"") + hash.ToString() + _T("\".\nlibgit reports:\n") + CString(msg), _T("TortoiseGit"), MB_ICONERROR);
447 return -1;
450 this->ParserFromCommit(&commit);
451 git_free_commit(&commit);
453 return 0;
457 int GitRev::GetCommit(CString refname)
459 CAutoLocker lock(g_Git.m_critGitDllSec);
461 g_Git.CheckAndInitDll();
463 if(refname.GetLength() >= 8)
464 if(refname.Find(_T("00000000")) == 0)
466 this->m_CommitHash.Empty();
467 this->m_Subject=_T("Working Copy");
468 return 0;
470 CStringA rev;
471 rev= CUnicodeUtils::GetUTF8(g_Git.FixBranchName(refname));
472 GIT_HASH sha;
476 if (git_get_sha1(rev.GetBuffer(), sha))
477 return -1;
479 catch (char * msg)
481 MessageBox(NULL, _T("Could not get SHA-1 of ref \"") + g_Git.FixBranchName(refname) + _T("\".\nlibgit reports:\n") + CString(msg), _T("TortoiseGit"), MB_ICONERROR);
482 return -1;
485 CGitHash hash((char*)sha);
486 GetCommitFromHash_withoutLock(hash);
487 return 0;
490 int GitRev::AddMergeFiles()
492 std::map<CString, int> map;
493 std::map<CString, int>::iterator it;
495 for (int i = 0; i < m_Files.GetCount(); ++i)
497 if(map.find(m_Files[i].GetGitPathString()) == map.end())
499 map[m_Files[i].GetGitPathString()]=0;
501 else
503 ++map[m_Files[i].GetGitPathString()];
507 for (it = map.begin(); it != map.end(); ++it)
509 if(it->second)
511 CTGitPath path;
512 path.SetFromGit(it->first);
513 path.m_ParentNo = MERGE_MASK;
514 path.m_StatAdd=_T("-");
515 path.m_StatDel=_T("-");
516 path.m_Action = CTGitPath::LOGACTIONS_MERGED;
517 m_Files.AddPath(path);
520 return 0;