123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  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. git_lastsummary() {
  99. #
  100. # Show last commit summary
  101. #
  102. # We can't do it outside git repo (or without git) but we should
  103. # not be asked to; targets that don't require git should make use
  104. # of cache built by dist target.
  105. #
  106. git_present || {
  107. echo UNKNOWN_SUMMARY
  108. warn "no git present; could not determine last summary"
  109. return 3
  110. }
  111. git_bool dirty && {
  112. echo "(index is dirty)"
  113. return
  114. }
  115. git log -1 --format=oneline HEAD \
  116. | cut -d' ' -f2-
  117. }
  118. semver() {
  119. #
  120. # Build proper SemVer version string
  121. #
  122. # Build version string from available info using following
  123. # logic:
  124. #
  125. # 1. Use version from last git tag (or mkit.ini if there is no
  126. # tag, which is possible on new project)
  127. # 2. if set, add project:prerl (from mkit.ini) as pre-release ID
  128. # (afer dash)
  129. # 3. if we are at a later commit than the last tag, add branch
  130. # name and commit sha1 to build metadata (after plus sign)
  131. # 4. if the tree is "dirty", i.e. has uncommited changes,
  132. # add "dirty" to build metadata
  133. #
  134. # The version is compatible with SemVer 2.0.0.
  135. #
  136. # Examples:
  137. #
  138. # foo v1.0.7 # all clear; proper release
  139. # foo v1.0.7-beta # mkit.ini: project:prerl="beta"
  140. # foo v1.0.7-beta+g1aef811.master # ^^ + some commits after
  141. # foo v1.0.7-beta+gf14fc4f.api2 # ^^ + on a feature branch
  142. # foo v1.0.7-beta+gf14fc4f.api2.dirty # ^^ + tree edited
  143. # foo v1.0.7-beta+dirty # tag OK but tree edited
  144. # foo v1.0.7+dirty # ^^ but no pre-release id
  145. #
  146. # Note that versions with "dirty" should be perceived as kind of
  147. # dangerous outside developer's own machine. Versions with sha1 are
  148. # safer but must not be released.
  149. #
  150. # FIXME: Using project:prerl for release IDs may not be compatible with
  151. # release strategy implemented in release.sh
  152. #
  153. local xyz # base version string
  154. local prerl # pre-release keyword (from mkit.ini, eg. 'beta')
  155. local latest_tag # latest git tag
  156. local brname # current branch name
  157. local ghash # current commit short hash
  158. local is_tagged=T # T if tagged (clean, no metadata), F if devel
  159. local is_dirty=F # F if dirty, T if clean
  160. local stamp # timestamp or nothing (see $MKIT_TSTAMP)
  161. local suffix # version suffix
  162. prerl=$(ini 1value project:prerl)
  163. case $MKIT_TSTAMP in
  164. none) stamp= ;;
  165. btime) stamp=$(date -u +%Y%m%d%H%M%S) ;;
  166. ctime) stamp=$(date -d @"$(git_fact latest_cdate)" -u +%Y%m%d%H%M%S) ;;
  167. esac
  168. grep ":" <<<"$prerl" \
  169. && warn "colon in project:prerl may corrupt version data: $prerl"
  170. git_present || {
  171. echo UNKNOWN_VERSION
  172. warn "no git present; could not determine SemVer"
  173. return 3
  174. }
  175. latest_tag=$(git_fact latest_tag)
  176. case $latest_tag in
  177. v*) xyz=${latest_tag:1} ;;
  178. "") warn "no tags, using base version from mkit.ini (ok for new project)"
  179. xyz=$(ini 1value project:version) ;;
  180. *) warn "bad form of last tag, using base version from mkit.ini: tag is '$latest_tag'"
  181. xyz=$(ini 1value project:version) ;;
  182. esac
  183. if ! git describe --tags --exact-match HEAD >&/dev/null;
  184. then # we are at a later commit than the last tag
  185. is_tagged=F
  186. brname=$(git_fact current_branch | sed 's/[^[:alnum:]]/_/g')
  187. ghash=$(git_fact latest_sha)
  188. fi
  189. git_bool dirty && is_dirty=T
  190. case "$is_dirty:$is_tagged:$stamp" in
  191. F:T:*) suffix="" ;;
  192. T:T:) suffix="+dirty" ;;
  193. T:T:*) suffix="+t$stamp.dirty" ;;
  194. F:F:) suffix="+$brname.g$ghash" ;;
  195. F:F:*) suffix="+t$stamp.$brname.g$ghash" ;;
  196. T:F:) suffix="+$brname.g$ghash.dirty" ;;
  197. T:F:*) suffix="+t$stamp.$brname.g$ghash.dirty" ;;
  198. *) suffix=MKIT_BUG
  199. warn "MKIT_BUG: bad dirt/commit detection" ;;
  200. esac
  201. test -n "$prerl" && suffix="-$prerl$suffix"
  202. echo "$xyz$suffix"
  203. }