Use CUnicodeUtils::GetUnicode instead of CGit::StringAppend if possible
[TortoiseGit.git] / src / Git / GitRev.cpp
blob1ea113f3d837538f6c637c617974c65c0d8bfffb
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2015 - 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));
52 GitRev::~GitRev(void)
56 #if 0
57 GitRev::GitRev(GitRev & rev)
60 GitRev& GitRev::operator=(GitRev &rev)
62 return *this;
64 #endif
65 void GitRev::Clear()
67 this->m_Action=0;
68 this->m_Files.Clear();
69 this->m_Action=0;
70 this->m_ParentHash.clear();
71 m_CommitterName.Empty();
72 m_CommitterEmail.Empty();
73 m_Body.Empty();
74 m_Subject.Empty();
75 m_CommitHash.Empty();
76 m_Ref.Empty();
77 m_RefAction.Empty();
78 m_Mark=0;
81 int GitRev::CopyFrom(GitRev &rev,bool OmitParentAndMark)
83 m_AuthorName =rev.m_AuthorName;
84 m_AuthorEmail =rev.m_AuthorEmail;
85 m_AuthorDate =rev.m_AuthorDate;
86 m_CommitterName =rev.m_CommitterName;
87 m_CommitterEmail=rev.m_CommitterEmail;
88 m_CommitterDate =rev.m_CommitterDate;
89 m_Subject =rev.m_Subject;
90 m_Body =rev.m_Body;
91 m_CommitHash =rev.m_CommitHash;
92 m_Files =rev.m_Files;
93 m_Action =rev.m_Action;
94 m_IsFull =rev.m_IsFull;
96 if(!OmitParentAndMark)
98 m_ParentHash =rev.m_ParentHash;
99 m_Mark =rev.m_Mark;
101 return 0;
104 int GitRev::SafeGetSimpleList(CGit *git)
106 if(InterlockedExchange(&m_IsUpdateing,TRUE) == FALSE)
108 m_SimpleFileList.clear();
109 git->CheckAndInitDll();
110 GIT_COMMIT commit;
111 GIT_COMMIT_LIST list;
112 GIT_HASH parent;
113 memset(&commit,0,sizeof(GIT_COMMIT));
115 CAutoLocker lock(g_Git.m_critGitDllSec);
119 if(git_get_commit_from_hash(&commit, this->m_CommitHash.m_hash))
120 return -1;
122 catch (char *)
124 return -1;
127 int i=0;
128 bool isRoot = this->m_ParentHash.empty();
129 git_get_commit_first_parent(&commit,&list);
130 while(git_get_commit_next_parent(&list,parent) == 0 || isRoot)
132 GIT_FILE file=0;
133 int count=0;
136 if(isRoot)
137 git_root_diff(git->GetGitSimpleListDiff(), commit.m_hash, &file, &count, 0);
138 else
139 git_do_diff(git->GetGitSimpleListDiff(), parent, commit.m_hash, &file, &count, 0);
141 catch (char *)
143 return -1;
146 isRoot = false;
148 CTGitPath path;
149 CString strnewname;
150 CString stroldname;
152 for (int j = 0; j < count; ++j)
154 path.Reset();
155 char *newname;
156 char *oldname;
158 strnewname.Empty();
159 stroldname.Empty();
161 int mode,IsBin,inc,dec;
164 git_get_diff_file(git->GetGitSimpleListDiff(), file, j, &newname, &oldname, &mode, &IsBin, &inc, &dec);
166 catch (char *)
168 return -1;
171 git->StringAppend(&strnewname, (BYTE*)newname, CP_UTF8);
173 m_SimpleFileList.push_back(strnewname);
176 git_diff_flush(git->GetGitSimpleListDiff());
177 ++i;
180 InterlockedExchange(&m_IsUpdateing,FALSE);
181 InterlockedExchange(&m_IsSimpleListReady, TRUE);
182 git_free_commit(&commit);
185 return 0;
187 int GitRev::SafeFetchFullInfo(CGit *git)
189 if(InterlockedExchange(&m_IsUpdateing,TRUE) == FALSE)
191 this->m_Files.Clear();
192 git->CheckAndInitDll();
193 GIT_COMMIT commit;
194 GIT_COMMIT_LIST list;
195 GIT_HASH parent;
196 memset(&commit,0,sizeof(GIT_COMMIT));
198 CAutoLocker lock(g_Git.m_critGitDllSec);
202 if (git_get_commit_from_hash(&commit, this->m_CommitHash.m_hash))
203 return -1;
205 catch (char *)
207 return -1;
210 int i=0;
212 git_get_commit_first_parent(&commit,&list);
213 bool isRoot = (list==NULL);
215 while(git_get_commit_next_parent(&list,parent) == 0 || isRoot)
217 GIT_FILE file=0;
218 int count=0;
222 if (isRoot)
223 git_root_diff(git->GetGitDiff(), this->m_CommitHash.m_hash, &file, &count, 1);
224 else
225 git_do_diff(git->GetGitDiff(), parent, commit.m_hash, &file, &count, 1);
227 catch (char *)
229 git_free_commit(&commit);
230 return -1;
232 isRoot = false;
234 CTGitPath path;
235 CString strnewname;
236 CString stroldname;
238 for (int j = 0; j < count; ++j)
240 path.Reset();
241 char *newname;
242 char *oldname;
244 strnewname.Empty();
245 stroldname.Empty();
247 int mode,IsBin,inc,dec;
248 git_get_diff_file(git->GetGitDiff(),file,j,&newname,&oldname,
249 &mode,&IsBin,&inc,&dec);
251 git->StringAppend(&strnewname, (BYTE*)newname, CP_UTF8);
252 git->StringAppend(&stroldname, (BYTE*)oldname, CP_UTF8);
254 path.SetFromGit(strnewname,&stroldname);
255 path.ParserAction((BYTE)mode);
256 path.m_ParentNo = i;
258 this->m_Action|=path.m_Action;
260 if(IsBin)
262 path.m_StatAdd=_T("-");
263 path.m_StatDel=_T("-");
265 else
267 path.m_StatAdd.Format(_T("%d"),inc);
268 path.m_StatDel.Format(_T("%d"),dec);
270 m_Files.AddPath(path);
272 git_diff_flush(git->GetGitDiff());
273 ++i;
277 InterlockedExchange(&m_IsUpdateing,FALSE);
278 InterlockedExchange(&m_IsFull,TRUE);
279 git_free_commit(&commit);
282 return 0;
285 int GitRev::ParserParentFromCommit(GIT_COMMIT *commit)
287 this->m_ParentHash.clear();
288 GIT_COMMIT_LIST list;
289 GIT_HASH parent;
291 git_get_commit_first_parent(commit,&list);
292 while(git_get_commit_next_parent(&list,parent)==0)
294 m_ParentHash.push_back(CGitHash((char *)parent));
296 return 0;
299 int GitRev::ParserFromCommit(GIT_COMMIT *commit)
301 int encode =CP_UTF8;
303 if(commit->m_Encode != 0 && commit->m_EncodeSize != 0)
305 CString str;
306 CGit::StringAppend(&str, (BYTE*)commit->m_Encode, CP_UTF8, commit->m_EncodeSize);
307 encode = CUnicodeUtils::GetCPCode(str);
310 this->m_CommitHash = commit->m_hash;
312 this->m_AuthorDate = commit->m_Author.Date;
314 this->m_AuthorEmail.Empty();
315 CGit::StringAppend(&m_AuthorEmail, (BYTE*)commit->m_Author.Email, encode, commit->m_Author.EmailSize);
317 this->m_AuthorName.Empty();
318 CGit::StringAppend(&m_AuthorName, (BYTE*)commit->m_Author.Name, encode, commit->m_Author.NameSize);
320 this->m_Body.Empty();
321 CGit::StringAppend(&m_Body, (BYTE*)commit->m_Body, encode, commit->m_BodySize);
323 this->m_CommitterDate = commit->m_Committer.Date;
325 this->m_CommitterEmail.Empty();
326 CGit::StringAppend(&m_CommitterEmail, (BYTE*)commit->m_Committer.Email, encode, commit->m_Committer.EmailSize);
328 this->m_CommitterName.Empty();
329 CGit::StringAppend(&m_CommitterName, (BYTE*)commit->m_Committer.Name, encode, commit->m_Committer.NameSize);
331 this->m_Subject.Empty();
332 CGit::StringAppend(&m_Subject, (BYTE*)commit->m_Subject,encode,commit->m_SubjectSize);
334 return 0;
336 void GitRev::DbgPrint()
338 ATLTRACE(_T("Commit %s\r\n"), this->m_CommitHash.ToString());
339 for (unsigned int i = 0; i < this->m_ParentHash.size(); ++i)
341 ATLTRACE(_T("Parent %i %s"), i, m_ParentHash[i].ToString());
343 ATLTRACE(_T("\n"));
346 int GitRev::GetParentFromHash(CGitHash &hash)
348 CAutoLocker lock(g_Git.m_critGitDllSec);
350 g_Git.CheckAndInitDll();
352 GIT_COMMIT commit;
353 if(git_get_commit_from_hash( &commit, hash.m_hash))
354 return -1;
356 this->ParserParentFromCommit(&commit);
357 git_free_commit(&commit);
359 this->m_CommitHash=hash;
361 return 0;
363 int GitRev::GetCommitFromHash(CGitHash &hash)
365 CAutoLocker lock(g_Git.m_critGitDllSec);
367 g_Git.CheckAndInitDll();
369 return GetCommitFromHash_withoutLock(hash);
372 int GitRev::GetCommitFromHash_withoutLock(CGitHash &hash)
374 GIT_COMMIT commit;
377 if (git_get_commit_from_hash(&commit, hash.m_hash))
378 return -1;
380 catch (char * msg)
382 MessageBox(NULL, _T("Could not get commit \"") + hash.ToString() + _T("\".\nlibgit reports:\n") + CString(msg), _T("TortoiseGit"), MB_ICONERROR);
383 return -1;
386 this->ParserFromCommit(&commit);
387 git_free_commit(&commit);
389 return 0;
393 int GitRev::GetCommit(CString refname)
395 CAutoLocker lock(g_Git.m_critGitDllSec);
397 g_Git.CheckAndInitDll();
399 if(refname.GetLength() >= 8)
400 if(refname.Find(_T("00000000")) == 0)
402 this->m_CommitHash.Empty();
403 this->m_Subject=_T("Working Copy");
404 return 0;
406 CStringA rev;
407 rev= CUnicodeUtils::GetUTF8(g_Git.FixBranchName(refname));
408 GIT_HASH sha;
412 if (git_get_sha1(rev.GetBuffer(), sha))
413 return -1;
415 catch (char * msg)
417 MessageBox(NULL, _T("Could not get SHA-1 of ref \"") + g_Git.FixBranchName(refname) + _T("\".\nlibgit reports:\n") + CString(msg), _T("TortoiseGit"), MB_ICONERROR);
418 return -1;
421 CGitHash hash((char*)sha);
422 GetCommitFromHash_withoutLock(hash);
423 return 0;
426 int GitRev::AddMergeFiles()
428 std::map<CString, int> map;
429 std::map<CString, int>::iterator it;
431 for (int i = 0; i < m_Files.GetCount(); ++i)
433 if(map.find(m_Files[i].GetGitPathString()) == map.end())
435 map[m_Files[i].GetGitPathString()]=0;
437 else
439 ++map[m_Files[i].GetGitPathString()];
443 for (it = map.begin(); it != map.end(); ++it)
445 if(it->second)
447 CTGitPath path;
448 path.SetFromGit(it->first);
449 path.m_ParentNo = MERGE_MASK;
450 path.m_StatAdd=_T("-");
451 path.m_StatDel=_T("-");
452 path.m_Action = CTGitPath::LOGACTIONS_MERGED;
453 m_Files.AddPath(path);
456 return 0;