Working Saturnin-based meta-command

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. #!/bin/bash
  2. # MKit - simple install helper
  3. # See LICENSE file for copyright and license details.
  4. mkit_import ini
  5. git_bool() {
  6. #
  7. # Get git bool (ie. exit status counts) $1
  8. #
  9. local bool_name=$1 # name of boolean to get
  10. git_present || warn "can't give bool outside git repo: $bool_name"
  11. case "$bool_name" in
  12. dirty_files)
  13. git diff-files | grep -qm 1 .
  14. ;;
  15. dirty_index)
  16. git diff-index HEAD | grep -qm 1 .
  17. ;;
  18. dirty)
  19. git_bool dirty_files || git_bool dirty_index
  20. ;;
  21. *)
  22. warn "unknown git bool asked: $bool_name"
  23. return 2
  24. ;;
  25. esac
  26. }
  27. git_fact() {
  28. #
  29. # Get git fact $1
  30. #
  31. local fact_name=$1 # name of fact to get
  32. git_present || warn "can't give fact outside git repo: $fact_name"
  33. case "$fact_name" in
  34. latest_tag)
  35. git log --format="%d" \
  36. | sed 's/,/\n/g' \
  37. | sed 's/^[[:blank:]]*//' \
  38. | grep -E '^\(?tag' \
  39. | tr -cd '[[:digit:]].v\n' \
  40. | grep . -m 1
  41. ;;
  42. latest_version)
  43. git_fact latest_tag | git_tag2ver
  44. ;;
  45. current_branch)
  46. git rev-parse --abbrev-ref HEAD
  47. ;;
  48. reldiff)
  49. git log --oneline "$(git_fact latest_tag)..HEAD" --name-only
  50. ;;
  51. latest_sha)
  52. git log -1 --pretty=format:%h HEAD
  53. ;;
  54. *)
  55. warn "unknown git fact asked: $fact_name"
  56. ;;
  57. esac
  58. }
  59. git_present() {
  60. #
  61. # True if we're in a git repo
  62. #
  63. git rev-parse HEAD >&/dev/null
  64. }
  65. git_tag2ver() {
  66. #
  67. # Convert tag to version
  68. #
  69. sed s/^v//
  70. }
  71. git_ver2tag() {
  72. #
  73. # Convert version to tag
  74. #
  75. sed s/^/v/
  76. }
  77. git_lasthash() {
  78. #
  79. # Show last commit hash (with .dirty suffix if needed)
  80. #
  81. # If outside git repo, get it from .mkit/git_lasthash, which
  82. # should have been put there by dist target. (I.e., this won't
  83. # work if you got outside the git repo in other way than dist
  84. # target, but that's actually expected.)
  85. #
  86. local last_hash # last commit hash
  87. if git_present; then # we are in git repo
  88. last_hash=$(git rev-parse HEAD)
  89. echo -n "$last_hash"
  90. git_bool dirty && echo -n ".dirty"
  91. else # we are outside (eg. distributor's build dir')
  92. grep . .mkit/git_lasthash || {
  93. echo UNKNOWN
  94. warn "malformed source, could not determine git hash"
  95. }
  96. fi
  97. }
  98. semver() {
  99. #
  100. # Build semver version string with build metadata
  101. #
  102. # Build version string from available info using following
  103. # logic:
  104. #
  105. # 1. use project.version (from mkit.ini)
  106. # 2. if we are in git, override the version with last tag
  107. # 3. if set, add project:prerl (from mkit.ini) as pre-release ID
  108. # (afer dash)
  109. # 4. if we are at a later commit than the last tag, add branch
  110. # name and commit sha1 to build metadata (after plus sign)
  111. # 5. if the tree is "dirty", i.e. has uncommited changes,
  112. # add "dirty" to build metadata
  113. #
  114. # The version is compatible with SemVer 2.0.0.
  115. #
  116. # Examples:
  117. #
  118. # myprog v1.0.7 # all clear
  119. # myprog v1.0.7-alpha # mkit.ini: project:prerl="alpha"
  120. # myprog v1.0.7-alpha+g1aef811.master # ^^ + some commits after
  121. # myprog v1.0.7-alpha+gf14fc4f.api2 # ^^ + on a feature branch
  122. # myprog v1.0.7-alpha+gf14fc4f.api2.dirty # ^^ + tree edited
  123. # myprog v1.0.7-alpha+dirty # tag OK but tree edited
  124. # myprog v1.0.7+dirty # ^^ but no pre-release id
  125. #
  126. # Note that versions with "dirty" should be perceived as kind of
  127. # dangerous outside developer's own machine. Versions with sha1 are
  128. # safer but must not be released.
  129. #
  130. # I have considered decorating the git commit refs to make them
  131. # sort of sortable (e.g. "r1.g1aef811"), but on second thought,
  132. # I don't think it's good idea to give *any* semantics to meta-data
  133. # at all. First, there is no rule that r1<r2<r3; a commit can be
  134. # removing what other just added and one change can be split to
  135. # multiple commits. Also, the whole thing breaks anyway once you
  136. # rebase your branch (no, it's not a sin). The sole purpose of
  137. # meta-data is to *identify* the code, and provide safe path back
  138. # to tree; commit refs are already perfect for that.
  139. #
  140. # FIXME: Using project:prerl for release IDs may not be compatible with
  141. # release strategy implemented in release.sh
  142. #
  143. local version # version string (final result)
  144. local prerl # pre-release keyword (from mkit.ini, eg. 'alpha')
  145. local latest_tag # latest git tag
  146. local commit # commit indicator (CURRENT_BRANCH.gHASH)
  147. local dirty # 0 if dirty, 1 if clean
  148. local suffix # version suffix
  149. local_get semver && return 0
  150. version=$(ini 1value project:version)
  151. prerl=$(ini 1value project:prerl)
  152. grep ":" <<<"$prerl" \
  153. && warn "colon in project:prerl may corrupt version data: $prerl"
  154. if git_present;
  155. then # we are in git repo... so we can get smart
  156. latest_tag=$(git_fact latest_tag)
  157. if ! git describe --tags --exact-match HEAD >&/dev/null;
  158. then # we are at a later commit than the last tag
  159. commit="$(git_fact current_branch).g$(git_fact latest_sha)"
  160. fi
  161. git_bool dirty; dirty=$?
  162. test -n "$latest_tag" && version=${latest_tag:1}
  163. case "$dirty:$commit" in
  164. 1:) suffix="" ;;
  165. 0:) suffix="+dirty" ;;
  166. 1:*) suffix="+$commit" ;;
  167. 0:*) suffix="+$commit.dirty" ;;
  168. *) suffix=MKIT_BUG
  169. warn "MKIT_BUG: bad dirt/commit detection" ;;
  170. esac
  171. test -n "$prerl" && suffix="-$prerl$suffix"
  172. version="$version$suffix"
  173. fi
  174. local_putb semver <<<"$version"
  175. echo "$version"
  176. }