123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  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. latest_cdate)
  55. git log -1 --format=%ct HEAD
  56. ;;
  57. *)
  58. warn "unknown git fact asked: $fact_name"
  59. ;;
  60. esac
  61. }
  62. git_present() {
  63. #
  64. # True if we're in a git repo
  65. #
  66. git rev-parse HEAD >&/dev/null
  67. }
  68. git_tag2ver() {
  69. #
  70. # Convert tag to version
  71. #
  72. sed s/^v//
  73. }
  74. git_ver2tag() {
  75. #
  76. # Convert version to tag
  77. #
  78. sed s/^/v/
  79. }
  80. git_lasthash() {
  81. #
  82. # Show last commit hash (with .dirty suffix if needed)
  83. #
  84. # We can't do it outside git repo (or without git) but we should
  85. # not be asked to; targets that don't require git should make use
  86. # of cache built by dist target.
  87. #
  88. local last_hash # last commit hash
  89. git_present || {
  90. echo UNKNOWN_HASH
  91. warn "no git present; could not determine last hash"
  92. return 3
  93. }
  94. last_hash=$(git rev-parse HEAD)
  95. echo -n "$last_hash"
  96. git_bool dirty && echo -n ".dirty"
  97. }
  98. semver() {
  99. #
  100. # Build proper SemVer version string
  101. #
  102. # Build version string from available info using following
  103. # logic:
  104. #
  105. # 1. Use version from last git tag (or mkit.ini if there is no
  106. # tag, which is possible on new project)
  107. # 2. if set, add project:prerl (from mkit.ini) as pre-release ID
  108. # (afer dash)
  109. # 3. 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. # 4. 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. # foo v1.0.7 # all clear; proper release
  119. # foo v1.0.7-beta # mkit.ini: project:prerl="beta"
  120. # foo v1.0.7-beta+g1aef811.master # ^^ + some commits after
  121. # foo v1.0.7-beta+gf14fc4f.api2 # ^^ + on a feature branch
  122. # foo v1.0.7-beta+gf14fc4f.api2.dirty # ^^ + tree edited
  123. # foo v1.0.7-beta+dirty # tag OK but tree edited
  124. # foo 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. # FIXME: Using project:prerl for release IDs may not be compatible with
  131. # release strategy implemented in release.sh
  132. #
  133. local xyz # base version string
  134. local prerl # pre-release keyword (from mkit.ini, eg. 'beta')
  135. local latest_tag # latest git tag
  136. local commit # commit indicator (CURRENT_BRANCH.gHASH)
  137. local dirty=F # F if dirty, T if clean
  138. local btime # timestamp or nothing (see $MKIT_TTAG)
  139. local suffix # version suffix
  140. prerl=$(ini 1value project:prerl)
  141. case $MKIT_TTAG in
  142. none) btime= ;;
  143. btime) btime=$(date -u +%Y%m%d%H%M%S) ;;
  144. ctime) btime=$(date -d @"$(git_fact latest_cdate)" -u +%Y%m%d%H%M%S) ;;
  145. esac
  146. grep ":" <<<"$prerl" \
  147. && warn "colon in project:prerl may corrupt version data: $prerl"
  148. git_present || {
  149. echo UNKNOWN_VERSION
  150. warn "no git present; could not determine SemVer"
  151. return 3
  152. }
  153. latest_tag=$(git_fact latest_tag)
  154. case $latest_tag in
  155. v*) xyz=${latest_tag:1} ;;
  156. "") warn "no tags, using base version from mkit.ini (ok for new project)"
  157. xyz=$(ini 1value project:version) ;;
  158. *) warn "bad form of last tag, using base version from mkit.ini: tag is '$latest_tag'"
  159. xyz=$(ini 1value project:version) ;;
  160. esac
  161. if ! git describe --tags --exact-match HEAD >&/dev/null;
  162. then # we are at a later commit than the last tag
  163. commit="$(git_fact current_branch).g$(git_fact latest_sha)"
  164. fi
  165. git_bool dirty && dirty=T
  166. case "$dirty:$btime:$commit" in
  167. F:*:) suffix="" ;;
  168. T::) suffix="+dirty" ;;
  169. T:*:) suffix="+t$btime.dirty" ;;
  170. F::*) suffix="+$commit" ;;
  171. F:*:*) suffix="+t$btime.$commit" ;;
  172. T::*) suffix="+$commit.dirty" ;;
  173. T:*:*) suffix="+t$btime.$commit.dirty" ;;
  174. *) suffix=MKIT_BUG
  175. warn "MKIT_BUG: bad dirt/commit detection" ;;
  176. esac
  177. test -n "$prerl" && suffix="-$prerl$suffix"
  178. echo "$xyz$suffix"
  179. }