36 thread_local wxString tl_contextPath;
42 tl_contextPath = aPath;
48 return tl_contextPath.IsEmpty() ? wxString( wxT(
"." ) ) : tl_contextPath;
55 tl_contextPath = aPath;
70 wxString ResolveEffectivePath(
const std::string& aPath )
72 if( aPath.empty() || aPath ==
"." )
75 return wxString::FromUTF8( aPath );
79 git_repository* OpenRepo(
const std::string& aPath )
84 const wxString effective = ResolveEffectivePath( aPath );
88 void CloseRepo( git_repository* aRepo )
91 git_repository_free( aRepo );
97 git_oid_fromstrn( &oid,
"0000000000000000000000000000000000000000", 40 );
101 git_oid GetFileCommit( git_repository* aRepo,
const std::string& aPath )
104 return MakeZeroOid();
109 if( git_reference_name_to_id( &head_oid, aRepo,
"HEAD" ) != 0 )
110 return MakeZeroOid();
113 if( aPath.empty() || aPath ==
"." )
117 git_revwalk* walker =
nullptr;
119 if( git_revwalk_new( &walker, aRepo ) != 0 )
120 return MakeZeroOid();
122 git_revwalk_sorting( walker, GIT_SORT_TIME );
123 git_revwalk_push( walker, &head_oid );
126 git_oid
result = MakeZeroOid();
128 git_oid prev_blob_oid = MakeZeroOid();
129 bool first_commit =
true;
131 while( git_revwalk_next( &commit_oid, walker ) == 0 )
133 git_commit* commit =
nullptr;
135 if( git_commit_lookup( &commit, aRepo, &commit_oid ) != 0 )
139 git_tree* tree =
nullptr;
141 if( git_commit_tree( &tree, commit ) == 0 )
144 git_tree_entry* entry =
nullptr;
146 if( git_tree_entry_bypath( &entry, tree, aPath.c_str() ) == 0 )
148 const git_oid* blob_oid = git_tree_entry_id( entry );
153 git_oid_cpy( &prev_blob_oid, blob_oid );
154 git_oid_cpy( &
result, &commit_oid );
155 first_commit =
false;
157 else if( git_oid_cmp( blob_oid, &prev_blob_oid ) != 0 )
160 git_tree_entry_free( entry );
161 git_tree_free( tree );
162 git_commit_free( commit );
168 git_oid_cpy( &
result, &commit_oid );
171 git_tree_entry_free( entry );
173 else if( !first_commit )
177 git_tree_free( tree );
178 git_commit_free( commit );
182 git_tree_free( tree );
185 git_commit_free( commit );
188 git_revwalk_free( walker );
198 DescribeInfo GetDescribeInfo(
const std::string& aMatch,
bool aAnyTags )
200 git_repository* repo = OpenRepo(
"." );
203 return { std::string(), 0 };
207 if( git_reference_name_to_id( &head_oid, repo,
"HEAD" ) != 0 )
210 return { std::string(), 0 };
213 git_strarray tag_names;
215 if( git_tag_list_match( &tag_names, aMatch.empty() ?
"*" : aMatch.c_str(), repo ) != 0 )
218 return { std::string(), 0 };
222 std::map<git_oid, std::string,
decltype(
223 [](
const git_oid& a,
const git_oid& b)
225 return git_oid_cmp(&a, &b) < 0;
228 for(
size_t i = 0; i < tag_names.count; ++i )
230 git_object* tag_obj =
nullptr;
232 if( git_revparse_single( &tag_obj, repo, tag_names.strings[i] ) == 0 )
234 git_object_t type = git_object_type( tag_obj );
236 if( type == GIT_OBJECT_TAG )
238 git_object* target =
nullptr;
240 if( git_tag_peel( &target, (git_tag*) tag_obj ) == 0 )
242 commit_to_tag[*git_object_id( target )] = tag_names.strings[i];
243 git_object_free( target );
246 else if( aAnyTags && type == GIT_OBJECT_COMMIT )
248 commit_to_tag[*git_object_id( tag_obj )] = tag_names.strings[i];
251 git_object_free( tag_obj );
255 git_strarray_dispose( &tag_names );
257 git_revwalk* walker =
nullptr;
259 if( git_revwalk_new( &walker, repo ) != 0 )
262 return { std::string(), 0 };
265 git_revwalk_sorting( walker, GIT_SORT_TOPOLOGICAL | GIT_SORT_TIME );
266 git_revwalk_push( walker, &head_oid );
268 DescribeInfo
result{ std::string(), 0 };
272 while( git_revwalk_next( &commit_oid, walker ) == 0 )
274 auto it = commit_to_tag.find( commit_oid );
276 if( it != commit_to_tag.end() )
286 git_revwalk_free( walker );
291 std::string GetCommitSignatureField(
const std::string& aPath,
bool aUseCommitter,
bool aGetEmail )
293 git_repository* repo = OpenRepo( aPath );
296 return std::string();
298 git_oid oid = GetFileCommit( repo, aPath );
300 if( git_oid_is_zero( &oid ) )
303 return std::string();
306 git_commit* commit =
nullptr;
309 if( git_commit_lookup( &commit, repo, &oid ) == 0 )
311 const git_signature* sig = aUseCommitter ? git_commit_committer( commit ) : git_commit_author( commit );
315 const char* field = aGetEmail ? sig->email : sig->name;
321 git_commit_free( commit );
333 git_repository* repo = OpenRepo( aPath );
336 return std::string();
338 git_oid oid = GetFileCommit( repo, aPath );
340 if( git_oid_is_zero( &oid ) )
343 return std::string();
346 int length = std::max( 4, std::min( aLength, GIT_OID_HEXSZ ) );
347 char hash[GIT_OID_HEXSZ + 1];
348 git_oid_tostr( hash, length + 1, &oid );
357 return GetDescribeInfo( aMatch, aAnyTags ).tag;
363 return GetDescribeInfo( aMatch, aAnyTags ).distance;
369 git_repository* repo = OpenRepo(
"." );
374 git_status_list* status =
nullptr;
375 git_status_options statusOpts;
376 git_status_options_init( &statusOpts, GIT_STATUS_OPTIONS_VERSION );
378 statusOpts.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR;
379 statusOpts.flags = aIncludeUntracked ? GIT_STATUS_OPT_INCLUDE_UNTRACKED : GIT_STATUS_OPT_EXCLUDE_SUBMODULES;
381 bool isDirty =
false;
383 if( git_status_list_new( &status, repo, &statusOpts ) == 0 )
385 isDirty = git_status_list_entrycount( status ) > 0;
386 git_status_list_free( status );
396 return GetCommitSignatureField( aPath,
false,
false );
402 return GetCommitSignatureField( aPath,
false,
true );
408 return GetCommitSignatureField( aPath,
true,
false );
414 return GetCommitSignatureField( aPath,
true,
true );
420 git_repository* repo = OpenRepo(
"." );
423 return std::string();
429 return branchName.ToStdString();
435 git_repository* repo = OpenRepo( aPath );
440 git_oid oid = GetFileCommit( repo, aPath );
442 if( git_oid_is_zero( &oid ) )
448 git_commit* commit =
nullptr;
449 int64_t timestamp = 0;
451 if( git_commit_lookup( &commit, repo, &oid ) == 0 )
453 timestamp =
static_cast<int64_t
>( git_commit_time( commit ) );
454 git_commit_free( commit );
465 return timestamp > 0 ? std::to_string( timestamp ) : std::string();
VCS (Version Control System) utility functions for text evaluation.
std::string GetAuthor(const std::string &aPath)
Get the author name of the HEAD commit.
bool IsDirty(bool aIncludeUntracked)
Check if the repository has uncommitted changes.
wxString GetContextPath()
Return the current context path for repo-scoped VCS queries.
std::string GetCommitterEmail(const std::string &aPath)
Get the committer email of the HEAD commit.
std::string GetCommitDate(const std::string &aPath)
Get the commit date of the HEAD commit as a timestamp string.
std::string GetAuthorEmail(const std::string &aPath)
Get the author email of the HEAD commit.
void SetContextPath(const wxString &aPath)
Set the filesystem path used as the repository-discovery starting point for repo-scoped VCS queries (...
std::string GetCommitter(const std::string &aPath)
Get the committer name of the HEAD commit.
std::string GetBranch()
Get the current branch name.
std::string GetNearestTag(const std::string &aMatch, bool aAnyTags)
Get the nearest tag/label from HEAD.
int64_t GetCommitTimestamp(const std::string &aPath)
Get the commit timestamp (Unix time) of the HEAD commit.
int GetDistanceFromTag(const std::string &aMatch, bool aAnyTags)
Get the number of commits since the nearest matching tag.
wxString result
Test unit parsing edge cases and error handling.