Skip to content

Commit

Permalink
expose HEAD's commit message
Browse files Browse the repository at this point in the history
Add two new new message fields to the gitstatusd's reply and
expose them in bash and zsh bindings:

- VCS_STATUS_COMMIT_ENCODING:
  Encoding of the HEAD's commit message. Empty value means UTF-8.
- VCS_STATUS_COMMIT_SUMMARY:
  The first paragraph of the HEAD's commit message as one line.

Commit summary is truncated to 256 bytes. This can be overridden
with --max-commit-summary-length/-z.

Note that truncation may result in invalid UTF-8.

Messages in exotic may not work because of SafePrint() in
gitstatusd. This can be fixed.
  • Loading branch information
romkatv committed May 29, 2021
1 parent 815301f commit e193be5
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 7 deletions.
6 changes: 6 additions & 0 deletions gitstatus.plugin.sh
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,8 @@ function gitstatus_stop() {
# VCS_STATUS_WORKDIR Git repo working directory. Not empty.
# VCS_STATUS_COMMIT Commit hash that HEAD is pointing to. Either 40 hex digits or
# empty if there is no HEAD (empty repo).
# VCS_STATUS_COMMIT_ENCODING Encoding of the HEAD's commit message. Empty value means UTF-8.
# VCS_STATUS_COMMIT_SUMMARY The first paragraph of the HEAD's commit message as one line.
# VCS_STATUS_LOCAL_BRANCH Local branch name or empty if not on a branch.
# VCS_STATUS_REMOTE_NAME The remote name, e.g. "upstream" or "origin".
# VCS_STATUS_REMOTE_BRANCH Upstream branch name. Can be empty.
Expand Down Expand Up @@ -403,6 +405,8 @@ function gitstatus_query() {
VCS_STATUS_PUSH_COMMITS_BEHIND="${resp[24]:-0}"
VCS_STATUS_NUM_SKIP_WORKTREE="${resp[25]:-0}"
VCS_STATUS_NUM_ASSUME_UNCHANGED="${resp[26]:-0}"
VCS_STATUS_COMMIT_ENCODING="${resp[27]-}"
VCS_STATUS_COMMIT_SUMMARY="${resp[28]-}"
VCS_STATUS_HAS_STAGED=$((VCS_STATUS_NUM_STAGED > 0))
if (( _GITSTATUS_DIRTY_MAX_INDEX_SIZE >= 0 &&
VCS_STATUS_INDEX_SIZE > _GITSTATUS_DIRTY_MAX_INDEX_SIZE_ )); then
Expand Down Expand Up @@ -445,6 +449,8 @@ function gitstatus_query() {
unset VCS_STATUS_PUSH_COMMITS_BEHIND
unset VCS_STATUS_NUM_SKIP_WORKTREE
unset VCS_STATUS_NUM_ASSUME_UNCHANGED
unset VCS_STATUS_COMMIT_ENCODING
unset VCS_STATUS_COMMIT_SUMMARY
fi
}

Expand Down
8 changes: 7 additions & 1 deletion gitstatus.plugin.zsh
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
# VCS_STATUS_COMMIT=c000eddcff0fb38df2d0137efe24d9d2d900f209
# VCS_STATUS_COMMITS_AHEAD=0
# VCS_STATUS_COMMITS_BEHIND=0
# VCS_STATUS_COMMIT_ENCODING=''
# VCS_STATUS_COMMIT_SUMMARY='pull upstream changes from gitstatus'
# VCS_STATUS_HAS_CONFLICTED=0
# VCS_STATUS_HAS_STAGED=0
# VCS_STATUS_HAS_UNSTAGED=1
Expand Down Expand Up @@ -88,6 +90,8 @@ typeset -g _gitstatus_plugin_dir"${1:-}"="${${(%):-%x}:A:h}"
# VCS_STATUS_WORKDIR Git repo working directory. Not empty.
# VCS_STATUS_COMMIT Commit hash that HEAD is pointing to. Either 40 hex digits or
# empty if there is no HEAD (empty repo).
# VCS_STATUS_COMMIT_ENCODING Encoding of the HEAD's commit message. Empty value means UTF-8.
# VCS_STATUS_COMMIT_SUMMARY The first paragraph of the HEAD's commit message as one line.
# VCS_STATUS_LOCAL_BRANCH Local branch name or empty if not on a branch.
# VCS_STATUS_REMOTE_NAME The remote name, e.g. "upstream" or "origin".
# VCS_STATUS_REMOTE_BRANCH Upstream branch name. Can be empty.
Expand Down Expand Up @@ -329,7 +333,9 @@ function _gitstatus_process_response"${1:-}"() {
VCS_STATUS_PUSH_COMMITS_AHEAD \
VCS_STATUS_PUSH_COMMITS_BEHIND \
VCS_STATUS_NUM_SKIP_WORKTREE \
VCS_STATUS_NUM_ASSUME_UNCHANGED in "${(@)resp[3,27]}"; do
VCS_STATUS_NUM_ASSUME_UNCHANGED \
VCS_STATUS_COMMIT_ENCODING \
VCS_STATUS_COMMIT_SUMMARY in "${(@)resp[3,29]}"; do
done
typeset -gi VCS_STATUS_{INDEX_SIZE,NUM_STAGED,NUM_UNSTAGED,NUM_CONFLICTED,NUM_UNTRACKED,COMMITS_AHEAD,COMMITS_BEHIND,STASHES,NUM_UNSTAGED_DELETED,NUM_STAGED_NEW,NUM_STAGED_DELETED,PUSH_COMMITS_AHEAD,PUSH_COMMITS_BEHIND,NUM_SKIP_WORKTREE,NUM_ASSUME_UNCHANGED}
typeset -gi VCS_STATUS_HAS_STAGED=$((VCS_STATUS_NUM_STAGED > 0))
Expand Down
8 changes: 8 additions & 0 deletions src/git.cc
Original file line number Diff line number Diff line change
Expand Up @@ -239,4 +239,12 @@ PushRemotePtr GetPushRemote(git_repository* repo, const git_reference* local) {
return PushRemotePtr(res.release());
}

CommitMessage GetCommitMessage(git_repository* repo, const git_oid& id) {
git_commit* commit;
VERIFY(!git_commit_lookup(&commit, repo, &id)) << GitError();
ON_SCOPE_EXIT(=) { git_commit_free(commit); };
return {.encoding = git_commit_message_encoding(commit) ?: "",
.summary = git_commit_summary(commit) ?: ""};
}

} // namespace gitstatus
9 changes: 9 additions & 0 deletions src/git.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,15 @@ git_reference* Head(git_repository* repo);
// Returns the name of the local branch, or an empty string.
const char* LocalBranchName(const git_reference* ref);

struct CommitMessage {
// Can be empty, meaning "UTF-8".
std::string encoding;
// The first paragraph of the commit's message as a one-liner.
std::string summary;
};

CommitMessage GetCommitMessage(git_repository* repo, const git_oid& id);

struct Remote {
// Tip of the remote branch.
git_reference* ref;
Expand Down
9 changes: 9 additions & 0 deletions src/gitstatus.cc
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ namespace {

using namespace std::string_literals;

void Truncate(std::string& s, size_t max_len) {
if (s.size() > max_len) s.resize(max_len);
}

void ProcessRequest(const Options& opts, RepoCache& cache, Request req) {
Timer timer;
ON_SCOPE_EXIT(&) { timer.Report("request"); };
Expand Down Expand Up @@ -167,6 +171,11 @@ void ProcessRequest(const Options& opts, RepoCache& cache, Request req) {
// The number of files in the index with assume-unchanged bit set.
resp.Print(stats.num_assume_unchanged);

CommitMessage msg = head_target ? GetCommitMessage(repo->repo(), *head_target) : CommitMessage();
Truncate(msg.summary, opts.max_commit_summary_length);
resp.Print(msg.encoding);
resp.Print(msg.summary);

resp.Dump("with git status");
}

Expand Down
32 changes: 26 additions & 6 deletions src/options.cc
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@ long ParseInt(const char* s) {
return res;
}

size_t ParseSizeT(const char* s) {
static_assert(sizeof(long) <= sizeof(size_t));
long res = ParseLong(s);
return res >= 0 ? res : -1;
}

void PrintUsage() {
std::cout << "Usage: gitstatusd [OPTION]...\n"
<< "Print machine-readable status of the git repos for directores in stdin.\n"
Expand Down Expand Up @@ -81,12 +87,18 @@ void PrintUsage() {
<< " repo that's been closed is much slower than for a repo that hasn't been.\n"
<< " Negative value means infinity.\n"
<< "\n"
<< " -z, --max-commit-summary-length=NUM [default=256]\n"
<< " Truncate commit summary if it's longer than this many bytes.\n"
<< "\n"
<< " -s, --max-num-staged=NUM [default=1]\n"
<< " Report at most this many staged changes; negative value means infinity.\n"
<< "\n"
<< " -u, --max-num-unstaged=NUM [default=1]\n"
<< " Report at most this many unstaged changes; negative value means infinity.\n"
<< "\n"
<< " -c, --max-num-conflicted=NUM [default=1]\n"
<< " Report at most this many conflicted changes; negative value means infinity.\n"
<< "\n"
<< " -d, --max-num-untracked=NUM [default=1]\n"
<< " Report at most this many untracked files; negative value means infinity.\n"
<< "\n"
Expand Down Expand Up @@ -170,6 +182,8 @@ void PrintUsage() {
<< " 25. Number of commits the current branch is behind push remote.\n"
<< " 26. Number of files in the index with skip-worktree bit set.\n"
<< " 27. Number of files in the index with assume-unchanged bit set.\n"
<< " 28. Encoding of the HEAD's commit message. Empty value means UTF-8.\n"
<< " 29. The first paragraph of the HEAD's commit message as one line.\n"
<< "\n"
<< "Note: Renamed files are reported as deleted plus new.\n"
<< "\n"
Expand Down Expand Up @@ -212,6 +226,8 @@ void PrintUsage() {
<< " '0'\n"
<< " '0'\n"
<< " '0'\n"
<< " ''\n"
<< " 'add a build server for darwin-arm64'\n"
<< "\n"
<< "EXIT STATUS\n"
<< "\n"
Expand Down Expand Up @@ -245,6 +261,7 @@ Options ParseOptions(int argc, char** argv) {
{"num-threads", required_argument, nullptr, 't'},
{"log-level", required_argument, nullptr, 'v'},
{"repo-ttl-seconds", required_argument, nullptr, 'r'},
{"max-commit-summary-length", required_argument, nullptr, 'z'},
{"max-num-staged", required_argument, nullptr, 's'},
{"max-num-unstaged", required_argument, nullptr, 'u'},
{"max-num-conflicted", required_argument, nullptr, 'c'},
Expand All @@ -257,7 +274,7 @@ Options ParseOptions(int argc, char** argv) {
{}};
Options res;
while (true) {
switch (getopt_long(argc, argv, "hVG:l:p:t:v:r:s:u:c:d:m:eUWD", opts, nullptr)) {
switch (getopt_long(argc, argv, "hVG:l:p:t:v:r:z:s:u:c:d:m:eUWD", opts, nullptr)) {
case -1:
if (optind != argc) {
std::cerr << "unexpected positional argument: " << argv[optind] << std::endl;
Expand Down Expand Up @@ -306,20 +323,23 @@ Options ParseOptions(int argc, char** argv) {
res.num_threads = n;
break;
}
case 'z':
res.max_commit_summary_length = ParseSizeT(optarg);
break;
case 's':
res.max_num_staged = ParseLong(optarg);
res.max_num_staged = ParseSizeT(optarg);
break;
case 'u':
res.max_num_unstaged = ParseLong(optarg);
res.max_num_unstaged = ParseSizeT(optarg);
break;
case 'c':
res.max_num_conflicted = ParseLong(optarg);
res.max_num_conflicted = ParseSizeT(optarg);
break;
case 'd':
res.max_num_untracked = ParseLong(optarg);
res.max_num_untracked = ParseSizeT(optarg);
break;
case 'm':
res.dirty_max_index_size = ParseLong(optarg);
res.dirty_max_index_size = ParseSizeT(optarg);
break;
case 'e':
res.recurse_untracked_dirs = true;
Expand Down
2 changes: 2 additions & 0 deletions src/options.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
namespace gitstatus {

struct Limits {
// Truncate commit summary if it's longer than this many bytes.
size_t max_commit_summary_length = 256;
// Report at most this many staged changes.
size_t max_num_staged = 1;
// Report at most this many unstaged changes.
Expand Down

0 comments on commit e193be5

Please sign in to comment.