123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. #!/bin/bash
  2. . mkit/include/ini.sh || die "cannot import ini.sh"
  3. build() {
  4. #
  5. # Add meat to all skeletons
  6. #
  7. local srcpath
  8. find src -type f -name '*.skel' \
  9. | while read srcpath;
  10. do
  11. build1 "$srcpath"
  12. done
  13. }
  14. build1() {
  15. #
  16. # Process one skeleton
  17. #
  18. local srcpath dstpath
  19. srcpath=$1
  20. dstpath=${srcpath%.skel}
  21. case $dstpath in
  22. *.md) cat $srcpath \
  23. | expand_includes \
  24. | expand_variables \
  25. > $dstpath ;;
  26. *) cat $srcpath \
  27. | expand_variables \
  28. > $dstpath ;;
  29. esac
  30. echo $dstpath >> built.list
  31. }
  32. build_manpages() {
  33. local manfile mdfile
  34. if command -v ronn >/dev/null;
  35. then
  36. ini lskeys "files:man" \
  37. | while read manfile;
  38. do
  39. mdfile=$manfile.md
  40. ronn -r $mdfile
  41. echo $manfile >> built.list
  42. done
  43. else
  44. echo "ronn is not installed"
  45. return 1
  46. fi
  47. }
  48. clean() {
  49. #
  50. # Clean up tree after building
  51. #
  52. test -f built.list && {
  53. cat built.list | xargs rm -f
  54. rm -f built.list
  55. } || :
  56. }
  57. dist() {
  58. #
  59. # Create distributable tarball
  60. #
  61. local version=$(get_version)
  62. local dirname=$MKIT_PKGNAME-$version
  63. mkdir -p $dirname
  64. local item
  65. cp -R $(ini values "lists:dist") $dirname
  66. sed -i -e "s/^VERSION = .*/VERSION = $version/" $dirname/config.mk
  67. tar -cf $dirname.tar $dirname
  68. gzip $dirname.tar
  69. rm -rf $dirname
  70. }
  71. expand_includes() {
  72. #
  73. # Expand include directives
  74. #
  75. # Expand e.g. `<!-- include4: foo.sh -->` to include code of foo.sh
  76. #
  77. perl -we '
  78. use strict;
  79. my $text;
  80. while (<>) {
  81. chomp;
  82. if (m/<!-- include4: (\S+) -->/) {
  83. open my $fh, $1 or warn "cannot find: $1";
  84. my $text = do { local($/); <$fh> };
  85. close $fh;
  86. $text =~ s/^(.)/ $1/gm;
  87. chomp $text;
  88. print "$text\n";
  89. } else {
  90. print "$_\n";
  91. }
  92. }
  93. '
  94. }
  95. expand_variables() {
  96. #
  97. # Expand variable values
  98. #
  99. local script=$(mktemp --tmpdir mkit-tmp.XXXXXXXXXX)
  100. local varname varvalue
  101. ini lskeys "vars" \
  102. | while read varname;
  103. do
  104. varvalue="$(ini 1value "vars:$varname" | sed -e 's/\$/\\$/' )"
  105. echo "s|$varname|$varvalue|;" >> $script
  106. done
  107. echo "s|__CODENAME__|$CODENAME|;" >> $script
  108. echo "s|__VERSION__|$(get_version)|;" >> $script
  109. perl -wp $script
  110. rm $script
  111. }
  112. get_version() {
  113. #
  114. # Build semver version string with build metadata
  115. #
  116. # Build version string from available info using following
  117. # logic:
  118. #
  119. # 1. use VERSION (from config.mk)
  120. # 2. if we are in git, override the version with last tag
  121. # 3. if set, add PRERELEASE (from config.mk) as pre-release ID
  122. # (afer dash)
  123. # 4. if we are at a later commit than the last tag, add branch
  124. # name and commit sha1 to build metadata (after plus sign)
  125. # 5. if the tree is "dirty", i.e. has uncommited changes,
  126. # add "dirty" to build metadata
  127. #
  128. # The version is compatible with SemVer 2.0.0.
  129. #
  130. # Examples:
  131. #
  132. # myprog v1.0.7 # all clear
  133. # myprog v1.0.7-alpha # PRERELEASE="alpha"
  134. # myprog v1.0.7-alpha+g1aef811.master # ^^ + some commits after
  135. # myprog v1.0.7-alpha+gf14fc4f.api2 # ^^ + on a feature branch
  136. # myprog v1.0.7-alpha+gf14fc4f.api2.dirty # ^^ + tree edited
  137. # myprog v1.0.7-alpha+dirty # tag OK but tree edited
  138. # myprog v1.0.7+dirty # ^^ but no pre-release id
  139. #
  140. # Note that versions with "dirty" should be perceived as kind of
  141. # dangerous outside developer's own machine. Versions with sha1 are
  142. # safer but must not be released.
  143. #
  144. # I have considered decorating the git commit refs to make them
  145. # sort of sortable (e.g. "r1.g1aef811"), but on second thought,
  146. # I don't think it's good idea to give *any* semantics to meta-data
  147. # at all. First, there is no rule that r1<r2<r3; a commit can be
  148. # removing what other just added and one change can be split to
  149. # multiple commits. Also, the whole thing breaks anyway once you
  150. # rebase your branch (no, it's not a sin). The sole purpose of
  151. # meta-data is to *identify* the code, and provide safe path back
  152. # to tree; commit refs are already perfect for that.
  153. #
  154. # FIXME: The assumpton "if we are in git repo, we can read version
  155. # from tags" fails if we are in shallow clone made from
  156. # other than a tagged commit.
  157. #
  158. # FIXME: Using PRERELEASE for release IDs may not be compatible with
  159. # release strategy implemented in release.sh
  160. #
  161. local version=$VERSION
  162. local prerl=$PRERELEASE
  163. grep ":" <<<"$prerl" && warn "colon in PRERELEASE may corrupt version data: $prerl"
  164. if git rev-parse HEAD >&/dev/null;
  165. then # we are in git repo... so we can get smart
  166. local lasttag=$(git tag | grep ^v | sort -V | tail -n1)
  167. if ! git describe --tags --exact-match HEAD >&/dev/null;
  168. then # we are at a later commit than the last tag
  169. local sha=g$(git log -1 --pretty=format:%h HEAD)
  170. local curbranch=$(git rev-parse --abbrev-ref HEAD)
  171. local commit="$curbranch.$sha"
  172. fi
  173. if test "$(git diff --shortstat 2>/dev/null)" != "";
  174. then # the tree is "dirty", i.e. has been edited
  175. local dirty=dirty
  176. fi
  177. version=${lasttag:1}
  178. local suffix=""
  179. case $prerl:$commit:$dirty in
  180. ::) suffix="" ;;
  181. ::dirty) suffix="+$dirty" ;;
  182. :*:) suffix="+$commit" ;;
  183. :*:dirty) suffix="+$commit" ;;
  184. *::) suffix="-$prerl" ;;
  185. *::dirty) suffix="-$prerl+$dirty" ;;
  186. *:*:) suffix="-$prerl+$commit" ;;
  187. *:*:dirty) suffix="-$prerl+$commit.$dirty" ;;
  188. esac
  189. version=$version$suffix
  190. fi
  191. echo $version
  192. }