blob: 3bad358dba0acb00253ff51e27983e5e9d6d844d [file] [log] [blame]
Bob Badour7a958202021-01-07 03:34:31 +00001#!/bin/sh
2
3set -u
4
5ME=$(basename $0)
6
7USAGE="Usage: ${ME} {options}
8
9Builds a license metadata specification and outputs it to stdout or {outfile}.
10
11The available options are:
12
13-k kind... license kinds
14-c condition... license conditions
15-p package... license package name
16-n notice... license notice file
17-d dependency... license metadata file dependency
18-t target... targets
19-m target:installed... map dependent targets to their installed names
20-is_container preserved dependent target name when given
21-o outfile output file
22"
23
24# Global flag variables
25license_kinds=
26license_conditions=
27license_package_name=
28license_notice=
29license_deps=
30targets=
31installmap=
32is_container=false
33ofile=
34
35# Global variables
36depfiles=" "
37effective_conditions=
38
39
40# Exits with a message.
41#
42# When the exit status is 2, assumes a usage error and outputs the usage message
43# to stderr before outputting the specific error message to stderr.
44#
45# Parameters:
46# Optional numeric exit status (defaults to 2, i.e. a usage error.)
47# Remaining args treated as an error message sent to stderr.
48die() {
49 lstatus=2
50 case "${1:-}" in *[^0-9]*) ;; *) lstatus="$1"; shift ;; esac
51 case "${lstatus}" in 2) echo "${USAGE}" >&2; echo >&2 ;; esac
52 if [ -n "$*" ]; then
53 echo -e "$*\n" >&2
54 fi
55 exit $lstatus
56}
57
58
59# Sets the flag variables based on the command-line.
60#
61# invoke with: process_args "$@"
62process_args() {
63 lcurr_flag=
64 while [ "$#" -gt '0' ]; do
65 case "${1}" in
66 -h)
67 echo "${USAGE}"
68 exit 0
69 ;;
70 -k)
71 lcurr_flag=kind
72 ;;
73 -c)
74 lcurr_flag=condition
75 ;;
76 -p)
77 lcurr_flag=package
78 ;;
79 -n)
80 lcurr_flag=notice
81 ;;
82 -d)
83 lcurr_flag=dependency
84 ;;
85 -t)
86 lcurr_flag=target
87 ;;
88 -m)
89 lcurr_flag=installmap
90 ;;
91 -o)
92 lcurr_flag=ofile
93 ;;
94 -is_container)
95 lcurr_flag=
96 is_container=true
97 ;;
98 -*)
99 die "Unknown flag: \"${1}\""
100 ;;
101 *)
102 case "${lcurr_flag}" in
103 kind)
104 license_kinds="${license_kinds}${license_kinds:+ }${1}"
105 ;;
106 condition)
107 license_conditions="${license_conditions}${license_conditions:+ }${1}"
108 ;;
109 package)
110 license_package_name="${license_package_name}${license_package_name:+ }${1}"
111 ;;
112 notice)
113 license_notice="${license_notice}${license_notice:+ }${1}"
114 ;;
115 dependency)
116 license_deps="${license_deps}${license_deps:+ }${1}"
117 ;;
118 target)
119 targets="${targets}${targets:+ }${1}"
120 ;;
121 installmap)
122 installmap="${installmap}${installmap:+ }${1}"
123 ;;
124 ofile)
125 if [ -n "${ofile}" ]; then
126 die "Output file -o appears twice as \"${ofile}\" and \"${1}\""
127 fi
128 ofile="${1}"
129 ;;
130 *)
131 die "Must precede argument \"${1}\" with type flag."
132 ;;
133 esac
134 ;;
135 esac
136 shift
137 done
138}
139
140# Reads a license metadata file from stdin, and outputs the named dependencies.
141#
142# No parameters.
143extract_deps() {
144 awk '$1 == "dep_name:" { sub(/^"/, "", $2); sub(/"$/, "", $2); print $2; }'
145}
146
147# Populates the depfiles variable identifying dependency files.
148#
149# Starting with the dependencies enumerated in license_deps, calculates the
150# transitive closure of all dependencies.
151#
152# Dependency names ending in .meta_module indirectly reference license
153# metadata with 1 license metadata filename per line.
154#
155# No parameters; no output.
156read_deps() {
157 lnewdeps=
158 for d in ${license_deps}; do
159 case "${d}" in
160 *.meta_module)
161 lnewdeps="${lnewdeps}${lnewdeps:+ }"$(cat "${d}") ;;
162 *)
163 lnewdeps="${lnewdeps}${lnewdeps:+ }${d}" ;;
164 esac
165 done
166 lnewdeps=$(echo "${lnewdeps}" | tr ' ' '\n' | sort -u)
167 lalldeps=
168 ldeps=
169 lmod=
170 ldep=
171 while [ "${#lnewdeps}" -gt '0' ]; do
172 ldeps="${lnewdeps}"
173 lnewdeps=
174 for ldep in ${ldeps}; do
175 depfiles="${depfiles}${ldep} "
176 lalldeps="${lalldeps}${lalldeps:+ }"$(cat "${ldep}" | extract_deps)
177 done
178 lalldeps=$(for d in ${lalldeps}; do echo "${d}"; done | sort -u)
179 for d in ${lalldeps}; do
180 ldeps="${d}"
181 case "${d}" in *.meta_module) ldeps=$(cat "${d}") ;; esac
182 for lmod in ${ldeps}; do
183 if ! expr "${depfiles}" : ".* ${lmod} .*" >/dev/null 2>&1; then
184 lnewdeps="${lnewdeps}${lnewdeps:+ }${lmod}"
185 fi
186 done
187 done
188 lalldeps=
189 done
190}
191
192# Returns the effective license conditions for the current license metadata.
193#
194# If a module is restricted or links in a restricted module, the effective
195# license has a restricted condition.
196calculate_effective_conditions() {
197 lconditions="${license_conditions}"
198 case "${license_conditions}" in
199 *restricted*) : do nothing ;;
200 *)
201 for d in ${depfiles}; do
202 if cat "${d}" | egrep -q 'effective_condition\s*:.*restricted' ; then
203 lconditions="${lconditions}${lconditions:+ }restricted"
204 fi
205 done
206 ;;
207 esac
208 echo "${lconditions}"
209}
210
211
212process_args "$@"
213
214if [ -n "${ofile}" ]; then
215 # truncate the output file before appending results
216 : >"${ofile}"
217else
218 ofile=/dev/stdout
219fi
220
221# spit out the license metadata file content
222(
223 echo 'license_package_name: "'${license_package_name}'"'
224 for kind in ${license_kinds}; do
225 echo 'license_kind: "'${kind}'"'
226 done
227 for condition in ${license_conditions}; do
228 echo 'license_condition: "'${condition}'"'
229 done
230 for f in ${license_notice}; do
231 echo 'license_text: "'${f}'"'
232 done
233 echo "is_container: ${is_container}"
234 for t in ${targets}; do
235 echo 'target: "'${t}'"'
236 done
237 for m in ${installmap}; do
238 echo 'install_map: "'${m}'"'
239 done
240) >>"${ofile}"
241read_deps
242effective_conditions=$(calculate_effective_conditions)
243for condition in ${effective_conditions}; do
244 echo 'effective_condition: "'${condition}'"'
245done >>"${ofile}"
246for dep in ${depfiles}; do
247 echo 'dep {'
248 cat "${dep}" | \
249 awk -v name="${dep}" '
250 function strip_type() {
251 $1 = ""
252 sub(/^\s*/, "")
253 }
254 BEGIN {
255 print " dep_name: " name
256 }
257 $1 == "license_package_name:" {
258 strip_type()
259 print " dep_package_name: "$0
260 }
261 $1 == "dep_name:" {
262 print " dep_sub_dep: "$2
263 }
264 $1 == "license_kind:" {
265 print " dep_license_kind: "$2
266 }
267 $1 == "license_condition:" {
268 print " dep_license_condition: "$2
269 }
270 $1 == "is_container:" {
271 print " dep_is_container: "$2
272 }
273 $1 == "license_text:" {
274 strip_type()
275 print " dep_license_text: "$0
276 }
277 $1 == "target:" {
278 print " dep_target: "$2
279 }
280 $1 == "install_map:" {
281 print " dep_install_map: "$2
282 }
283 '
284 # The restricted license kind is contagious to all linked dependencies.
285 dep_conditions=$(echo $(
286 cat "${dep}" | awk '
287 $1 == "effective_condition:" {
288 $1 = ""
289 sub(/^\s*/, "")
290 gsub(/"/, "")
291 print
292 }
293 '
294 ))
295 for condition in ${dep_conditions}; do
296 echo ' dep_effective_condition: "'${condition}'"'
297 done
298 if ! ${is_container}; then
299 case "${dep_conditions}" in
300 *restricted*) : already restricted -- nothing to inherit ;;
301 *)
302 case "${effective_conditions}" in
303 *restricted*)
304 # "contagious" restricted infects everything linked to restricted
305 echo ' dep_effective_condition: "restricted"'
306 ;;
307 esac
308 ;;
309 esac
310 fi
311 echo '}'
312done >>"${ofile}"