#!/bin/bash . "$MKIT_DIR/include/ini.sh" || die "cannot import ini.sh" git_bool() { # # Get git bool (ie. exit status counts) $1 # local bool_name="$1" git_present || warn "can't give bool outside git repo: $bool_name" case "$bool_name" in dirty_files) git diff-files | grep -qm 1 . ;; dirty_index) git diff-index HEAD | grep -qm 1 . ;; dirty) git_bool dirty_files || git_bool dirty_index ;; *) warn "unknown git bool asked: $bool_name" return 2 ;; esac } git_fact() { # # Get git fact $1 # local fact_name="$1" git_present || warn "can't give fact outside git repo: $fact_name" case "$fact_name" in latest_tag) git log --format="%d" \ | sed 's/,/\n/g' \ | sed 's/^[[:blank:]]*//' \ | grep -E '^\(?tag' \ | tr -cd '[[:digit:]].v\n' \ | grep . -m 1 ;; latest_version) git_fact latest_tag | git_tag2ver ;; current_branch) git rev-parse --abbrev-ref HEAD ;; reldiff) git log --oneline "$(git_fact latest_tag)..HEAD" --name-only ;; latest_sha) git log -1 --pretty=format:%h HEAD ;; *) warn "unknown git fact asked: $fact_name" ;; esac } git_present() { # # True if we're in a git repo # git rev-parse HEAD >&/dev/null } git_tag2ver() { # # Convert tag to version # sed s/^v// } git_ver2tag() { # # Convert version to tag # sed s/^/v/ } git_lasthash() { # # Show last commit hash (with .dirty suffix if needed) # # If outside git repo, get it from .mkit/git_lasthash, which # should have been put there by dist target. (I.e., this won't # work if you got outside the git repo in other way than dist # target, but that's actually expected.) # if git_present; then # we are in git repo local last_hash=$(git rev-parse HEAD) echo -n "$last_hash" git_bool dirty && echo -n ".dirty" else # we are outside (eg. distributor's build dir') grep . .mkit/git_lasthash || { echo UNKNOWN warn "malformed source, could not determine git hash" } fi } semver() { # # Build semver version string with build metadata # # Build version string from available info using following # logic: # # 1. use project.version (from mkit.ini) # 2. if we are in git, override the version with last tag # 3. if set, add project:prerl (from mkit.ini) as pre-release ID # (afer dash) # 4. if we are at a later commit than the last tag, add branch # name and commit sha1 to build metadata (after plus sign) # 5. if the tree is "dirty", i.e. has uncommited changes, # add "dirty" to build metadata # # The version is compatible with SemVer 2.0.0. # # Examples: # # myprog v1.0.7 # all clear # myprog v1.0.7-alpha # mkit.ini: project:prerl="alpha" # myprog v1.0.7-alpha+g1aef811.master # ^^ + some commits after # myprog v1.0.7-alpha+gf14fc4f.api2 # ^^ + on a feature branch # myprog v1.0.7-alpha+gf14fc4f.api2.dirty # ^^ + tree edited # myprog v1.0.7-alpha+dirty # tag OK but tree edited # myprog v1.0.7+dirty # ^^ but no pre-release id # # Note that versions with "dirty" should be perceived as kind of # dangerous outside developer's own machine. Versions with sha1 are # safer but must not be released. # # I have considered decorating the git commit refs to make them # sort of sortable (e.g. "r1.g1aef811"), but on second thought, # I don't think it's good idea to give *any* semantics to meta-data # at all. First, there is no rule that r1&/dev/null; then # we are at a later commit than the last tag local commit="$(git_fact current_branch).g$(git_fact latest_sha)" fi local dirty="" local suffix="" git_bool dirty; dirty=$? test -n "$latest_tag" && version=${latest_tag:1} case "$dirty:$commit" in 1:) suffix="" ;; 0:) suffix="+dirty" ;; 1:*) suffix="+$commit" ;; 0:*) suffix="+$commit.dirty" ;; *) suffix=MKIT_BUG; warn "MKIT_BUG: bad dirt/commit detection" ;; esac test -n "$prerl" && suffix="-$prerl$suffix" version="$version$suffix" fi echo "$version" }