BioDynaMo  v1.05.119-a4ff3934
git_tracker.cc
Go to the documentation of this file.
1 // -----------------------------------------------------------------------------
2 //
3 // Copyright (C) 2021 CERN & University of Surrey for the benefit of the
4 // BioDynaMo collaboration. All Rights Reserved.
5 //
6 // Licensed under the Apache License, Version 2.0 (the "License");
7 // you may not use this file except in compliance with the License.
8 //
9 // See the LICENSE file distributed with this work for details.
10 // See the NOTICE file distributed with this work for additional information
11 // regarding copyright ownership.
12 //
13 // -----------------------------------------------------------------------------
14 
15 #ifdef USE_LIBGIT2
16 
17 #include "git_tracker.h"
18 #include <filesystem>
19 #include "core/util/log.h"
20 #include "fstream"
21 #include "git2.h"
22 #include "iostream"
23 #include "stdio.h"
24 
25 // C style callback function for libgit2 - taken from the libgit2 examples.
26 // See common.h in the libgit2 examples for more information. Definition
27 // of the callback function at the bottom of this file.
28 int diff_output(const git_diff_delta* d, const git_diff_hunk* h,
29  const git_diff_line* l, void* p);
30 
31 namespace bdm {
32 
33 void GitTracker::SaveGitDetails() {
34  // Determine the absolute path to the BioDynaMo installation
35  bdm_installation_ = GetAbsolutePath(bdm_installation_);
36  // Determine the absolute path to the simulation output
37  simulation_output_ = GetAbsolutePath(simulation_output_);
38 
39  // Write the git info for the BioDynaMo installation
40  std::string filename = simulation_output_ + "/bdm_git_info.txt";
41  SaveGitInfo(filename, bdm_installation_);
42 
43  // Write the git info for the simulation output
44  filename = simulation_output_ + "/bdm_sim_git_info.txt";
45  SaveGitInfo(filename, cwd_);
46 
47  // Write the git diff for the BioDynaMo installation
48  filename = simulation_output_ + "/bdm_git_diff.patch";
49  SaveGitDiff(filename, bdm_installation_);
50 
51  // Write the git diff for the simulation output
52  filename = simulation_output_ + "/bdm_sim_git_diff.patch";
53  SaveGitDiff(filename, cwd_);
54 }
55 
56 void GitTracker::SaveGitInfo(const std::string& file,
57  const std::string& repository_path) const {
58  std::ofstream out(file);
59  PrintGitInfo(repository_path, out);
60 }
61 
62 void GitTracker::PrintGitInfo(const std::string& repository_path,
63  std::ostream& out) const {
64  // Absolute path to repository
65  std::string abs_repo_path = GetAbsolutePath(repository_path);
66 
67  // Use libgit2 to verify that the repository is valid
68  git_libgit2_init();
69  git_repository* repo = nullptr;
70  git_repository_open(&repo, abs_repo_path.c_str());
71  if (repo == nullptr) {
72  Log::Error("GitTracker", "Error: ", abs_repo_path,
73  " is not a valid git repository");
74  return;
75  }
76 
77  // Get the name of the repository via libgit2
78  const char* repo_name = git_repository_path(repo);
79 
80  // Get the commit hash
81  git_reference* head = nullptr;
82  git_reference_lookup(&head, repo, "HEAD");
83  git_object* head_commit = nullptr;
84  git_reference_peel(&head_commit, head, GIT_OBJ_COMMIT);
85  const git_oid* oid = git_commit_id((git_commit*)head_commit);
86  char oid_str[GIT_OID_HEXSZ + 1];
87  git_oid_tostr(oid_str, GIT_OID_HEXSZ + 1, oid);
88 
89  // Get the commit message
90  const char* commit_message = git_commit_message((git_commit*)head_commit);
91 
92  // Get the commit author
93  const git_signature* commit_author =
94  git_commit_author((git_commit*)head_commit);
95 
96  // Get the commit author name
97  const char* author_name = commit_author->name;
98 
99  // Get the commit author email
100  const char* author_email = commit_author->email;
101 
102  // Get the branch name
103  const char* branch_name = git_reference_shorthand(head);
104 
105  // Get reference target
106  git_reference* target = nullptr;
107  git_reference_resolve(&target, head);
108  const char* target_name = git_reference_name(target);
109 
110  // Print the git info
111  out << "Git repository : " << repo_name << "\n"
112  << "Git branch name : " << target_name << "\n"
113  << " : " << branch_name << "\n"
114  << "Git commit hash : " << oid_str << "\n"
115  << "Git author email : " << author_email << "\n"
116  << "Git author name : " << author_name << "\n"
117  << "Git commit message : " << commit_message << "\n"
118  << std::endl;
119 
120  // Cleanup
121  git_object_free(head_commit);
122  git_reference_free(head);
123  git_reference_free(target);
124  git_repository_free(repo);
125  git_libgit2_shutdown();
126 }
127 
128 void GitTracker::SaveGitDiff(const std::string& file,
129  const std::string& repository_path) const {
130  // Absolute path to repository
131  std::string abs_repo_path = GetAbsolutePath(repository_path);
132 
133  // Use libgit2 to verify that the repository is valid
134  git_libgit2_init();
135  git_repository* repo = nullptr;
136  git_repository_open(&repo, abs_repo_path.c_str());
137  if (repo == nullptr) {
138  Log::Error("GitTracker", "Error: ", abs_repo_path,
139  " is not a valid git repository");
140  return;
141  }
142 
143  // Generate the git diff for the repository
144  git_diff* diff = nullptr;
145  git_diff_index_to_workdir(&diff, repo, nullptr, nullptr);
146 
147  // Open C style file
148  FILE* fp = fopen(file.c_str(), "w");
149 
150  // Print all the deltas to the file. If fopen fails, the diff will be printed
151  // to stdout
152  git_diff_print(diff, GIT_DIFF_FORMAT_PATCH, diff_output, fp);
153 
154  // Close C style file if the pointer is not null
155  if (fp) {
156  fclose(fp);
157  }
158 
159  // Cleanup
160  git_diff_free(diff);
161  git_repository_free(repo);
162  git_libgit2_shutdown();
163 }
164 
165 std::string GitTracker::GetAbsolutePath(const std::string& path) const {
166  // Get absolute path via filesystem
167  return std::filesystem::absolute(path).string();
168 };
169 
170 void GitTracker::ConstructFolderNames() {
171  // Determine the current working directory via filesystem
172  cwd_ = std::filesystem::current_path();
173  // Trim the build directory from the current working directory if the string
174  // ends with build
175  if (cwd_.substr(cwd_.size() - 5, 5) == "build") {
176  cwd_ = cwd_.substr(0, cwd_.size() - 6);
177  }
178  // Load the environment variable BDMSYS
179  bdm_installation_ = std::getenv("BDMSYS");
180  // Determine the absolute path to the BioDynaMo installation
181  bdm_installation_ = GetAbsolutePath(bdm_installation_);
182  // Trim the build directory from the BDMSYS environment variable
183  bdm_installation_ =
184  std::filesystem::path(bdm_installation_).parent_path().string();
185 };
186 } // namespace bdm
187 
188 // This function is taken from the libgit2 documentation. It is used to print
189 // the git diff to a file.
190 int diff_output(const git_diff_delta* d, const git_diff_hunk* h,
191  const git_diff_line* l, void* p) {
192  FILE* fp = (FILE*)p;
193 
194  (void)d;
195  (void)h;
196 
197  if (!fp)
198  fp = stdout;
199 
200  if (l->origin == GIT_DIFF_LINE_CONTEXT ||
201  l->origin == GIT_DIFF_LINE_ADDITION ||
202  l->origin == GIT_DIFF_LINE_DELETION)
203  fputc(l->origin, fp);
204 
205  fwrite(l->content, 1, l->content_len, fp);
206 
207  return 0;
208 }
209 
210 #endif // USE_LIBGIT2
bdm
Definition: agent.cc:39
bdm::Log::Error
static void Error(const std::string &location, const Args &... parts)
Prints error message.
Definition: log.h:79
log.h
git_tracker.h