From 033551b758ce400a2209ef2e8223abb3cf17ebed Mon Sep 17 00:00:00 2001 From: Peter Wu Date: Fri, 22 Nov 2013 23:32:42 +0100 Subject: git-log-describe: introduce cache to speed up git-describe git-describe is slow, this change allows the output to be cached in a directory using two levels (first two chars of hash for a directory, the remaining 38 for the file). Set `-vcache=1` to enable the cache or specify a custom cache directory with `-vcache_dir=DIR`. On the Linux tree, this feature decreases the run time from 18 seconds to just one second (with .git in already in disk cache for both trials and 466 commits for a certain path). --- git-log-describe.awk | 92 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 83 insertions(+), 9 deletions(-) (limited to 'git-log-describe.awk') diff --git a/git-log-describe.awk b/git-log-describe.awk index c4f7fee..27063c4 100755 --- a/git-log-describe.awk +++ b/git-log-describe.awk @@ -2,13 +2,30 @@ # Adds a "git describe" (nearest tag) output for `git log` (with support for # color escapes and --graph markers). --oneline is not supported. # +# Optional variables: +# -vcache={0|1} Enable a cache for git describe outputs. If set to 1, +# .git/describe-cache.d/ as default cache_dir. +# -vcache_dir=DIR Use DIR to store cached git-describe results. DIR will +# be created if non-existent. Implies -vcache=1. +# -vcache_ro={0|1} Set to 1 to prevent creating new files in cache. +# # Copyright (c) 2013 Peter Wu # Licensed under GPLv3 or any latter version -function has_color(str) { - if (str ~ /\033/) return 1; +BEGIN { + if (!cache_dir && cache) { + # Use directory in .git/ as default. + "git rev-parse --show-toplevel" | getline cache_dir; + if (cache_dir) + cache_dir = cache_dir "/.git/describe-cache.d"; + } - return 0; + if (cache_dir) { + # Skip cache directory if non-existent and read only or if the + # directory cannot be created. + if (cache_ro && !is_dir(cache_dir) || !mkdir_p(cache_dir)) + cache_dir = ""; + } } { print; } @@ -26,12 +43,69 @@ function has_color(str) { # match only git's "commit" label, not something from the commit message. $0 ~ /^commit/ && -$1 == "commit" && $2 ~ /^[0-9a-f]{5,40}$/ { +$1 == "commit" && $2 ~ /^[0-9a-f]{4,40}$/ { hash = $2; + desc = git_describe(hash); + + if (desc) { + printf("%" indent_len "sDescribe: ", ""); + + if (is_color) + print "\033[96m" desc "\033[m"; # light cyan + else + print desc; + } +} + +# Helper functions +function shellescape(arg) { + gsub(/'/, "'\\''", arg); + return "'" arg "'"; +} + +function is_dir(path) { + return system("test -d " shellescape(path)) == 0; +} + +function mkdir_p(dir) { + return system("mkdir -p -- " shellescape(dir)) == 0; +} + +function has_color(str) { + if (str ~ /\033/) return 1; + + return 0; +} + +# Show the name matching the sha1 hash (consisting of 4-40 hexadecimals). +function git_describe(hash) { + desc = ""; + + if (length(hash) != 40) { + "git rev-parse --default " hash | getline hash; + + if (length(hash) != 40) return ""; + } + + # try cached output if enabled/any. + if (cache_dir) { + cache_subdir = cache_dir "/" substr(hash, 1, 2); + cache_file = cache_subdir "/" substr(hash, 3); + getline desc < cache_file; + close(cache_file); + } + + # cache entry was unavailable, get a description now. + if (!desc) { + "git describe --first-parent " hash | getline desc; + + # write description to cache if allowed. + if (cache_dir && desc && !cache_ro) { + mkdir_p(cache_subdir); + print desc > cache_file; + close(cache_file); + } + } - printf("%" indent_len "sDescribe: ", ""); - if (is_color) printf("\033[96m"); # light cyan - system("git describe --first-parent " hash " | tr -d '\n'"); - if (is_color) printf("\033[m"); - printf("\n"); + return desc; } -- cgit v1.2.1