Simple Makefile target helper https://pagure.io/mkit

build.sh 7.2KB

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