Explorar el Código

Update own dogfood

Alois Mahdal hace 8 años
padre
commit
94cb4cf71b

+ 14
- 20
mkit.ini Ver fichero

@@ -1,3 +1,4 @@
1
+#mkit version=0.0.14
1 2
 
2 3
 [project]
3 4
 
@@ -9,31 +10,24 @@
9 10
     relsrc      = master
10 11
     reldst      = last
11 12
 
12
-[ENV]
13
-
14
-    PREFIX = utils
15
-
16 13
 [lists]
14
+    tarball = Makefile
15
+    tarball = mkit.ini
16
+    tarball = README.md
17
+    tarball = src
18
+    tarball = utils
17 19
 
18
-    group = bin
19
-    group = rest
20
-
21
-    dist = Makefile
22
-    dist = mkit.ini
23
-    dist = README.md
24
-    dist = src
25
-    dist = utils
26
-
27
-[modes]
28
-    bin = 755
20
+[ENV]
21
+    PREFIX = utils
29 22
 
30 23
 [roots]
31 24
     bin  = [ENV:PREFIX]/mkit
32 25
     rest = [ENV:PREFIX]/mkit
33 26
 
34
-[files:bin]
35
-    src/make     = make
27
+[modes]
28
+    bin = 755
36 29
 
37
-[files:rest]
38
-    src/include  = include
39
-    src/mkit.mk  = mkit.mk
30
+[files]
31
+    bin = src/make
32
+    rest = src/include
33
+    rest = src/mkit.mk

+ 122
- 187
utils/mkit/include/build.sh Ver fichero

@@ -1,21 +1,10 @@
1 1
 #!/bin/bash
2 2
 
3
-. "$MKIT_DIR/include/ini.sh" || die "cannot import ini.sh"
3
+. "$MKIT_DIR/include/ini.sh"   || die "cannot import ini.sh"
4
+. "$MKIT_DIR/include/facts.sh" || die "cannot import facts.sh"
4 5
 
5 6
 
6
-build() {
7
-    #
8
-    # Add meat to all skeletons
9
-    #
10
-    local srcpath
11
-    find src -type f -name '*.skel' \
12
-     | while read srcpath;
13
-       do
14
-           build1 "$srcpath"
15
-       done
16
-}
17
-
18
-build1() {
7
+_build1() {
19 8
     #
20 9
     # Process one skeleton
21 10
     #
@@ -23,14 +12,84 @@ build1() {
23 12
     local dstpath="$2"
24 13
     local ftype="$3"
25 14
     test -n "$dstpath"  || dstpath=${srcpath%.skel}
26
-    test -n "$ftype"    || ftype=$(guess_ftype "$dstpath")
15
+    test -n "$ftype"    || ftype=$(_guess_ftype "$dstpath")
27 16
     debug_var srcpath dstpath ftype
28
-    <"$srcpath" build1_ftype "$ftype" >"$dstpath"
17
+    <"$srcpath" _build1_ftype "$ftype" >"$dstpath"
29 18
     mkdir -p "$MKIT_LOCAL"
30 19
     echo "$dstpath" >> "$MKIT_LOCAL/built.lst"
31 20
 }
32 21
 
33
-guess_ftype() {
22
+_build1_ftype() {
23
+    #
24
+    # Build a file of type $1
25
+    #
26
+    local ftype="$1"
27
+    case $ftype in
28
+        MKIT_COMMON)    _expand_tokens "tokens" ;;
29
+        markdown)       _expand_includes | _expand_tokens "tokens" ;;
30
+        rpmstuff)       _expand_tokens "tokens" "rpmstuff:tokens" ;;
31
+        *)              die "unknown file type: $ftype" ;;
32
+    esac
33
+}
34
+
35
+_expand_includes() {
36
+    #
37
+    # Expand include directives
38
+    #
39
+    # Expand e.g. `<!-- include4: foo.sh -->` to include code of foo.sh
40
+    #
41
+    perl -we '
42
+        use strict;
43
+        my $text;
44
+        while (<>) {
45
+            chomp;
46
+            if (m/<!-- include4: (\S+) -->/) {
47
+                open my $fh, $1 or warn "cannot find: $1";
48
+                my $text = do { local($/); <$fh> };
49
+                close $fh;
50
+                $text =~ s/^(.)/    $1/gm;
51
+                chomp $text;
52
+                print "$text\n";
53
+            } else {
54
+                print "$_\n";
55
+            }
56
+        }
57
+    '
58
+}
59
+
60
+_expand_tokens() {
61
+    #
62
+    # Expand tokens from sections $@
63
+    #
64
+    local script=$(mktemp --tmpdir mkit-tmp.XXXXXXXXXX)
65
+    local section varname varvalue
66
+    {
67
+        for section in "$@";
68
+        do
69
+            debug_var section
70
+            ini lskeys "$section" \
71
+              | while read varname;
72
+                do
73
+                    varvalue="$(ini 1value "$section:$varname" | _qfs )"
74
+                    echo "s|$varname|$varvalue|g;"
75
+                    debug_var varname varvalue
76
+                done
77
+        done
78
+        echo "s|__MKIT_PROJ_NAME__|$(ini 1value project:name | _qfs)|g;"
79
+        echo "s|__MKIT_PROJ_CODENAME__|$(ini 1value project:codename | _qfs)|g;"
80
+        echo "s|__MKIT_PROJ_PKGNAME__|$(ini 1value project:pkgname | _qfs)|g;"
81
+        echo "s|__MKIT_PROJ_TAGLINE__|$(ini 1value project:tagline | _qfs)|g;"
82
+        echo "s|__MKIT_PROJ_MAINTAINER__|$(ini 1value project:maintainer | _qfs)|g;"
83
+        echo "s|__MKIT_PROJ_VCS_BROWSER__|$(ini 1value project:vcs_browser | _qfs)|g;"
84
+        echo "s|__MKIT_PROJ_GIT_LASTHASH__|$(git_lasthash | _qfs)|g;"
85
+        echo "s|__MKIT_PROJ_VERSION__|$(semver | _qfs)|g;"
86
+        echo "s|__MKIT_SELF_VERSION__|$MKIT_VERSION|g;"
87
+    } >> "$script"
88
+    sed -f "$script" || die "_expand_tokens failed"
89
+    rm "$script"
90
+}
91
+
92
+_guess_ftype() {
34 93
     #
35 94
     # Guess file type from destination path $1
36 95
     #
@@ -41,17 +100,26 @@ guess_ftype() {
41 100
     esac
42 101
 }
43 102
 
44
-build1_ftype() {
103
+_qfs() {
45 104
     #
46
-    # Build a file of type $1
105
+    # Quote for our sed scipt's RHS
47 106
     #
48
-    local ftype="$1"
49
-    case $ftype in
50
-        MKIT_COMMON)    expand_variables "vars" ;;
51
-        markdown)       expand_includes | expand_variables "vars" ;;
52
-        rpmstuff)       expand_variables "vars" "rpmstuff:vars" ;;
53
-        *)              die "unknown file type: $ftype" ;;
54
-    esac
107
+    sed '
108
+        s:\\:\\\\:g
109
+        s:|:\\|:g
110
+    '
111
+}
112
+
113
+build() {
114
+    #
115
+    # Add meat to all skeletons
116
+    #
117
+    local srcpath
118
+    find src -type f -name '*.skel' \
119
+     | while read srcpath;
120
+       do
121
+           _build1 "$srcpath"
122
+       done
55 123
 }
56 124
 
57 125
 build_manpages() {
@@ -85,30 +153,11 @@ clean() {
85 153
     true
86 154
 }
87 155
 
88
-dist() {
89
-    #
90
-    # Create distributable tarball
91
-    #
92
-    #FIXME: lacking Makefile skills, we do this step twice fot
93
-    #       rpmstuff, hence -f hack for gzip
94
-    #
95
-    local version=$(get_version)
96
-    local dirname=$MKIT_PROJ_PKGNAME-$version
97
-    mkdir -p "$dirname"
98
-    ini values "lists:dist" | xargs -I DIST_ITEM cp -R DIST_ITEM "$dirname"
99
-    update_version "$version" "$dirname/mkit.ini"
100
-    tar -cf "$dirname.tar" "$dirname"
101
-    gzip -f "$dirname.tar"      # see above FIXME
102
-    mkdir -p "$MKIT_LOCAL"
103
-    echo "$dirname.tar.gz" >> "$MKIT_LOCAL/built.lst"
104
-    rm -rf "$dirname"
105
-}
106
-
107 156
 debstuff() {
108 157
     #
109 158
     # Build Debian stuff (eamed tarball, debian dir)
110 159
     #
111
-    local version="$(get_version)"
160
+    local version="$(semver)"
112 161
 
113 162
     # tarball - we should already have by means of 'dist'
114 163
     #
@@ -119,8 +168,8 @@ debstuff() {
119 168
 
120 169
     # read content of each mandatory file from debian_skel
121 170
     #
122
-    local debian_skel=$(ini 1value debstuff:debian_skel)
123
-    test -n "$debian_skel" || die "debstuff:debian_skel not specified"
171
+    local debian_skel=$(ini 1value dist:debstuff)
172
+    test -n "$debian_skel" || die "dist:debstuff not specified"
124 173
     test -d "$debian_skel" || die "debian directory template found: $debian_skel"
125 174
     mkdir -p debian/source
126 175
     local dfsrc dftgt
@@ -129,154 +178,40 @@ debstuff() {
129 178
         do
130 179
             dftgt="debian/${dfsrc#$debian_skel}"
131 180
             mkdir -p "$(dirname "$dftgt")"
132
-            build1 "$dfsrc" "$dftgt"
181
+            _build1 "$dfsrc" "$dftgt"
133 182
         done
134 183
     echo debian >> "$MKIT_LOCAL/built.lst"
135 184
 }
136 185
 
137
-rpmstuff() {
138
-    #
139
-    # Build specfile
140
-    #
141
-    local specname="$MKIT_PROJ_PKGNAME.spec"
142
-    local specsrc="$(ini 1value "rpmstuff:spec_skel")"
143
-    test -n "$specsrc" || die "rpmstuff:spec_skel not specified"
144
-    test -f "$specsrc" || die "specfile template not found: $specsrc"
145
-    build1 "$specsrc" "$specname"
146
-}
147
-
148
-expand_includes() {
149
-    #
150
-    # Expand include directives
151
-    #
152
-    # Expand e.g. `<!-- include4: foo.sh -->` to include code of foo.sh
186
+dist() {
153 187
     #
154
-    perl -we '
155
-        use strict;
156
-        my $text;
157
-        while (<>) {
158
-            chomp;
159
-            if (m/<!-- include4: (\S+) -->/) {
160
-                open my $fh, $1 or warn "cannot find: $1";
161
-                my $text = do { local($/); <$fh> };
162
-                close $fh;
163
-                $text =~ s/^(.)/    $1/gm;
164
-                chomp $text;
165
-                print "$text\n";
166
-            } else {
167
-                print "$_\n";
168
-            }
169
-        }
170
-    '
171
-}
172
-
173
-expand_variables() {
188
+    # Create distributable tarball
174 189
     #
175
-    # Expand variables from sections $@
190
+    #FIXME: lacking Makefile skills, we do this step twice fot
191
+    #       rpmstuff, hence -f hack for gzip
176 192
     #
177
-    local script=$(mktemp --tmpdir mkit-tmp.XXXXXXXXXX)
178
-    local section varname varvalue
179
-    {
180
-        for section in "$@";
181
-        do
182
-            debug_var section
183
-            ini lskeys "$section" \
184
-              | while read varname;
185
-                do
186
-                    varvalue="$(ini 1value "$section:$varname" | sed -e 's/\$/\\$/' )"
187
-                    echo "s|$varname|$varvalue|;"
188
-                    debug_var varname varvalue
189
-                done
190
-        done
191
-        echo "s|__MKIT_PROJ_NAME__|$(ini 1value project:name)|;"
192
-        echo "s|__MKIT_PROJ_CODENAME__|$(ini 1value project:codename)|;"
193
-        echo "s|__MKIT_PROJ_PKGNAME__|$(ini 1value project:pkgname)|;"
194
-        echo "s|__MKIT_PROJ_TAGLINE__|$(ini 1value project:tagline)|;"
195
-        echo "s|__MKIT_PROJ_VERSION__|$(get_version)|;"
196
-        echo "s|__MKIT_SELF_VERSION__|$MKIT_VERSION|;"
197
-    } >> "$script"
198
-    perl -wp "$script" || die "expand_variables failed"
199
-    rm "$script"
193
+    local version=$(semver)
194
+    local git_lasthash=$(git_lasthash)
195
+    local dirname=$MKIT_PROJ_PKGNAME-$version
196
+    mkdir -p "$dirname"
197
+    ini values "dist:tarball" | xargs -I DIST_ITEM cp -R DIST_ITEM "$dirname"
198
+    update_version "$version" "$dirname/mkit.ini"
199
+    mkdir -p "$dirname/.mkit"
200
+    echo -n "$git_lasthash" > "$dirname/.mkit/git_lasthash"
201
+    tar -cf "$dirname.tar" "$dirname"
202
+    gzip -f "$dirname.tar"      # see above FIXME
203
+    mkdir -p "$MKIT_LOCAL"
204
+    echo "$dirname.tar.gz" >> "$MKIT_LOCAL/built.lst"
205
+    rm -rf "$dirname"
200 206
 }
201 207
 
202
-get_version() {
203
-    #
204
-    # Build semver version string with build metadata
205
-    #
206
-    # Build version string from available info using following
207
-    # logic:
208
-    #
209
-    #  1. use project.version (from mkit.ini)
210
-    #  2. if we are in git, override the version with last tag
211
-    #  3. if set, add project:prerl (from mkit.ini) as pre-release ID
212
-    #     (afer dash)
213
-    #  4. if we are at a later commit than the last tag, add branch
214
-    #     name and commit sha1 to build metadata (after plus sign)
215
-    #  5. if the tree is "dirty", i.e. has uncommited changes,
216
-    #     add "dirty" to build metadata
217
-    #
218
-    # The version is compatible with SemVer 2.0.0.
219
-    #
220
-    # Examples:
221
-    #
222
-    #     myprog v1.0.7                         # all clear
223
-    #     myprog v1.0.7-alpha                   # mkit.ini: project:prerl="alpha"
224
-    #     myprog v1.0.7-alpha+g1aef811.master   # ^^ + some commits after
225
-    #     myprog v1.0.7-alpha+gf14fc4f.api2     # ^^ + on a feature branch
226
-    #     myprog v1.0.7-alpha+gf14fc4f.api2.dirty  # ^^ + tree edited
227
-    #     myprog v1.0.7-alpha+dirty             # tag OK but tree edited
228
-    #     myprog v1.0.7+dirty                   # ^^ but no pre-release id
229
-    #
230
-    # Note that versions with "dirty" should be perceived as kind of
231
-    # dangerous outside developer's own machine.  Versions with sha1 are
232
-    # safer but must not be released.
233
-    #
234
-    # I have considered decorating the git commit refs to make them
235
-    # sort of sortable (e.g. "r1.g1aef811"), but on second thought,
236
-    # I don't think it's good idea to give *any* semantics to meta-data
237
-    # at all.  First, there is no rule that r1<r2<r3; a commit can be
238
-    # removing what other just added and one change can be split to
239
-    # multiple commits.  Also, the whole thing breaks anyway once you
240
-    # rebase your branch (no, it's not a sin).  The sole purpose of
241
-    # meta-data is to *identify* the code, and provide safe path back
242
-    # to tree; commit refs are already perfect for that.
208
+rpmstuff() {
243 209
     #
244
-    # FIXME:  Using project:prerl for release IDs may not be compatible with
245
-    #         release strategy implemented in release.sh
210
+    # Build specfile
246 211
     #
247
-    local version=$(ini 1value project:version)
248
-    local prerl=$(ini 1value project:prerl)
249
-    grep ":" <<<"$prerl" && warn "colon in project:prerl may corrupt version data: $prerl"
250
-    if git rev-parse HEAD >&/dev/null;
251
-    then    # we are in git repo... so we can get smart
252
-        local latest_tag=$(
253
-            git log --format="%D" \
254
-              | sed 's/,/\n/g' \
255
-              | sed 's/^[[:blank:]]*//; ' \
256
-              | grep -E '^tag: v[[:digit:]]+\.' \
257
-              | cut -d' ' -f2 \
258
-              | head -1
259
-        )
260
-        if ! git describe --tags --exact-match HEAD >&/dev/null;
261
-        then    # we are at a later commit than the last tag
262
-            local sha=g$(git log -1 --pretty=format:%h HEAD)
263
-            local curbranch=$(git rev-parse --abbrev-ref HEAD)
264
-            local commit="$curbranch.$sha"
265
-        fi
266
-        if test "$(git diff --shortstat 2>/dev/null)" != "";
267
-        then    # the tree is "dirty", i.e. has been edited
268
-            local dirty=dirty
269
-        fi
270
-        test -n "$latest_tag" && version=${latest_tag:1}
271
-        local suffix=""
272
-        case "$commit:$dirty" in
273
-            :)       suffix=""                ;;
274
-            :dirty)  suffix="+$dirty"         ;;
275
-            *:)      suffix="+$commit"        ;;
276
-            *:dirty) suffix="+$commit.$dirty" ;;
277
-        esac
278
-        test -b "$prerl" && suffix="-$prerl$suffix"
279
-        version="$version$suffix"
280
-    fi
281
-    echo "$version"
212
+    local specname="$MKIT_PROJ_PKGNAME.spec"
213
+    local specsrc="$(ini 1value "dist:rpmstuff")"
214
+    test -n "$specsrc" || die "dist:rpmstuff not specified"
215
+    test -f "$specsrc" || die "specfile template not found: $specsrc"
216
+    _build1 "$specsrc" "$specname"
282 217
 }

+ 35
- 29
utils/mkit/include/deploy.sh Ver fichero

@@ -1,24 +1,10 @@
1 1
 #!/bin/bash
2 2
 
3
-_maybe() {
4
-    #
5
-    # Call the deploy command $1 $@ unless in dry mode
6
-    #
7
-    debug "$@"
8
-    local cmd="$1"; shift
9
-    $MKIT_DRY && return
10
-    case "$cmd" in
11
-        cp|rm|rmdir|chmod|mkdir) $cmd "$@" ;;
12
-        install)                 command -p install "$@" ;;
13
-        *)                       die "bad command called";;
14
-    esac
15
-}
16
-
17
-deploy_item() {
3
+_deploy_item() {
18 4
     #
19 5
     # Deploy item and make it look like wanted
20 6
     #
21
-    # usage: deploy_item src dst [mode]
7
+    # usage: _deploy_item src dst [mode]
22 8
     #
23 9
     # Both src and dst must be names of actual items[1],
24 10
     # whereas dst must not exist.  On update, dst is
@@ -54,18 +40,20 @@ deploy_item() {
54 40
     fi
55 41
 }
56 42
 
57
-get_dst() {
43
+_get_dst() {
58 44
     #
59 45
     # Find out target path for src file $2 of group $1
60 46
     #
61 47
     local grp=$1
62 48
     local src=$2
63
-    echo "$(get_root "$grp")/$(ini 1value "files:$grp:$src")"
49
+    local dst=$3
50
+    test -n "$dst" || dst=${src##*/}
51
+    echo "$(_get_root "$grp")/$dst"
64 52
 }
65 53
 
66
-get_root() {
54
+_get_root() {
67 55
     #
68
-    # Find out target rooot for group $1
56
+    # Find out target root for group $1
69 57
     #
70 58
     local grp="$1"
71 59
     local root=$(ini 1value "roots:$grp")
@@ -78,20 +66,36 @@ get_root() {
78 66
     esac
79 67
 }
80 68
 
69
+_maybe() {
70
+    #
71
+    # Call the deploy command $1 $@ unless in dry mode
72
+    #
73
+    debug "$@"
74
+    local cmd="$1"; shift
75
+    $MKIT_DRY && return
76
+    case "$cmd" in
77
+        cp|rm|rmdir|chmod|mkdir) $cmd "$@" ;;
78
+        install)                 command -p install "$@" ;;
79
+        *)                       die "bad command called";;
80
+    esac
81
+}
82
+
81 83
 install() {
82 84
     #
83 85
     # Install product
84 86
     #
85 87
     local dst group mode src
86
-    ini values "lists:group" \
88
+    ini lskeys "files" \
89
+      | sort \
90
+      | uniq \
87 91
       | while read group;
88 92
         do
89 93
             mode=$(ini 1value "modes:$group")
90
-            ini lskeys "files:$group" \
91
-              | while read src;
94
+            ini values "files:$group" \
95
+              | while read src dst;
92 96
                 do
93
-                    dst=$(get_dst "$group" "$src")
94
-                    deploy_item "$src" "$dst" "$mode"
97
+                    dst=$(_get_dst "$group" "$src" "$dst")
98
+                    _deploy_item "$src" "$dst" "$mode"
95 99
                 done
96 100
         done
97 101
     test -f "$MKIT_LOCAL/autoclean" && clean
@@ -103,13 +107,15 @@ uninstall() {
103 107
     # Uninstall product
104 108
     #
105 109
     local dst group src
106
-    ini values "lists:group" \
110
+    ini lskeys "files" \
111
+      | sort \
112
+      | uniq \
107 113
       | while read group;
108 114
         do
109
-            ini lskeys "files:$group" \
110
-              | while read src;
115
+            ini values "files:$group" \
116
+              | while read src dst;
111 117
                 do
112
-                    dst=$(get_dst "$group" "$src")
118
+                    dst=$(_get_dst "$group" "$src" "$dst")
113 119
                     _maybe rm -vrf "$dst"
114 120
                 done
115 121
         done

+ 175
- 0
utils/mkit/include/facts.sh Ver fichero

@@ -0,0 +1,175 @@
1
+#!/bin/bash
2
+
3
+. "$MKIT_DIR/include/ini.sh" || die "cannot import ini.sh"
4
+
5
+git_bool() {
6
+    #
7
+    # Get git bool (ie. exit status counts) $1
8
+    #
9
+    local bool_name="$1"
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
+
28
+git_fact() {
29
+    #
30
+    # Get git fact $1
31
+    #
32
+    local fact_name="$1"
33
+    git_present || warn "can't give fact outside git repo: $fact_name"
34
+    case "$fact_name" in
35
+        latest_tag)
36
+            git log --format="%d" \
37
+              | sed 's/,/\n/g' \
38
+              | sed 's/^[[:blank:]]*//' \
39
+              | grep -E '^\(?tag' \
40
+              | tr -cd '[[:digit:]].v\n' \
41
+              | grep . -m 1
42
+            ;;
43
+        latest_version)
44
+            git_fact latest_tag | git_tag2ver
45
+            ;;
46
+        current_branch)
47
+            git rev-parse --abbrev-ref HEAD
48
+            ;;
49
+        reldiff)
50
+            git log --oneline "$(git_fact latest_tag)..HEAD" --name-only
51
+            ;;
52
+        latest_sha)
53
+            git log -1 --pretty=format:%h HEAD
54
+            ;;
55
+        *)
56
+            warn "unknown git fact asked: $fact_name"
57
+            ;;
58
+    esac
59
+}
60
+
61
+git_present() {
62
+    #
63
+    # True if we're in a git repo
64
+    #
65
+    git rev-parse HEAD >&/dev/null
66
+}
67
+
68
+git_tag2ver() {
69
+    #
70
+    # Convert tag to version
71
+    #
72
+    sed s/^v//
73
+}
74
+
75
+git_ver2tag() {
76
+    #
77
+    # Convert version to tag
78
+    #
79
+    sed s/^/v/
80
+}
81
+
82
+git_lasthash() {
83
+    #
84
+    # Show last commit hash (with .dirty suffix if needed)
85
+    #
86
+    # If outside git repo, get it from .mkit/git_lasthash, which
87
+    # should have been put there by dist target.  (I.e., this won't
88
+    # work if you got outside the git repo in other way than dist
89
+    # target, but that's actually expected.)
90
+    #
91
+    if git_present;
92
+    then    # we are in git repo
93
+        local last_hash=$(git rev-parse HEAD)
94
+        echo -n "$last_hash"
95
+        git_bool dirty && echo -n ".dirty"
96
+    else    # we are outside (eg. distributor's build dir')
97
+        grep . .mkit/git_lasthash || {
98
+            echo UNKNOWN
99
+            warn "malformed source, could not determine git hash"
100
+        }
101
+    fi
102
+}
103
+
104
+semver() {
105
+    #
106
+    # Build semver version string with build metadata
107
+    #
108
+    # Build version string from available info using following
109
+    # logic:
110
+    #
111
+    #  1. use project.version (from mkit.ini)
112
+    #  2. if we are in git, override the version with last tag
113
+    #  3. if set, add project:prerl (from mkit.ini) as pre-release ID
114
+    #     (afer dash)
115
+    #  4. if we are at a later commit than the last tag, add branch
116
+    #     name and commit sha1 to build metadata (after plus sign)
117
+    #  5. if the tree is "dirty", i.e. has uncommited changes,
118
+    #     add "dirty" to build metadata
119
+    #
120
+    # The version is compatible with SemVer 2.0.0.
121
+    #
122
+    # Examples:
123
+    #
124
+    #     myprog v1.0.7                         # all clear
125
+    #     myprog v1.0.7-alpha                   # mkit.ini: project:prerl="alpha"
126
+    #     myprog v1.0.7-alpha+g1aef811.master   # ^^ + some commits after
127
+    #     myprog v1.0.7-alpha+gf14fc4f.api2     # ^^ + on a feature branch
128
+    #     myprog v1.0.7-alpha+gf14fc4f.api2.dirty  # ^^ + tree edited
129
+    #     myprog v1.0.7-alpha+dirty             # tag OK but tree edited
130
+    #     myprog v1.0.7+dirty                   # ^^ but no pre-release id
131
+    #
132
+    # Note that versions with "dirty" should be perceived as kind of
133
+    # dangerous outside developer's own machine.  Versions with sha1 are
134
+    # safer but must not be released.
135
+    #
136
+    # I have considered decorating the git commit refs to make them
137
+    # sort of sortable (e.g. "r1.g1aef811"), but on second thought,
138
+    # I don't think it's good idea to give *any* semantics to meta-data
139
+    # at all.  First, there is no rule that r1<r2<r3; a commit can be
140
+    # removing what other just added and one change can be split to
141
+    # multiple commits.  Also, the whole thing breaks anyway once you
142
+    # rebase your branch (no, it's not a sin).  The sole purpose of
143
+    # meta-data is to *identify* the code, and provide safe path back
144
+    # to tree; commit refs are already perfect for that.
145
+    #
146
+    # FIXME:  Using project:prerl for release IDs may not be compatible with
147
+    #         release strategy implemented in release.sh
148
+    #
149
+    local version=$(ini 1value project:version)
150
+    local prerl=$(ini 1value project:prerl)
151
+    grep ":" <<<"$prerl" && warn "colon in project:prerl may corrupt version data: $prerl"
152
+    if git_present;
153
+    then    # we are in git repo... so we can get smart
154
+        local latest_tag=$(git_fact latest_tag)
155
+        if ! git describe --tags --exact-match HEAD >&/dev/null;
156
+        then    # we are at a later commit than the last tag
157
+            local commit="$(git_fact current_branch).g$(git_fact latest_sha)"
158
+        fi
159
+        local dirty=""
160
+        local suffix=""
161
+        git_bool dirty; dirty=$?
162
+        test -n "$latest_tag" && version=${latest_tag:1}
163
+        case "$dirty:$commit" in
164
+            1:)  suffix=""               ;;
165
+            0:)  suffix="+dirty"         ;;
166
+            1:*) suffix="+$commit"       ;;
167
+            0:*) suffix="+$commit.dirty" ;;
168
+            *)   suffix=MKIT_BUG;
169
+                 warn "MKIT_BUG: bad dirt/commit detection" ;;
170
+        esac
171
+        test -n "$prerl" && suffix="-$prerl$suffix"
172
+        version="$version$suffix"
173
+    fi
174
+    echo "$version"
175
+}

+ 39
- 19
utils/mkit/include/ini.sh Ver fichero

@@ -1,24 +1,5 @@
1 1
 #!/bin/bash
2 2
 
3
-ini() {
4
-    #
5
-    # do ini operation
6
-    #
7
-    local op=$1
8
-    local arg=$2
9
-    local fn
10
-    local limit=_ini_cat
11
-    debug_var op arg
12
-    case $op in
13
-        lskeys) fn=_ini_lskeys   ;;
14
-        sec)    fn=_ini_grepsec  ;;
15
-        values) fn=_ini_greppath ;;
16
-        1value) fn=_ini_greppath; limit="tail -1" ;;
17
-        *)      die "incorrect use of \`ini()\`"
18
-    esac
19
-    <"$MKIT_INI" $fn "$arg" | $limit
20
-}
21
-
22 3
 _ini_cat() {
23 4
     #
24 5
     # A no-op for text stream
@@ -121,3 +102,42 @@ _ini_maybe_expand() {
121 102
         _ini_cat
122 103
     fi
123 104
 }
105
+
106
+ini() {
107
+    #
108
+    # do ini operation
109
+    #
110
+    local op=$1
111
+    local arg=$2
112
+    local fn
113
+    local limit=_ini_cat
114
+    case $op in
115
+        lskeys) fn=_ini_lskeys   ;;
116
+        sec)    fn=_ini_grepsec  ;;
117
+        values) fn=_ini_greppath ;;
118
+        1value) fn=_ini_greppath; limit="tail -1" ;;
119
+        *)      die "incorrect use of \`ini()\`"
120
+    esac
121
+    <"$MKIT_INI" $fn "$arg" | $limit
122
+}
123
+
124
+update_version() {
125
+    #
126
+    # Change project.version in mkit.ini at path $2 to version $1
127
+    #
128
+    local version="$1"
129
+    local inifile="$2"
130
+    local tmp=$(mktemp -t mkit.update_version.XXXXXXXX)
131
+    <"$inifile" perl -e '
132
+        my $hit = 0;
133
+        my $done = 0;
134
+        foreach (<STDIN>) {
135
+            if      ($done) { print; next; }
136
+            elsif   (m/\[project\]/) { $hit++; print; next; }
137
+            elsif   (m/\[/) { $hit = 0; print; next; }
138
+            elsif   ($hit) { s/\bversion\b( *)=( *).*/version$1=$2$ARGV[0]/ and $done++; print; }
139
+            else { print; next; }
140
+        }
141
+    ' "$version" >"$tmp" || die "failed to update version in mkit.ini"
142
+    mv "$tmp" "$inifile"
143
+}

+ 79
- 57
utils/mkit/include/mkit.sh Ver fichero

@@ -5,6 +5,26 @@
5 5
 . "$MKIT_DIR/include/release.sh" || die "cannot import release.sh"
6 6
 . "$MKIT_DIR/include/ini.sh"    || die "cannot import ini.sh"
7 7
 
8
+_valid_targets() {
9
+    #
10
+    # List valid routes
11
+    #
12
+    echo build
13
+    echo build_manpages
14
+    echo clean
15
+    echo debstuff
16
+    echo dist
17
+    echo install
18
+    echo release_x
19
+    echo release_y
20
+    echo release_z
21
+    echo rpmstuff
22
+    echo uninstall
23
+    echo vbump_x
24
+    echo vbump_y
25
+    echo vbump_z
26
+}
27
+
8 28
 debug() {
9 29
     #
10 30
     # Print debug message
@@ -30,23 +50,6 @@ debug_var() {
30 50
     done
31 51
 }
32 52
 
33
-MKIT_INI=${MKIT_INI:-mkit.ini}
34
-MKIT_INI_EXPAND=2
35
-MKIT_PROJ_NAME=$(ini 1value "project:name")
36
-MKIT_PROJ_PKGNAME=$(ini 1value "project:pkgname")
37
-MKIT_DEFAULT_MODE="644"
38
-
39
-mkit_init() {
40
-    #
41
-    # Do basic initialization
42
-    #
43
-    # Check for ini file and some variables
44
-    #
45
-    test -f "$MKIT_INI" || die "cannot find mkit.ini: $MKIT_INI"
46
-    test -n "$(tr -d '[:space:]' <<<"$MKIT_LOCAL")" \
47
-     || die "MKIT_LOCAL must be non-blank: '$MKIT_LOCAL'"
48
-}
49
-
50 53
 die() {
51 54
     #
52 55
     # Exit with message and non-zero exit status
@@ -55,39 +58,71 @@ die() {
55 58
     exit 4
56 59
 }
57 60
 
58
-warn() {
61
+_compver() {
62
+    #
63
+    # True if version $1 matches our version
64
+    #
65
+    # If our x is 0, check first two fragments, otherwise check just
66
+    # the x.  Fragments must equal.
67
+    #
68
+    local their_ver our_x our_y their_x their_y
69
+    their_ver="$1"
70
+    their_x=${their_ver%%.*}
71
+    their_y=${their_ver##$their_x.}
72
+    their_y=${their_y%%.*}
73
+    our_x=${MKIT_VERSION%%.*}
74
+    our_y=${MKIT_VERSION##$our_x.}
75
+    our_y=${our_y%%.*}
76
+    debug_var MKIT_VERSION our_x our_y their_ver their_x their_y
77
+    test "$their_x" -eq "$our_x" || return 1
78
+    test "$our_x" -eq 0 && {
79
+        test "$their_y" = "$our_y"
80
+        return $?
81
+    }
82
+    return 0
83
+}
84
+
85
+_chkiniversion() {
59 86
     #
60
-    # Print warning message
87
+    # Check if ini version is supported
61 88
     #
62
-    echo "$@" >&2
89
+    # Look for "#mkit version=0.0.0" or similar in first or last
90
+    # 3 lines of the file; then check if the version is supported.
91
+    #
92
+    local ver_line
93
+    local their_ver
94
+    ver_line=$(
95
+        {
96
+            head -3 "$MKIT_INI"
97
+            tac "$MKIT_INI" | tail -3
98
+        } | grep -m 1 -E '^# *mkit +version *= *v?[0-9]+\.[0-9]+\.[0-9]+'
99
+    )
100
+    test -n "$ver_line" \
101
+     || die "version mark ('#mkit version=x.y.z') not found in: $MKIT_INI"
102
+    their_ver="$(tr -d '[:blank:]v' <<<"${ver_line##*=}")"
103
+    _compver "$their_ver" \
104
+     || die "bad mkit.ini version: $their_ver does not match $MKIT_VERSION"
63 105
 }
64 106
 
65
-update_version() {
66
-    #
67
-    # Change project.version in mkit.ini at path $2 to version $1
68
-    #
69
-    local version="$1"
70
-    local inifile="$2"
71
-    local tmp=$(mktemp -t mkit.update_version.XXXXXXXX)
72
-    <"$inifile" perl -e '
73
-        my $hit = 0;
74
-        my $done = 0;
75
-        foreach (<STDIN>) {
76
-            if      ($done) { print; next; }
77
-            elsif   (m/\[project\]/) { $hit++; print; next; }
78
-            elsif   (m/\[/) { $hit = 0; print; next; }
79
-            elsif   ($hit) { s/\bversion\b *=.*/version = $ARGV[0]/ and $done++; print; }
80
-            else { print; next; }
81
-        }
82
-    ' "$version" >"$tmp" || die "failed to update version in mkit.ini"
83
-    mv "$tmp" "$inifile"
107
+mkit_init() {
108
+    #
109
+    # Do basic initialization
110
+    #
111
+    # Check for ini file and some variables
112
+    #
113
+    $MKIT_DRY && MKIT_DEBUG=true
114
+    MKIT_PROJ_PKGNAME=$(ini 1value "project:pkgname")
115
+    test -f "$MKIT_INI" || die "cannot find mkit.ini: $MKIT_INI"
116
+    _chkiniversion
117
+    test -n "$(tr -d '[:space:]' <<<"$MKIT_LOCAL")" \
118
+     || die "MKIT_LOCAL must be non-blank: '$MKIT_LOCAL'"
84 119
 }
85 120
 
86 121
 route() {
87 122
     #
88 123
     # Call correct function based on $1
89 124
     #
90
-    if valid_targets | grep -qwx "^$1";
125
+    if _valid_targets | grep -qwx "^$1";
91 126
     then
92 127
         "$1"
93 128
     else
@@ -95,27 +130,14 @@ route() {
95 130
             echo "usage: $(basename "$0") TARGET"
96 131
             echo
97 132
             echo "valid targets:"
98
-            valid_targets | sed 's/^/    /'
133
+            _valid_targets | sed 's/^/    /'
99 134
         } >&2
100 135
     fi
101 136
 }
102 137
 
103
-valid_targets() {
138
+warn() {
104 139
     #
105
-    # List valid routes
140
+    # Print warning message
106 141
     #
107
-    echo build
108
-    echo build_manpages
109
-    echo clean
110
-    echo debstuff
111
-    echo dist
112
-    echo install
113
-    echo release_x
114
-    echo release_y
115
-    echo release_z
116
-    echo rpmstuff
117
-    echo uninstall
118
-    echo vbump_x
119
-    echo vbump_y
120
-    echo vbump_z
142
+    echo "$@" >&2
121 143
 }

+ 95
- 103
utils/mkit/include/release.sh Ver fichero

@@ -1,172 +1,164 @@
1 1
 #!/bin/bash
2 2
 
3
-__die_if() {
3
+. "$MKIT_DIR/include/ini.sh"   || die "cannot import ini.sh"
4
+. "$MKIT_DIR/include/facts.sh" || die "cannot import facts.sh"
5
+
6
+_bump_version() {
7
+    #
8
+    # Bump version on stdin by level $1 (x, y or z)
9
+    #
10
+    local rlevel=$1
11
+    local old
12
+    read -r old
13
+    local oldx=${old%.*.*}
14
+    local oldz=${old#*.*.}
15
+    local tmpy=${old%.*}
16
+    local oldy=${tmpy#*.}
17
+    local new=""
18
+    case $rlevel in
19
+        x) new="$((oldx+1)).0.0"            ;;
20
+        y) new="$oldx.$((oldy+1)).0"        ;;
21
+        z) new="$oldx.$oldy.$((oldz+1))"    ;;
22
+        *) die "invalid release level: $1"  ;;
23
+    esac
24
+    echo "$new"
25
+}
26
+
27
+_relck() {
4 28
     #
5 29
     # Die if blocking condition $1 is detected
6 30
     #
7 31
     local condition="$1"
8 32
     local x
9 33
     case "$condition" in
10
-        nogit)
34
+        git_present)
11 35
             git rev-parse HEAD >&/dev/null\
12 36
              || die "cannot do this outside git repo"
13 37
             ;;
14
-        norelbr)
38
+        at_relsrc)
15 39
             local relsrc=$(ini 1value project:relsrc)
16
-            __git_info curbranch \
40
+            git_fact current_branch \
17 41
               | grep -qFx "$relsrc" \
18 42
              || die "you are not on release source branch: $relsrc"
19 43
             ;;
20
-        dirty)
44
+        not_dirty)
21 45
             git diff --shortstat 2>/dev/null \
22 46
               | grep -q . \
23 47
              && die "tree is dirty: $dirt"
24 48
             ;;
25
-        novertag)
26
-            __git_info lasttag \
49
+        tags_ok)
50
+            git_fact latest_tag \
27 51
               | grep -q . \
28
-             || die "cannot find last tag"
52
+             || die "cannot find latest tag"
29 53
             ;;
30
-        nobump)
54
+        vbump_hot)
31 55
             git diff-tree --no-commit-id --name-only -r HEAD \
32 56
               | grep -qFx mkit.ini \
33 57
              || die "last change must be version bump in mkit.ini"
34 58
             ;;
35
-        wip)
36
-            __git_info reldiff \
59
+        no_wip)
60
+            git_fact reldiff \
37 61
               | grep '^....... WIP ' \
38
-             && die "WIP commit since $(__git_info lasttag)"
62
+             && die "WIP commit since $(git_fact latest_tag)"
39 63
             ;;
40
-        old_c)
41
-            x=$(__ver_info nextver_g)
42
-            __ver_info currver_c \
43
-              | grep -qFx "$x" \
44
-             || die "new version not in mkit.ini: $x"
64
+        ini_version)
65
+            local oracle=$(git_fact latest_version | _bump_version "$rlevel")
66
+            ini 1value project:version  \
67
+              | grep -qFx "$oracle" \
68
+             || die "new version not in mkit.ini: $oracle"
69
+            ;;
70
+        *)
71
+            die "unknown release check: $condition"
45 72
             ;;
46 73
     esac
47 74
 }
48 75
 
49
-__git_info() {
50
-    #
51
-    # Get git info $1
52
-    #
53
-    local info="$1"
54
-    case "$info" in
55
-        lasttag)    git tag | grep ^v | sort -V | tail -n1  ;;
56
-        curbranch)  git rev-parse --abbrev-ref HEAD         ;;
57
-        reldiff)    git log --oneline "$(__git_info lasttag)..HEAD" --name-only ;;
58
-    esac
59
-}
60
-
61
-__ver_info() {
62
-    #
63
-    # Get git info $1
64
-    #
65
-    local info="$1"
66
-    case "$info" in
67
-        lastver_g)  __git_info lasttag | sed s/^v// ;;
68
-        nextver_g)  __make_ver "$level" "$(__ver_info lastver_g)" ;;
69
-        currver_c)  ini 1value project:version ;;
70
-        nextver_c)  __make_ver "$level" "$(__ver_info currver_c)" ;;
71
-    esac
72
-}
73
-
74
-__make_ver() {
75
-    local level=$1
76
-    local old=$2
77
-    local oldx=${old%.*.*}
78
-    local oldz=${old#*.*.}
79
-    local tmpy=${old%.*}
80
-    local oldy=${tmpy#*.}
81
-    case $level in
82
-        x) new="$((oldx+1)).0.0"            ;;
83
-        y) new="$oldx.$((oldy+1)).0"        ;;
84
-        z) new="$oldx.$oldy.$((oldz+1))"    ;;
85
-        *) die "invalid release level: $1"  ;;
86
-    esac
87
-    echo "$new"
88
-}
89
-
90
-__release() {
76
+_release() {
91 77
     #
92 78
     # Prepare release
93 79
     #
94 80
     # Span release routines: make a signed tag, check branch
95 81
     # and update release branch
96 82
     #
97
-    # FIXME: Using project:prerl as build.sh:get_version() does may not be
83
+    # FIXME: Using project:prerl as build.sh:semver() does may not be
98 84
     #        compatible with this release strategy
99 85
     #
100
-    local level=$1
86
+    local rlevel=$1
101 87
     local newtag
88
+    local reldst
102 89
 
103
-    __die_if nogit
104
-    __die_if norelbr
105
-    __die_if dirty
106
-    __die_if novertag
107
-    __die_if nobump
108
-    __die_if wip
109
-    __die_if old_c
90
+    _relck git_present
91
+    _relck at_relsrc
92
+    _relck not_dirty
93
+    _relck tags_ok
94
+    _relck vbump_hot
95
+    _relck no_wip
96
+    _relck ini_version
110 97
 
111
-    newtag=v$(__ver_info nextver_g)
98
+    newtag=$(git_fact latest_version | _bump_version "$rlevel" | git_ver2tag )
112 99
     set -e
113 100
     debug_var newtag
114 101
     $MKIT_DRY && return
115
-    git tag -m "$MKIT_PROJ_NAME $newtag - $CODENAME" "$newtag"
116
-    git branch -f "$(ini 1value project:reldst)" "$newtag"
117
-}
102
+    git tag -m "$(ini 1value project:name) $newtag - $CODENAME" "$newtag"
118 103
 
119
-__git_msg_vbump() {
120
-    echo "Bump version"
121
-    echo ""
122
-    echo "Overview of changes:"
123
-    echo ""
124
-    __git_info reldiff \
125
-      | sed '
126
-            s/^[a-f0-9]\{7\} / *  &/; t PATHS
127
-            s/^/        /
128
-            :PATHS
129
-        '
104
+    reldst=$(ini 1value project:reldst)
105
+    debug_var reldst
106
+    if test -n "$reldst";
107
+    then
108
+        git branch -f "$reldst" "$newtag"
109
+    fi
130 110
 }
131 111
 
132
-__vbump() {
133
-    local level="$1"
112
+_vbump() {
113
+    local rlevel="$1"
134 114
     local lastver   # current from mkit.ini
135 115
     local nextver   # after the bump
136
-    __die_if nogit
137
-    __die_if norelbr
138
-    __die_if dirty
139
-    lastver=$(__ver_info currver_c)
140
-    nextver=$(__ver_info nextver_c)
116
+    _relck git_present
117
+    _relck at_relsrc
118
+    _relck not_dirty
119
+    nextver=$(ini 1value project:version | _bump_version "$rlevel")
141 120
     debug_var lastver nextver
142 121
     $MKIT_DRY && return
143 122
     update_version "$nextver" mkit.ini \
144 123
       || die "failed to update version in mkit.ini"
145 124
     git add mkit.ini \
146 125
       || die "failed to add mkit.ini to the index"
147
-    git commit -e -m "$(__git_msg_vbump)"
126
+    git commit -e -m "$(_vbump_gitmsg)"
148 127
 }
149 128
 
150
-vbump_x() {
151
-    __vbump x
129
+_vbump_gitmsg() {
130
+    echo "Bump version"
131
+    echo ""
132
+    echo "Overview of changes:"
133
+    echo ""
134
+    git_fact reldiff \
135
+      | sed '
136
+            s/^[a-f0-9]\{7\} / *  &/; t PATHS
137
+            s/^/        /
138
+            :PATHS
139
+        '
152 140
 }
153 141
 
154
-vbump_y() {
155
-    __vbump y
142
+release_x() {
143
+    _release x
156 144
 }
157 145
 
158
-vbump_z() {
159
-    __vbump z
146
+release_y() {
147
+    _release y
160 148
 }
161 149
 
162
-release_x() {
163
-    __release x
150
+release_z() {
151
+    _release z
164 152
 }
165 153
 
166
-release_y() {
167
-    __release y
154
+vbump_x() {
155
+    _vbump x
168 156
 }
169 157
 
170
-release_z() {
171
-    __release z
158
+vbump_y() {
159
+    _vbump y
160
+}
161
+
162
+vbump_z() {
163
+    _vbump z
172 164
 }

+ 56
- 5
utils/mkit/make Ver fichero

@@ -6,12 +6,63 @@ die() {
6 6
     echo "$@" && exit 9
7 7
 }
8 8
 
9
-export MKIT_VERSION=0.0.11+devel.gda0869d
10 9
 
11
-export MKIT_DIR=${MKIT_DIR:-$(dirname "$0")}
12
-export MKIT_LOCAL=${MKIT_LOCAL:-.mkit}
13
-export MKIT_DRY=${MKIT_DRY:-false}
14
-export MKIT_DEBUG=${MKIT_DEBUG:-false}
10
+#
11
+# Debug mode (true|false)
12
+#
13
+MKIT_DEBUG=${MKIT_DEBUG:-false}
14
+
15
+#
16
+# Default deploy mode for files
17
+#
18
+MKIT_DEFAULT_MODE="644"
19
+
20
+#
21
+# Path to MKit dir (where 'include' is)
22
+#
23
+MKIT_DIR=${MKIT_DIR:-$(dirname "$0")}
24
+
25
+#
26
+# Dry mode (true|false)
27
+#
28
+# Set to true to not install anything. Implies MKIT_DEBUG.
29
+#
30
+MKIT_DRY=${MKIT_DRY:-false}
31
+
32
+#
33
+# Path to mkit.ini
34
+#
35
+MKIT_INI=${MKIT_INI:-mkit.ini}
36
+
37
+#
38
+# Limit ini expansion depth
39
+#
40
+# To avoid endless loops, this value is subtracted each
41
+# time ini() expands a reference; when zero is reached,
42
+# no more expansions happen.
43
+#
44
+MKIT_INI_EXPAND=2
45
+
46
+#
47
+# Path to MKit local config and temp
48
+#
49
+# Typically hidden in project root, here MKit can
50
+# save its temporary lists.
51
+#
52
+MKIT_LOCAL=${MKIT_LOCAL:-.mkit}
53
+
54
+#
55
+# Package name
56
+#
57
+# Used as base for tarball and in some default tokens.
58
+#
59
+MKIT_PROJ_PKGNAME=""
60
+
61
+#
62
+# This MKit version
63
+#
64
+MKIT_VERSION=0.0.13+devel.gec1f180
65
+
15 66
 
16 67
 . "$MKIT_DIR/include/mkit.sh" || die "failed to init; check if MKIT_DIR is set properly: $MKIT_DIR"
17 68