a mirabilos-support support script
[shellsnippets/shellsnippets.git] / mksh / mvnrepo.sh
1 #!/usr/bin/env mksh
2 # -*- mode: sh -*-
3 #-
4 # Copyright © 2018
5 #       mirabilos <t.glaser@tarent.de>
6 #
7 # Provided that these terms and disclaimer and all copyright notices
8 # are retained or reproduced in an accompanying document, permission
9 # is granted to deal in this work without restriction, including un‐
10 # limited rights to use, publicly perform, distribute, sell, modify,
11 # merge, give away, or sublicence.
12 #
13 # This work is provided “AS IS” and WITHOUT WARRANTY of any kind, to
14 # the utmost extent permitted by applicable law, neither express nor
15 # implied; without malicious intent or gross negligence. In no event
16 # may a licensor, author or contributor be held liable for indirect,
17 # direct, other damage, loss, or other issues arising in any way out
18 # of dealing in the work, even if advised of the possibility of such
19 # damage or existence of a defect, except proven that it results out
20 # of said person’s immediate fault when using the work as intended.
21 #-
22 # Create mvnrepository.com URLs for all dependencies, extensions and
23 # Maven plugins, sorted and categorised, for up-to-date checks.
24
25 LC_ALL=C; export LC_ALL
26 unset LANGUAGE
27
28 set -e
29 set -o pipefail
30 me=$(realpath "$0/..")
31 . "$me/assockit.ksh"
32 . "$me/progress-bar"
33
34 die() {
35         print -ru2 -- "E: $*"
36         exit 1
37 }
38
39 set -A grouping 'Parent' 'Project' 'Dependencies' 'Extensions' 'Plugins' 'Plugin Deps'
40
41 function xml2path {
42         # thankfully only HT, CR, LF are, out of all C0 controls, valid in XML
43         xmlstarlet tr "$me/mvnrepo.xsl" "$1" | { tr '\n' '\ 1'; print; } | \
44             sed -e 's!\ 1$!!' -e "s!'\ 1//!'\ 2//!g" -e "s!'\\\\''\ 2!'\\\\''\ 1!g" | \
45             tr '\ 2' '\n' | \
46             grep -E "^[^']*/(groupId|artifactId|version)='" >target/pom.xp
47 }
48
49 function extract {
50         local line value base path p t x bron=$1 lines=$2
51
52         # thankfully neither ' nor = are valid in XML names
53         set +e
54         while IFS= read -r line; do
55                 draw_progress_bar
56                 if [[ $line = *'\ 1'* ]]; then
57                         print -ru2 -- "W: Embedded newline in ${line@Q}"
58                         continue
59                 fi
60                 value=${line#*=}
61                 eval "value=$value" # trust our XSLT escaping code
62                 (( $? )) && die "Error reading value from line ${line@Q}"
63                 line=${line%%=*}
64                 base=${line##*/}
65                 line=${line%/*}
66                 asso_sets "$value" "$bron" "$line" "$base"
67         done <target/pom.xp
68         asso_loadk "$bron"
69         for path in "${asso_y[@]}"; do
70                 draw_progress_bar
71                 p=${path//'['+([0-9])']'}
72                 if [[ $p = //project/parent ]]; then
73                         t=0
74                 elif [[ $p = //project ]]; then
75                         t=1
76                 elif [[ $p = */extension ]]; then
77                         t=3
78                 elif [[ $p = */plugin/dependencies/dependency ]]; then
79                         t=5
80                 elif [[ $p = */plugin ]]; then
81                         t=4
82                 elif [[ $p = */dependencies/dependency ]]; then
83                         t=2
84                 elif [[ $p = */@(configuration|exclusions)/* ]]; then
85                         # skip well-known others silently
86                         continue
87                 else
88                         print -ru2 -- "W: Unknown XPath: $path"
89                         continue
90                 fi
91                 x=$(asso_getv "$bron" "$path" groupId)
92                 [[ -n $x ]] || case $t {
93                 (1)     x=$(asso_getv "$bron" //project/parent groupId)
94                         [[ -n $x ]] || die "No groupId for project or parent"
95                         ;;
96                 (4)     x=org.apache.maven.plugins
97                         #print -ru2 -- "W: missing groupId for $path"
98                         ;;
99                 (*)     die "missing groupId for $path"
100                         ;;
101                 }
102                 [[ $x = */* ]] && die "wtf, groupId ${x@Q} for $path contains a slash"
103                 t+=/$x
104                 x=$(asso_getv "$bron" "$path" artifactId)
105                 if [[ -n $x ]]; then
106                         t+=/$x
107                         [[ $x = */* ]] && die "wtf, artifactId ${x@Q} for $path contains a slash"
108                         x=$(asso_getv "$bron" "$path" version)
109                         [[ $x = *'${'* || $x = *[\\/:\"\<\>\|?*]* ]] && x=
110                 fi
111                 [[ -n $x ]] && asso_sets "$x" versions "$t"
112                 asso_setnull $lines "$t"
113         done
114         set -e
115 }
116
117 function output {
118         local lineno=-1 nlines line vsn lines=$1
119         local last=-1 typ
120
121         set +e
122         asso_loadk $lines
123         nlines=${#asso_y[*]}
124         (( nlines )) || print -r -- "(none)"
125         while (( ++lineno < nlines )); do
126                 draw_progress_bar
127                 line=${asso_y[lineno]}
128                 vsn=$(asso_getv versions "$line")
129                 [[ -n $vsn ]] && line+=/$vsn
130                 typ=${line::1}
131                 line=${line:2}
132                 if (( typ < 2 )); then
133                         print -nr -- "${grouping[typ]}: "
134                 elif (( typ != last )); then
135                         print
136                         print -r -- "${grouping[typ]}:"
137                 fi
138                 (( last = typ ))
139                 print -r -- "https://mvnrepository.com/artifact/$line"
140         done
141         set -e
142 }
143
144 function drop {
145         local lineno=-1 nlines line vsn lines=$1 from=$2
146
147         set +e
148         asso_loadk $lines
149         nlines=${#asso_y[*]}
150         while (( ++lineno < nlines )); do
151                 draw_progress_bar
152                 asso_unset $from "${asso_y[lineno]}"
153         done
154         set -e
155 }
156
157 mkdir -p target
158 rm -f target/effective-pom.xml
159 mvn -B -N help:effective-pom -Doutput=target/effective-pom.xml >&2 &
160 xml2path pom.xml
161
162 Lxp=$(wc -l <target/pom.xp)
163 # first estimate
164 Lxe=$((Lxp * 3 / 2))
165 Lop=$((Lxp / 3))
166 Loe=300 # outrageous, I know, but it makes things smoother
167 set +e
168 init_progress_bar $((2*Lxp + 2 + 2*Lxe + 1 + Lop + 1 + Lop + Loe))
169 set -e
170
171 LN=$_cur_progress_bar
172 extract p plines
173 Lxpr=$((_cur_progress_bar - LN))
174
175 while [[ -n $(jobs) ]]; do wait; done
176 set +e
177 draw_progress_bar
178 set -e
179
180 xml2path target/effective-pom.xml
181
182 Lxe=$(wc -l <target/pom.xp)
183 # re-estimate
184 Loe=$(( (Lxe-Lxp) / 3 ))
185 set +e
186 asso_loadk plines
187 Lop=${#asso_y[*]}
188 _cnt_progress_bar=$((Lxpr + 2 + 2*Lxe + 1 + Lop + 1 + Lop + Loe))
189 draw_progress_bar
190 set -e
191
192 LN=$_cur_progress_bar
193 extract e elines
194 Lxer=$((_cur_progress_bar - LN))
195 rm -f target/effective-pom.xml target/pom.xp
196
197 # recalculate
198 set +e
199 asso_loadk elines
200 Loe=${#asso_y[*]}
201 _cnt_progress_bar=$((Lxpr + 2 + Lxer + 1 + Lop + 1 + Lop + Loe))
202 draw_progress_bar
203 set -e
204
205 drop plines elines
206
207 set +e
208 asso_loadk elines
209 Loe=${#asso_y[*]}
210 _cnt_progress_bar=$((Lxpr + 2 + Lxer + 1 + Lop + 1 + Lop + Loe))
211 draw_progress_bar
212 set -e
213
214 output plines
215 print
216 print Effective POM extras:
217 output elines
218 set +e
219 done_progress_bar