TrackGit
Log.cpp
Go to the documentation of this file.
1 
8 #include "Log.h"
9 #include "../UI/LogWindow.h"
10 
11 #include <InterfaceKit.h>
12 
13 #include <stdlib.h>
14 #include <strings.h>
15 
16 
22 Log::Log(BString repo)
23  :
24  GitCommand()
25 {
26  fRepo = repo;
27  fLogWindow = NULL;
28 }
29 
30 
37 {
38  if (fLogWindow == NULL)
39  fLogWindow = new LogWindow(fRepo);
40  return fLogWindow;
41 }
42 
43 
48 void
50 {
51  BString logText = GetLogText();
52 
53  if (!fLogWindow) {
54  fLogWindow->Quit();
55  return;
56  }
57 
58  fLogWindow->SetText(logText);
59 }
60 
61 
69 void check_lg2(int error, const char* message, const char* extra)
70 {
71  const char *lg_msg = "";
72  if (!error)
73  return;
74 
75  const git_error* err = giterr_last();
76  if (err)
77  lg_msg = err->message;
78 
79  BString buffer("Error : %s. %s");
80  buffer.ReplaceFirst("%s", message);
81  buffer.ReplaceFirst("%s", lg_msg);
82  BAlert* alert = new BAlert("", buffer.String(), "Cancel",
83  0, 0, B_WIDTH_AS_USUAL, B_WARNING_ALERT);
84  alert->Go();
85 }
86 
87 
91 static void print_time(const git_time *intime, const char *prefix,
92  BString &text)
93 {
94  char sign, out[32];
95  struct tm *intm;
96  int offset, hours, minutes;
97  time_t t;
98 
99  offset = intime->offset;
100  if (offset < 0) {
101  sign = '-';
102  offset = -offset;
103  } else {
104  sign = '+';
105  }
106 
107  hours = offset / 60;
108  minutes = offset % 60;
109 
110  t = (time_t)intime->time + (intime->offset * 60);
111 
112  intm = gmtime(&t);
113  strftime(out, sizeof(out), "%a %b %e %T %Y", intm);
114 
115  text << prefix << out << " "<< sign << hours << minutes << "\n";
116 }
117 
118 
122 static void print_commit(git_commit *commit, struct log_options *opts,
123  BString &text)
124 {
125  char buf[GIT_OID_HEXSZ + 1];
126  int i, count;
127  const git_signature *sig;
128  const char *scan, *eol;
129 
130  git_oid_tostr(buf, sizeof(buf), git_commit_id(commit));
131  text << "commit " << buf << "\n";
132 
133  if ((count = (int)git_commit_parentcount(commit)) > 1) {
134  text << "Merge: ";
135  for (i = 0; i < count; ++i) {
136  git_oid_tostr(buf, 8, git_commit_parent_id(commit, i));
137  text << buf;
138  }
139  text << "\n";
140  }
141 
142  if ((sig = git_commit_author(commit)) != NULL) {
143  text << "Author: " << sig->name << " <" << sig->email << ">\n";
144  print_time(&sig->when, "Date: ", text);
145  }
146  text << "\n";
147 
148  for (scan = git_commit_message(commit); scan && *scan; ) {
149  for (eol = scan; *eol && *eol != '\n'; ++eol) /* find eol */;
150 
151  text << "\t" << scan << "\n";
152  scan = *eol ? eol + 1 : NULL;
153  }
154  text << "\n";
155 }
156 
157 
161 static void push_rev(struct log_state *s, git_object *obj, int hide)
162 {
163  hide = s->hide ^ hide;
164 
166  if (!s->walker) {
167  check_lg2(git_revwalk_new(&s->walker, s->repo),
168  "Could not create revision walker", NULL);
169  git_revwalk_sorting(s->walker, s->sorting);
170  }
171 
172  if (!obj)
173  check_lg2(git_revwalk_push_head(s->walker),
174  "Could not find repository HEAD", NULL);
175  else if (hide)
176  check_lg2(git_revwalk_hide(s->walker, git_object_id(obj)),
177  "Reference does not refer to a commit", NULL);
178  else
179  check_lg2(git_revwalk_push(s->walker, git_object_id(obj)),
180  "Reference does not refer to a commit", NULL);
181 
182  git_object_free(obj);
183 }
184 
188 static int add_revision(struct log_state *s, const char *revstr)
189 {
190  git_revspec revs;
191  int hide = 0;
192 
194  if (!s->repo) {
195  if (!s->repodir) s->repodir = ".";
196  check_lg2(git_repository_open_ext(&s->repo, s->repodir, 0, NULL),
197  "Could not open repository", s->repodir);
198  }
199 
200  if (!revstr) {
201  push_rev(s, NULL, hide);
202  return 0;
203  }
204 
205  if (*revstr == '^') {
206  revs.flags = GIT_REVPARSE_SINGLE;
207  hide = !hide;
208 
209  if (git_revparse_single(&revs.from, s->repo, revstr + 1) < 0)
210  return -1;
211  } else if (git_revparse(&revs, s->repo, revstr) < 0)
212  return -1;
213 
214  if ((revs.flags & GIT_REVPARSE_SINGLE) != 0)
215  push_rev(s, revs.from, hide);
216  else {
217  push_rev(s, revs.to, hide);
218 
219  if ((revs.flags & GIT_REVPARSE_MERGE_BASE) != 0) {
220  git_oid base;
221  check_lg2(git_merge_base(&base, s->repo,
222  git_object_id(revs.from), git_object_id(revs.to)),
223  "Could not find merge base", revstr);
224  check_lg2(
225  git_object_lookup(&revs.to, s->repo, &base, GIT_OBJ_COMMIT),
226  "Could not find merge base commit", NULL);
227 
228  push_rev(s, revs.to, hide);
229  }
230 
231  push_rev(s, revs.from, !hide);
232  }
233 
234  return 0;
235 }
236 
237 
242 BString
244 {
245  git_repository *repo = NULL;
246  BString text;
247  int i, count = 0, printed = 0, parents;
248  struct log_state s;
249  struct log_options opt;
250  git_diff_options diffopts = GIT_DIFF_OPTIONS_INIT;
251  git_oid oid;
252  git_commit *commit = NULL;
253  git_pathspec *ps = NULL;
254 
255  git_libgit2_init();
256 
257  memset(&s, 0, sizeof(s));
258  s.sorting = GIT_SORT_TIME;
259  s.repodir = fRepo.String();
260 
261  memset(&opt, 0, sizeof(opt));
262  opt.max_parents = -1;
263  opt.limit = -1;
264 
265  if (!s.revisions)
266  add_revision(&s, NULL);
267 
270  printed = count = 0;
271 
272  for (; !git_revwalk_next(&oid, s.walker); git_commit_free(commit)) {
273  check_lg2(git_commit_lookup(&commit, s.repo, &oid),
274  "Failed to look up commit", NULL);
275 
276  print_commit(commit, &opt, text);
277  }
278 
279  git_pathspec_free(ps);
280  git_repository_free(repo);
281  git_libgit2_shutdown();
282 
283  return text;
284 }
int revisions
Definition: Log.h:27
int hide
Definition: Log.h:25
const char * repodir
Definition: Log.h:23
virtual void Execute()
Log command execution.
Definition: Log.cpp:49
Status Options structure.
Definition: Status.h:23
int sorting
Definition: Log.h:26
log_options holds other command line options that affect log output
Definition: Log.h:34
The Log Window class.
Definition: LogWindow.h:20
virtual void Quit()
The function to Quit the window.
Log(BString)
Log class Constructor.
Definition: Log.cpp:22
int max_parents
Definition: Log.h:38
BString GetLogText()
Constructs the entire Log Text for given repo.
Definition: Log.cpp:243
GitCommand Class.
Definition: GitCommand.h:20
static void print_time(const git_time *intime, const char *prefix, BString &text)
Helper to format a git_time value like Git.
Definition: Log.cpp:91
Header file of Log command.
log_state represents walker being configured while handling options
Definition: Log.h:21
git_repository * repo
Definition: Log.h:22
void SetText(BString)
Sets Text of the View in Window.
Definition: LogWindow.cpp:58
static void print_commit(git_commit *commit, struct log_options *opts, BString &text)
Helper to print a commit object.
Definition: Log.cpp:122
LogWindow * fLogWindow
The Log Window.
Definition: Log.h:58
git_revwalk * walker
Definition: Log.h:24
void check_lg2(int error, const char *message, const char *extra)
Checks if libgit2 api was successfully executed.
Definition: Log.cpp:69
The TrackGit Window class.
virtual TrackGitWindow * GetWindow()
This returns pointer to the log window.
Definition: Log.cpp:36
static void push_rev(struct log_state *s, git_object *obj, int hide)
Push object (for hide or show) onto revwalker.
Definition: Log.cpp:161
int limit
Definition: Log.h:37
static int add_revision(struct log_state *s, const char *revstr)
Parse revision string and add revs to walker.
Definition: Log.cpp:188
BString fRepo
The repo/directory where command is called.
Definition: Log.h:54