123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392 |
- #!/bin/bash
- # MKit - simple install helper
- # See LICENSE file for copyright and license details.
-
- mkit_import ini
- mkit_import facts
- mkit_import plugin
- mkit_import util
-
-
- build__file() {
- #
- # Process one skeleton $1 of type $3 (or guessed) to path $2
- #
- local srcpath=$1 # skeleton path
- local dstpath=$2 # destination meaty animal path
- local ftype=$3 # file/builder type
- test -n "$dstpath" || dstpath=${srcpath%.skel}
- test -n "$ftype" || ftype=MKIT_COMMON
- debug_var srcpath dstpath ftype
- <"$srcpath" __build__file_type "$ftype" >"$dstpath"
- build__record "$dstpath"
- }
-
- __build__file_type() {
- #
- # Build a file of type $1; fom stdin to stdout
- #
- local ftype=$1 # file/builder type
- if test "$ftype" == MKIT_COMMON; then
- __build__macro_expand "build:macros"
- elif plugin__isvalid "$ftype"; then
- __build__macro_expand "$ftype:macros"
- else
- die "unknown file type: $ftype"
- fi
- }
-
- __build__macro_ls() {
- #
- # List known macros
- #
- find "${MacroDirs[@]}" -mindepth 1 -depth -printf '%P\n' \
- | sed 's/[.]/:/g'
- }
-
- __build__macro_read() {
- #
- # Read macro $1
- #
- local key=$1
- find "${MacroDirs[@]}" -mindepth 1 -depth -name "$key" \
- | head -1 \
- | xargs -r cat
- }
-
- __build__macro_put() {
- #
- # Write stdin as macro $1
- #
- local fqkey=$1
- local file="$MKIT_LOCAL/data/${fqkey//:/.}"
- mkdir -p "${file%/*}"
- cat >"$file"
- }
-
- __build__macro_expand_line() {
- #
- # Expand macro from config in single line $1
- #
- # If macro value has multiple lines, repeat original line with
- # different substitution.
- #
- # E.g. if macro value is "foo\nbar" and macro name is __FOO__,
- # line `see: "__FOO__"` will expand to two lines: `see: "foo"`
- # and `see: "bar"`.
- #
- local raw_line=$1 # line to process
- local macro_name # macro name
- local macro_value_line # line of macro value
- local expanded_line # expanded line
- expanded_line=$raw_line
- for macro_name in $(__build__macro_ls); do
- if ! test "${raw_line//$macro_name}" == "$raw_line"; then
- expanded_line=$(
- while IFS= read -r macro_value_line; do
- echo "${raw_line//"$macro_name"/"$macro_value_line"}"
- done <<<"$(__build__macro_read "$macro_name")"
- )
- fi
- raw_line=$expanded_line
- done
- echo "$expanded_line"
- return 1
- }
-
- __build__macro_expand() {
- #
- # Read stdin, expanding macros from extra sections $@
- #
- local MacroDirs=() # directories to lookup macros in
- local mdir # every ^^
- local line # each line on stdin
- local bltndata="$MKIT_LOCAL/data/MKIT_BUILTIN"
- local usrdata="$MKIT_LOCAL/data/macros"
- test -d "$bltndata" && MacroDirs+=("$bltndata")
- test -d "$usrdata" && MacroDirs+=("$usrdata")
- for extra in "$@"; do
- mdir="$MKIT_LOCAL/data/${extra//:/.}"
- test -d "$mdir" || continue
- MacroDirs+=("$mdir")
- done
- while IFS= read -r line; do
- __build__macro_expand_line "$line"
- done
- }
-
- build__cached() {
- #
- # Cached value $1 of function $1()
- #
- # In order to support git-less builds, some values might be cached
- # in $MKIT_LOCAL. This function gets file $1 from that cache (cache
- # hit) or re-creates it (cache miss), but prints its body in either
- # case.
- #
- # The command to re-create file is the same as the key (ie. no
- # arguments).
- #
- local name=$1
- __local_get "$name" && debug "cache hit with: $name()" && return 0
- debug "cache miss with: $name()"
- "$name" | __local_putb "$name"
- __local_get "$name"
- }
-
- __local_putb() {
- #
- # Make file $1 in $MKIT_LOCAL from stdin and mark as built
- #
- local fpath=$1
- __local_put "$fpath" && build__record "$MKIT_LOCAL/$fpath"
- }
-
- __local_put() {
- #
- # Make file $1 in $MKIT_LOCAL from stdin
- #
- local fpath="$MKIT_LOCAL/$1"
- { mkdir -p "${fpath%/*}" && cat >"$fpath"; } \
- || die "cannot write to local cache: $fpath"
- }
-
- __local_get() {
- #
- # Read file $1 in $MKIT_LOCAL
- #
- local fpath="$MKIT_LOCAL/$1"
- cat "$fpath" 2>/dev/null
- }
-
- build__fact() {
- #
- # Make fact file $1 in $MKIT_LOCAL from stdin; mark as built
- #
- local name=$1
- __local_put "facts/$name" || die
- build__recordr "$MKIT_LOCAL/facts"
- }
-
- build__factr() {
- #
- # Read fact file $1 from $MKIT_LOCAL
- #
- local name=$1
- cat "$MKIT_LOCAL/facts/$name" || die
- }
-
- build__record() {
- #
- # Record file $1 for deletion on `clean`
- #
- local file=$1
- mkdir -p "$MKIT_LOCAL"
- echo "1:$file" >> "$MKIT_LOCAL/built.lst"
- }
-
- build__recordr() {
- #
- # Record dir $1 for recursive deletion on `clean`
- #
- local path=$1
- mkdir -p "$MKIT_LOCAL"
- echo "r:$path" >> "$MKIT_LOCAL/built.lst"
- }
-
- _mkit_builddata() {
- #
- # Build config data
- #
- local macro
- local section
- test -d "$MKIT_LOCAL/data/build.macros" && {
- warn "mkit: using cached _mkit_builddata: $(date -Isec -r "$MKIT_LOCAL/data/build.macros")" \
- "mkit: (hint: run 'make clean' to regenerate it)"
- return 0
- }
- build__recordr "$MKIT_LOCAL/data"
- for macro in $(ini lskeys "build:macros"); do
- ini values "build:macros:$macro" | __build__macro_put "build:macros/$macro"
- done
- }
-
- _mkit_inidata() {
- #
- # Build INI data
- #
- test -d "$MKIT_LOCAL/data/ini" && {
- warn "mkit: using cached _mkit_inidata: $(date -Isec -r "$MKIT_LOCAL/data/ini")" \
- "mkit: (hint: run 'make clean' to regenerate it)"
- return 0
- }
- build__recordr "$MKIT_LOCAL/data"
- local sect
- local key
- ini lssect \
- | while read -r sect; do
- mkdir -p "$MKIT_LOCAL/data/ini/$sect"
- ini lskeys "$sect" \
- | while read -r key; do
- ini values "$sect:$key" >"$MKIT_LOCAL/data/ini/$sect/$key"
- done
- done
- }
-
- _mkit_metadata() {
- #
- # Build meta data
- #
- local plg_sections=()
- test -d "$MKIT_LOCAL/data/MKIT_BUILTIN" && {
- warn "mkit: using cached _mkit_metadata: $(date -Isec -r "$MKIT_LOCAL/data/MKIT_BUILTIN")" \
- "mkit: (hint: run 'make clean' to regenerate it)"
- return 0
- }
- build__recordr "$MKIT_LOCAL/data"
- echo "$MKIT_VERSION" | __build__macro_put MKIT_BUILTIN/__MKIT_MKIT_VERSION__
- ini 1value project:name | __build__macro_put MKIT_BUILTIN/__MKIT_PROJ_NAME__
- ini 1value project:codename | __build__macro_put MKIT_BUILTIN/__MKIT_PROJ_CODENAME__
- ini 1value project:license | __build__macro_put MKIT_BUILTIN/__MKIT_PROJ_LICENSE__
- ini 1value project:pkgname | __build__macro_put MKIT_BUILTIN/__MKIT_PROJ_PKGNAME__
- ini 1value project:tagline | __build__macro_put MKIT_BUILTIN/__MKIT_PROJ_TAGLINE__
- ini 1value project:maintainer | __build__macro_put MKIT_BUILTIN/__MKIT_PROJ_MAINTAINER__
- ini 1value project:vcs_browser | __build__macro_put MKIT_BUILTIN/__MKIT_PROJ_VCS_BROWSER__
- build__cached git_lasthash | __build__macro_put MKIT_BUILTIN/__MKIT_PROJ_GIT_LASTHASH__
- build__cached git_lastsummary | __build__macro_put MKIT_BUILTIN/__MKIT_PROJ_GIT_LASTSUMMARY__
- build__cached semver | __build__macro_put MKIT_BUILTIN/__MKIT_PROJ_VERSION__
- util__loadarr plg_sections __plugin_macro_sections
- debug_var plg_sections
- for section in macros "${plg_sections[@]}"; do
- for macro in $(ini lskeys "$section"); do
- ini values "$section:$macro" | __build__macro_put "$section/$macro"
- done
- done
- }
-
- __subdirs() {
- #
- # List direct sub-directories of $1
- #
- find "$1" -maxdepth 1 -mindepth 1 -printf '%P\n' -type d
- }
-
- __subfiles() {
- #
- # List direct sub-files of $1
- #
- find "$1" -maxdepth 1 -mindepth 1 -printf '%P\n' -type f
- }
-
- __plugin_macro_sections() {
- #
- # List macro sections for plugins
- #
- plugin__ls \
- | sed 's/$/:macros/'
- }
-
- _mkit_show_metadata() {
- #
- # Show sampler of macro values
- #
- __show_msection MKIT_BUILTIN
- __show_msection macros
- __plugin_macro_sections \
- | while read -r section; do
- __show_msection "$section"
- done
- }
-
- _mkit_show_builddata() {
- #
- # Show sampler of config values
- #
- __show_msection build:macros
- }
-
- __show_msection() {
- #
- # Show macros of section $1
- #
- local section=$1
- local macro_name
- local first=true
- local label=$section
- local secdir="$MKIT_LOCAL/data/${section//:/.}"
- test -d "$secdir" || return 0
- test "$section" == MKIT_BUILTIN && label="(builtin)"
- for macro_name in $(__subfiles "$secdir"); do
- $first && echo "$label:"; first=false
- echo " $macro_name => '$(<"$secdir/$macro_name")'"
- done
- }
-
- build() {
- #
- # Add meat to all skeletons
- #
- local srcpath # each source path
- find . -type f -name '*.skel' \
- | while read -r srcpath; do
- build__file "$srcpath"
- done
- }
-
- clean() {
- #
- # Clean up tree after building
- #
- local path
- local line
- local depth
- test -f "$MKIT_LOCAL/built.lst" || return 0
- {
- cat "$MKIT_LOCAL/built.lst"
- echo "1:$MKIT_LOCAL/built.lst"
- echo "1:$MKIT_LOCAL"
- } \
- | grep -v -e '\.\.' -e ^/ -e '^~' \
- | while IFS=: read -r depth path; do
- test -e "$path" || continue
- case $depth in
- 1) warn "removing: $path"
- test -d "$path" \
- && rmdir -p --ignore-fail-on-non-empty "$path"
- test -f "$path" && rm "$path"
- ;;
- r) warn "removing recursively: $path"
- rm -r "$path"
- ;;
- *) warn "invalid built.lst format!"
- ;;
- esac
- done
- true
- }
-
- dist() {
- #
- # Create distributable tarball
- #
- #FIXME: lacking Makefile skills, we do this step twice for
- # rpmstuff, hence -f hack for gzip
- #
- local version # tarball version
- local git_lasthash # last git commit hash
- local dirname # directory and tarball name
- version=$(semver)
- dirname=$MKIT_PROJ_PKGNAME-$version
- git_lasthash=$(git_lasthash)
- debug_var version dirname git_lasthash
- mkdir -p "$dirname"
- ini values "dist:tarball" | xargs -I DIST_ITEM cp -R DIST_ITEM "$dirname"
- mkdir -p "$dirname/.mkit"
- echo -n "$version" > "$dirname/.mkit/semver"
- echo -n "$git_lasthash" > "$dirname/.mkit/git_lasthash"
- cp -r "$MKIT_LOCAL/data" "$dirname/.mkit/"
- tar -cf "$dirname.tar" "$dirname"
- gzip -f "$dirname.tar" # see above FIXME
- build__record "$dirname.tar.gz"
- rm -rf "$dirname"
- }
|