add a few scripts from org.evolvis.tartools:maven-parent
[shellsnippets/shellsnippets.git] / mksh / sortdeps.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 # Pipe a Maven POM <dependencies> or <exclusions> element’s content,
23 # without the surrounding grouping element, into this to sort them.
24
25 LC_ALL=C; export LC_ALL
26 unset LANGUAGE
27
28 set -e
29 cr=$'\r'
30 lf=$'\n'
31 (( ${#cr} == 1 ))
32 set -o pipefail
33
34 # offsets in element array
35 OTYPE=0
36 OgroupId=1
37 OartifactId=2
38 Oversion=5
39 Otype=4
40 Oclassifier=3
41 Oscope=6
42 OsystemPath=8
43 Oexclusions=9
44 Ooptional=7
45 OPRECOMMENT=10
46 OINCOMMENT=11
47
48 exec 4<&0
49 (
50         print '<toplevel>'
51         tr "$cr" "$lf" <&4
52         print '</toplevel>'
53 ) | xmlstarlet fo -e UTF-8 -n - |&
54
55 die() {
56         print -ru2 -- "E: $*"
57         print -ru2 -- "N: line: ${line@Q}"
58         exit 1
59 }
60
61 set -A sortlines
62 IFS= read -pr line
63 [[ $line = '<?xml version="1.0" encoding="UTF-8"?>' ]] || \
64     die unexpected first line not XML declaration
65 IFS= read -pr line
66 [[ $line = '<toplevel>' ]] || die unexpected second line not start tag
67
68 set -A el
69 state=0
70 while IFS= read -pr line; do
71         case $state:$line {
72         (0:'<!--'*'-->')
73                 el[OPRECOMMENT]+=$line ;;
74         (1:'<!--'*'-->')
75                 el[OINCOMMENT]+=$line ;;
76         (0:'<!--'*)
77                 el[OPRECOMMENT]+=$line
78                 while IFS= read -pr line; do
79                         el[OPRECOMMENT]+=\ ${line##*([   ])}
80                         [[ $line = *'-->' ]] && break
81                 done
82                 [[ $line = *'-->' ]] || die unclosed comment ;;
83         (1:'<!--'*)
84                 el[OINCOMMENT]+=$line
85                 while IFS= read -pr line; do
86                         el[OINCOMMENT]+=\ ${line##*([    ])}
87                         [[ $line = *'-->' ]] && break
88                 done
89                 [[ $line = *'-->' ]] || die unclosed comment ;;
90         (0:'</toplevel>')
91                 state=9 ;;
92         (0:'<dependency>')
93                 el[OTYPE]=0
94                 state=1 ;;
95         (0:'<exclusion>')
96                 el[OTYPE]=1
97                 state=1 ;;
98         (1:'</dependency>'|1:'</exclusion>')
99                 sortlines+=("${el[0]}$cr${el[1]}$cr${el[2]}$cr${el[3]}$cr${el[4]}$cr${el[5]}$cr${el[6]}$cr${el[7]}$cr${el[8]}$cr${el[9]}$cr${el[10]}$cr${el[11]}")
100                 set -A el
101                 state=0 ;;
102         (1:'<'@(groupId|artifactId|version|type|classifier|scope|systemPath|exclusions|optional)'/>')
103                 ;;
104         (1:'<groupId>'*'</groupId>')
105                 x=${line#'<groupId>'}
106                 el[OgroupId]=${x%'</groupId>'} ;;
107         (1:'<artifactId>'*'</artifactId>')
108                 x=${line#'<artifactId>'}
109                 el[OartifactId]=${x%'</artifactId>'} ;;
110         (1:'<version>'*'</version>')
111                 x=${line#'<version>'}
112                 el[Oversion]=${x%'</version>'} ;;
113         (1:'<type>'*'</type>')
114                 x=${line#'<type>'}
115                 el[Otype]=${x%'</type>'} ;;
116         (1:'<classifier>'*'</classifier>')
117                 x=${line#'<classifier>'}
118                 el[Oclassifier]=${x%'</classifier>'} ;;
119         (1:'<scope>'*'</scope>')
120                 x=${line#'<scope>'}
121                 el[Oscope]=${x%'</scope>'} ;;
122         (1:'<systemPath>'*'</systemPath>')
123                 x=${line#'<systemPath>'}
124                 el[OsystemPath]=${x%'</systemPath>'} ;;
125         (1:'<optional>'*'</optional>')
126                 x=${line#'<optional>'}
127                 el[Ooptional]=${x%'</optional>'} ;;
128         (1:'<exclusions>')
129                 x=
130                 while IFS= read -pr line; do
131                         [[ $line = '</exclusions>' ]] && break
132                         x+=$line
133                 done
134                 [[ $line = '</exclusions>' ]] || die unterminated exclusions
135                 line=$x
136                 x=$(mksh "$0" <<<"$line") || die could not sort sub-exclusions
137                 el[Oexclusions]=${x//"$lf"} ;;
138         (*)
139                 die illegal line in state $state ;;
140         }
141 done
142 (( state == 9 )) || die unexpected last line not end tag
143
144 for x in "${sortlines[@]}"; do
145         print -r -- "$x"
146 done | sort -u |&
147
148 set -A beg -- '<dependency>' '<exclusion>'
149 set -A end -- '</dependency>' '</exclusion>'
150 while IFS="$cr" read -prA el; do
151         [[ -n ${el[OPRECOMMENT]} ]] && print -r -- "${el[OPRECOMMENT]}"
152         print -r -- "${beg[el[OTYPE]]}"
153         [[ -n ${el[OINCOMMENT]} ]] && print -r -- "${el[OINCOMMENT]}"
154         [[ -n ${el[OgroupId]} ]] && print -r -- "<groupId>${el[OgroupId]}</groupId>"
155         [[ -n ${el[OartifactId]} ]] && print -r -- "<artifactId>${el[OartifactId]}</artifactId>"
156         [[ -n ${el[Oversion]} ]] && print -r -- "<version>${el[Oversion]}</version>"
157         [[ -n ${el[Otype]} ]] && print -r -- "<type>${el[Otype]}</type>"
158         [[ -n ${el[Oclassifier]} ]] && print -r -- "<classifier>${el[Oclassifier]}</classifier>"
159         [[ -n ${el[Oscope]} ]] && print -r -- "<scope>${el[Oscope]}</scope>"
160         [[ -n ${el[OsystemPath]} ]] && print -r -- "<systemPath>${el[OsystemPath]}</systemPath>"
161         [[ -n ${el[Oexclusions]} ]] && print -r -- "<exclusions>${el[Oexclusions]}</exclusions>"
162         [[ -n ${el[Ooptional]} ]] && print -r -- "<optional>${el[Ooptional]}</optional>"
163         print -r -- "${end[el[OTYPE]]}"
164 done
165
166 exit 0