#!/bin/bash . "$MKIT_DIR/include/ini.sh" || die "cannot import ini.sh" 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: v[[:digit:]]+\.' \ | cut -d' ' -f2 \ | head -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) if test "$(git diff --shortstat 2>/dev/null)" != ""; then # the tree is "dirty", i.e. has been edited local suffix=.dirty fi local suffix="" echo -n "$last_hash$suffix" 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 if test "$(git diff --shortstat 2>/dev/null)" != ""; then # the tree is "dirty", i.e. has been edited local dirty=dirty fi test -n "$latest_tag" && version=${latest_tag:1} local suffix="" case "$commit:$dirty" in :) suffix="" ;; :dirty) suffix="+$dirty" ;; *:) suffix="+$commit" ;; *:dirty) suffix="+$commit.$dirty" ;; esac test -b "$prerl" && suffix="-$prerl$suffix" version="$version$suffix" fi echo "$version" }