xref: /aosp_15_r20/build/soong/scripts/transitive-deps.sh (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1*333d2b36SAndroid Build Coastguard Worker#!/bin/bash
2*333d2b36SAndroid Build Coastguard Worker
3*333d2b36SAndroid Build Coastguard Workerset -eu
4*333d2b36SAndroid Build Coastguard Worker
5*333d2b36SAndroid Build Coastguard Worker# Copyright 2020 Google Inc. All rights reserved.
6*333d2b36SAndroid Build Coastguard Worker#
7*333d2b36SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
8*333d2b36SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
9*333d2b36SAndroid Build Coastguard Worker# You may obtain a copy of the License at
10*333d2b36SAndroid Build Coastguard Worker#
11*333d2b36SAndroid Build Coastguard Worker#     http://www.apache.org/licenses/LICENSE-2.0
12*333d2b36SAndroid Build Coastguard Worker#
13*333d2b36SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
14*333d2b36SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
15*333d2b36SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16*333d2b36SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
17*333d2b36SAndroid Build Coastguard Worker# limitations under the License.
18*333d2b36SAndroid Build Coastguard Worker
19*333d2b36SAndroid Build Coastguard Worker# Tool to evaluate the transitive closure of the ninja dependency graph of the
20*333d2b36SAndroid Build Coastguard Worker# files and targets a given target depends on.
21*333d2b36SAndroid Build Coastguard Worker#
22*333d2b36SAndroid Build Coastguard Worker# i.e. the list of things that, if changed, could cause a change to a target.
23*333d2b36SAndroid Build Coastguard Worker
24*333d2b36SAndroid Build Coastguard Workerreadonly me=$(basename "${0}")
25*333d2b36SAndroid Build Coastguard Worker
26*333d2b36SAndroid Build Coastguard Workerreadonly usage="usage: ${me} {options} target [target...]
27*333d2b36SAndroid Build Coastguard Worker
28*333d2b36SAndroid Build Coastguard WorkerEvaluate the transitive closure of files and ninja targets that one or more
29*333d2b36SAndroid Build Coastguard Workertargets depend on.
30*333d2b36SAndroid Build Coastguard Worker
31*333d2b36SAndroid Build Coastguard WorkerDependency Options:
32*333d2b36SAndroid Build Coastguard Worker
33*333d2b36SAndroid Build Coastguard Worker  -(no)order_deps   Whether to include order-only dependencies. (Default false)
34*333d2b36SAndroid Build Coastguard Worker  -(no)implicit     Whether to include implicit dependencies. (Default true)
35*333d2b36SAndroid Build Coastguard Worker  -(no)explicit     Whether to include regular / explicit deps. (Default true)
36*333d2b36SAndroid Build Coastguard Worker
37*333d2b36SAndroid Build Coastguard Worker  -nofollow         Unanchored regular expression. Matching paths and targets
38*333d2b36SAndroid Build Coastguard Worker                    always get reported. Their dependencies do not get reported
39*333d2b36SAndroid Build Coastguard Worker                    unless first encountered in a 'container' file type.
40*333d2b36SAndroid Build Coastguard Worker                    Multiple allowed and combined using '|'.
41*333d2b36SAndroid Build Coastguard Worker                    e.g. -nofollow='*.so' not -nofollow='.so$'
42*333d2b36SAndroid Build Coastguard Worker                    -nofollow='*.so|*.dex' or -nofollow='*.so' -nofollow='.dex'
43*333d2b36SAndroid Build Coastguard Worker                    (Defaults to no matches)
44*333d2b36SAndroid Build Coastguard Worker  -container        Unanchored regular expression. Matching file extensions get
45*333d2b36SAndroid Build Coastguard Worker                    treated as 'container' files for -nofollow option.
46*333d2b36SAndroid Build Coastguard Worker                    Multiple allowed and combines using '|'
47*333d2b36SAndroid Build Coastguard Worker                    (Default 'apex|apk|zip|jar|tar|tgz')
48*333d2b36SAndroid Build Coastguard Worker
49*333d2b36SAndroid Build Coastguard WorkerOutput Options:
50*333d2b36SAndroid Build Coastguard Worker
51*333d2b36SAndroid Build Coastguard Worker  -(no)quiet        Suppresses progress output to stderr and interactive
52*333d2b36SAndroid Build Coastguard Worker    alias -(no)q    prompts. By default, when stderr is a tty, progress gets
53*333d2b36SAndroid Build Coastguard Worker                    reported to stderr; when both stderr and stdin are tty,
54*333d2b36SAndroid Build Coastguard Worker                    the script asks user whether to delete intermediate files.
55*333d2b36SAndroid Build Coastguard Worker                    When suppressed or not prompted, script always deletes the
56*333d2b36SAndroid Build Coastguard Worker                    temporary / intermediate files.
57*333d2b36SAndroid Build Coastguard Worker  -sep=<delim>      Use 'delim' as output field separator between notice
58*333d2b36SAndroid Build Coastguard Worker                    checksum and notice filename in notice output.
59*333d2b36SAndroid Build Coastguard Worker                    e.g. sep='\\t'
60*333d2b36SAndroid Build Coastguard Worker                    (Default space)
61*333d2b36SAndroid Build Coastguard Worker  -csv              Shorthand for -sep=','
62*333d2b36SAndroid Build Coastguard Worker  -directories=<f>  Output directory names of dependencies to 'f'.
63*333d2b36SAndroid Build Coastguard Worker    alias -d        User '/dev/stdout' to send directories to stdout. Defaults
64*333d2b36SAndroid Build Coastguard Worker                    to no directory output.
65*333d2b36SAndroid Build Coastguard Worker  -notices=<file>   Output license and notice file paths to 'file'.
66*333d2b36SAndroid Build Coastguard Worker    alias -n        Use '/dev/stdout' to send notices to stdout. Defaults to no
67*333d2b36SAndroid Build Coastguard Worker                    license/notice output.
68*333d2b36SAndroid Build Coastguard Worker  -projects=<file>  Output git project names to 'file'. Use '/dev/stdout' to
69*333d2b36SAndroid Build Coastguard Worker    alias -p        send projects to stdout. Defaults to no project output.
70*333d2b36SAndroid Build Coastguard Worker  -targets=<fils>   Output target dependencies to 'file'. Use '/dev/stdout' to
71*333d2b36SAndroid Build Coastguard Worker    alias -t        send targets to stdout.
72*333d2b36SAndroid Build Coastguard Worker                    When no directory, notice, project or target output options
73*333d2b36SAndroid Build Coastguard Worker                    given, defaults to stdout. Otherwise, defaults to no target
74*333d2b36SAndroid Build Coastguard Worker                    output.
75*333d2b36SAndroid Build Coastguard Worker
76*333d2b36SAndroid Build Coastguard WorkerAt minimum, before running this script, you must first run:
77*333d2b36SAndroid Build Coastguard Worker$ source build/envsetup.sh
78*333d2b36SAndroid Build Coastguard Worker$ lunch
79*333d2b36SAndroid Build Coastguard Worker$ m nothing
80*333d2b36SAndroid Build Coastguard Workerto setup the build environment, choose a target platform, and build the ninja
81*333d2b36SAndroid Build Coastguard Workerdependency graph.
82*333d2b36SAndroid Build Coastguard Worker"
83*333d2b36SAndroid Build Coastguard Worker
84*333d2b36SAndroid Build Coastguard Workerfunction die() { echo -e "${*}" >&2; exit 2; }
85*333d2b36SAndroid Build Coastguard Worker
86*333d2b36SAndroid Build Coastguard Worker# Reads one input target per line from stdin; outputs (isnotice target) tuples.
87*333d2b36SAndroid Build Coastguard Worker#
88*333d2b36SAndroid Build Coastguard Worker# output target is a ninja target that the input target depends on
89*333d2b36SAndroid Build Coastguard Worker# isnotice in {0,1} with 1 for output targets believed to be license or notice
90*333d2b36SAndroid Build Coastguard Workerfunction getDeps() {
91*333d2b36SAndroid Build Coastguard Worker    (tr '\n' '\0' | xargs -0 -r "${ninja_bin}" -f "${ninja_file}" -t query) \
92*333d2b36SAndroid Build Coastguard Worker    | awk -v include_order="${include_order_deps}" \
93*333d2b36SAndroid Build Coastguard Worker        -v include_implicit="${include_implicit_deps}" \
94*333d2b36SAndroid Build Coastguard Worker        -v include_explicit="${include_deps}" \
95*333d2b36SAndroid Build Coastguard Worker        -v containers="${container_types}" \
96*333d2b36SAndroid Build Coastguard Worker    '
97*333d2b36SAndroid Build Coastguard Worker      BEGIN {
98*333d2b36SAndroid Build Coastguard Worker        ininput = 0
99*333d2b36SAndroid Build Coastguard Worker        isnotice = 0
100*333d2b36SAndroid Build Coastguard Worker        currFileName = ""
101*333d2b36SAndroid Build Coastguard Worker        currExt = ""
102*333d2b36SAndroid Build Coastguard Worker      }
103*333d2b36SAndroid Build Coastguard Worker      $1 == "outputs:" || $1 == "validations:" {
104*333d2b36SAndroid Build Coastguard Worker        ininput = 0
105*333d2b36SAndroid Build Coastguard Worker      }
106*333d2b36SAndroid Build Coastguard Worker      ininput == 0 && $0 ~ /^\S\S*:$/ {
107*333d2b36SAndroid Build Coastguard Worker        isnotice = ($0 ~ /.*NOTICE.*[.]txt:$/)
108*333d2b36SAndroid Build Coastguard Worker        currFileName = gensub(/^.*[/]([^/]*)[:]$/, "\\1", "g")
109*333d2b36SAndroid Build Coastguard Worker        currExt = gensub(/^.*[.]([^./]*)[:]$/, "\\1", "g")
110*333d2b36SAndroid Build Coastguard Worker      }
111*333d2b36SAndroid Build Coastguard Worker      ininput != 0 && $1 !~ /^[|][|]?/ {
112*333d2b36SAndroid Build Coastguard Worker        if (include_explicit == "true") {
113*333d2b36SAndroid Build Coastguard Worker          fileName = gensub(/^.*[/]([^/]*)$/, "\\1", "g")
114*333d2b36SAndroid Build Coastguard Worker          print ( \
115*333d2b36SAndroid Build Coastguard Worker              (isnotice && $0 !~ /^\s*build[/]soong[/]scripts[/]/) \
116*333d2b36SAndroid Build Coastguard Worker              || $0 ~ /NOTICE|LICEN[CS]E/ \
117*333d2b36SAndroid Build Coastguard Worker              || $0 ~ /(notice|licen[cs]e)[.]txt/ \
118*333d2b36SAndroid Build Coastguard Worker          )" "(fileName == currFileName||currExt ~ "^(" containers ")$")" "gensub(/^\s*/, "", "g")
119*333d2b36SAndroid Build Coastguard Worker        }
120*333d2b36SAndroid Build Coastguard Worker      }
121*333d2b36SAndroid Build Coastguard Worker      ininput != 0 && $1 == "|" {
122*333d2b36SAndroid Build Coastguard Worker        if (include_implicit == "true") {
123*333d2b36SAndroid Build Coastguard Worker          fileName = gensub(/^.*[/]([^/]*)$/, "\\1", "g")
124*333d2b36SAndroid Build Coastguard Worker          $1 = ""
125*333d2b36SAndroid Build Coastguard Worker          print ( \
126*333d2b36SAndroid Build Coastguard Worker              (isnotice && $0 !~ /^\s*build[/]soong[/]scripts[/]/) \
127*333d2b36SAndroid Build Coastguard Worker              || $0 ~ /NOTICE|LICEN[CS]E/ \
128*333d2b36SAndroid Build Coastguard Worker              || $0 ~ /(notice|licen[cs]e)[.]txt/ \
129*333d2b36SAndroid Build Coastguard Worker          )" "(fileName == currFileName||currExt ~ "^(" containers ")$")" "gensub(/^\s*/, "", "g")
130*333d2b36SAndroid Build Coastguard Worker        }
131*333d2b36SAndroid Build Coastguard Worker      }
132*333d2b36SAndroid Build Coastguard Worker      ininput != 0 && $1 == "||" {
133*333d2b36SAndroid Build Coastguard Worker        if (include_order == "true") {
134*333d2b36SAndroid Build Coastguard Worker          fileName = gensub(/^.*[/]([^/]*)$/, "\\1", "g")
135*333d2b36SAndroid Build Coastguard Worker          $1 = ""
136*333d2b36SAndroid Build Coastguard Worker          print ( \
137*333d2b36SAndroid Build Coastguard Worker              (isnotice && $0 !~ /^\s*build[/]soong[/]scripts[/]/) \
138*333d2b36SAndroid Build Coastguard Worker              || $0 ~ /NOTICE|LICEN[CS]E/ \
139*333d2b36SAndroid Build Coastguard Worker              || $0 ~ /(notice|licen[cs]e)[.]txt/ \
140*333d2b36SAndroid Build Coastguard Worker          )" "(fileName == currFileName||currExt ~ "^(" containers ")$")" "gensub(/^\s*/, "", "g")
141*333d2b36SAndroid Build Coastguard Worker        }
142*333d2b36SAndroid Build Coastguard Worker      }
143*333d2b36SAndroid Build Coastguard Worker      $1 == "input:" {
144*333d2b36SAndroid Build Coastguard Worker        ininput = 1
145*333d2b36SAndroid Build Coastguard Worker      }
146*333d2b36SAndroid Build Coastguard Worker    '
147*333d2b36SAndroid Build Coastguard Worker}
148*333d2b36SAndroid Build Coastguard Worker
149*333d2b36SAndroid Build Coastguard Worker# Reads one input directory per line from stdin; outputs unique git projects.
150*333d2b36SAndroid Build Coastguard Workerfunction getProjects() {
151*333d2b36SAndroid Build Coastguard Worker    while read d; do
152*333d2b36SAndroid Build Coastguard Worker        while [ "${d}" != '.' ] && [ "${d}" != '/' ]; do
153*333d2b36SAndroid Build Coastguard Worker            if [ -d "${d}/.git/" ]; then
154*333d2b36SAndroid Build Coastguard Worker                echo "${d}"
155*333d2b36SAndroid Build Coastguard Worker                break
156*333d2b36SAndroid Build Coastguard Worker            fi
157*333d2b36SAndroid Build Coastguard Worker            d=$(dirname "${d}")
158*333d2b36SAndroid Build Coastguard Worker        done
159*333d2b36SAndroid Build Coastguard Worker    done | sort -u
160*333d2b36SAndroid Build Coastguard Worker}
161*333d2b36SAndroid Build Coastguard Worker
162*333d2b36SAndroid Build Coastguard Worker
163*333d2b36SAndroid Build Coastguard Workerif [ -z "${ANDROID_BUILD_TOP}" ]; then
164*333d2b36SAndroid Build Coastguard Worker    die "${me}: Run 'lunch' to configure the build environment"
165*333d2b36SAndroid Build Coastguard Workerfi
166*333d2b36SAndroid Build Coastguard Worker
167*333d2b36SAndroid Build Coastguard Workerif [ -z "${TARGET_PRODUCT}" ]; then
168*333d2b36SAndroid Build Coastguard Worker    die "${me}: Run 'lunch' to configure the build environment"
169*333d2b36SAndroid Build Coastguard Workerfi
170*333d2b36SAndroid Build Coastguard Worker
171*333d2b36SAndroid Build Coastguard Workerreadonly ninja_file="${ANDROID_BUILD_TOP}/out/combined-${TARGET_PRODUCT}.ninja"
172*333d2b36SAndroid Build Coastguard Workerif [ ! -f "${ninja_file}" ]; then
173*333d2b36SAndroid Build Coastguard Worker    die "${me}: Run 'm nothing' to build the dependency graph"
174*333d2b36SAndroid Build Coastguard Workerfi
175*333d2b36SAndroid Build Coastguard Worker
176*333d2b36SAndroid Build Coastguard Workerreadonly ninja_bin="${ANDROID_BUILD_TOP}/prebuilts/build-tools/linux-x86/bin/ninja"
177*333d2b36SAndroid Build Coastguard Workerif [ ! -x "${ninja_bin}" ]; then
178*333d2b36SAndroid Build Coastguard Worker    die "${me}: Cannot find ninja executable expected at ${ninja_bin}"
179*333d2b36SAndroid Build Coastguard Workerfi
180*333d2b36SAndroid Build Coastguard Worker
181*333d2b36SAndroid Build Coastguard Worker
182*333d2b36SAndroid Build Coastguard Worker# parse the command-line
183*333d2b36SAndroid Build Coastguard Worker
184*333d2b36SAndroid Build Coastguard Workerdeclare -a targets # one or more targets to evaluate
185*333d2b36SAndroid Build Coastguard Worker
186*333d2b36SAndroid Build Coastguard Workerinclude_order_deps=false    # whether to trace through || "order dependencies"
187*333d2b36SAndroid Build Coastguard Workerinclude_implicit_deps=true  # whether to trace through | "implicit deps"
188*333d2b36SAndroid Build Coastguard Workerinclude_deps=true           # whether to trace through regular explicit deps
189*333d2b36SAndroid Build Coastguard Workerquiet=false                 # whether to suppress progress
190*333d2b36SAndroid Build Coastguard Worker
191*333d2b36SAndroid Build Coastguard Workerprojects_out=''             # where to output the list of projects
192*333d2b36SAndroid Build Coastguard Workerdirectories_out=''          # where to output the list of directories
193*333d2b36SAndroid Build Coastguard Workertargets_out=''              # where to output the list of targets/source files
194*333d2b36SAndroid Build Coastguard Workernotices_out=''              # where to output the list of license/notice files
195*333d2b36SAndroid Build Coastguard Worker
196*333d2b36SAndroid Build Coastguard Workersep=" "                     # separator between md5sum and notice filename
197*333d2b36SAndroid Build Coastguard Worker
198*333d2b36SAndroid Build Coastguard Workernofollow=''                 # regularexp must fully match targets to skip
199*333d2b36SAndroid Build Coastguard Worker
200*333d2b36SAndroid Build Coastguard Workercontainer_types=''          # regularexp must full match file extension
201*333d2b36SAndroid Build Coastguard Worker                            # defaults to 'apex|apk|zip|jar|tar|tgz' below.
202*333d2b36SAndroid Build Coastguard Worker
203*333d2b36SAndroid Build Coastguard Workeruse_stdin=false             # whether to read targets from stdin i.e. target -
204*333d2b36SAndroid Build Coastguard Worker
205*333d2b36SAndroid Build Coastguard Workerwhile [ $# -gt 0 ]; do
206*333d2b36SAndroid Build Coastguard Worker    case "${1:-}" in
207*333d2b36SAndroid Build Coastguard Worker      -)
208*333d2b36SAndroid Build Coastguard Worker        use_stdin=true
209*333d2b36SAndroid Build Coastguard Worker      ;;
210*333d2b36SAndroid Build Coastguard Worker      -*)
211*333d2b36SAndroid Build Coastguard Worker        flag=$(expr "${1}" : '^-*\(.*\)$')
212*333d2b36SAndroid Build Coastguard Worker        case "${flag:-}" in
213*333d2b36SAndroid Build Coastguard Worker          order_deps)
214*333d2b36SAndroid Build Coastguard Worker            include_order_deps=true;;
215*333d2b36SAndroid Build Coastguard Worker          noorder_deps)
216*333d2b36SAndroid Build Coastguard Worker            include_order_deps=false;;
217*333d2b36SAndroid Build Coastguard Worker          implicit)
218*333d2b36SAndroid Build Coastguard Worker            include_implicit_deps=true;;
219*333d2b36SAndroid Build Coastguard Worker          noimplicit)
220*333d2b36SAndroid Build Coastguard Worker            include_implicit_deps=false;;
221*333d2b36SAndroid Build Coastguard Worker          explicit)
222*333d2b36SAndroid Build Coastguard Worker            include_deps=true;;
223*333d2b36SAndroid Build Coastguard Worker          noexplicit)
224*333d2b36SAndroid Build Coastguard Worker            include_deps=false;;
225*333d2b36SAndroid Build Coastguard Worker          csv)
226*333d2b36SAndroid Build Coastguard Worker            sep=",";;
227*333d2b36SAndroid Build Coastguard Worker          sep)
228*333d2b36SAndroid Build Coastguard Worker            sep="${2?"${usage}"}"; shift;;
229*333d2b36SAndroid Build Coastguard Worker          sep=)
230*333d2b36SAndroid Build Coastguard Worker            sep=$(expr "${flag}" : '^sep=\(.*\)$');;
231*333d2b36SAndroid Build Coastguard Worker          q) ;&
232*333d2b36SAndroid Build Coastguard Worker          quiet)
233*333d2b36SAndroid Build Coastguard Worker            quiet=true;;
234*333d2b36SAndroid Build Coastguard Worker          noq) ;&
235*333d2b36SAndroid Build Coastguard Worker          noquiet)
236*333d2b36SAndroid Build Coastguard Worker            quiet=false;;
237*333d2b36SAndroid Build Coastguard Worker          nofollow)
238*333d2b36SAndroid Build Coastguard Worker            case "${nofollow}" in
239*333d2b36SAndroid Build Coastguard Worker              '')
240*333d2b36SAndroid Build Coastguard Worker                nofollow="${2?"${usage}"}";;
241*333d2b36SAndroid Build Coastguard Worker              *)
242*333d2b36SAndroid Build Coastguard Worker                nofollow="${nofollow}|${2?"${usage}"}";;
243*333d2b36SAndroid Build Coastguard Worker            esac
244*333d2b36SAndroid Build Coastguard Worker            shift
245*333d2b36SAndroid Build Coastguard Worker          ;;
246*333d2b36SAndroid Build Coastguard Worker          nofollow=*)
247*333d2b36SAndroid Build Coastguard Worker            case "${nofollow}" in
248*333d2b36SAndroid Build Coastguard Worker              '')
249*333d2b36SAndroid Build Coastguard Worker                nofollow=$(expr "${flag}" : '^nofollow=\(.*\)$');;
250*333d2b36SAndroid Build Coastguard Worker              *)
251*333d2b36SAndroid Build Coastguard Worker                nofollow="${nofollow}|"$(expr "${flag}" : '^nofollow=\(.*\)$');;
252*333d2b36SAndroid Build Coastguard Worker            esac
253*333d2b36SAndroid Build Coastguard Worker          ;;
254*333d2b36SAndroid Build Coastguard Worker          container)
255*333d2b36SAndroid Build Coastguard Worker            container_types="${container_types}|${2?"${usage}"}";;
256*333d2b36SAndroid Build Coastguard Worker          container=*)
257*333d2b36SAndroid Build Coastguard Worker            container_types="${container_types}|"$(expr "${flag}" : '^container=\(.*\)$');;
258*333d2b36SAndroid Build Coastguard Worker          p) ;&
259*333d2b36SAndroid Build Coastguard Worker          projects)
260*333d2b36SAndroid Build Coastguard Worker            projects_out="${2?"${usage}"}"; shift;;
261*333d2b36SAndroid Build Coastguard Worker          p=*) ;&
262*333d2b36SAndroid Build Coastguard Worker          projects=*)
263*333d2b36SAndroid Build Coastguard Worker            projects_out=$(expr "${flag}" : '^.*=\(.*\)$');;
264*333d2b36SAndroid Build Coastguard Worker          d) ;&
265*333d2b36SAndroid Build Coastguard Worker          directores)
266*333d2b36SAndroid Build Coastguard Worker            directories_out="${2?"${usage}"}"; shift;;
267*333d2b36SAndroid Build Coastguard Worker          d=*) ;&
268*333d2b36SAndroid Build Coastguard Worker          directories=*)
269*333d2b36SAndroid Build Coastguard Worker            directories_out=$(expr "${flag}" : '^.*=\(.*\)$');;
270*333d2b36SAndroid Build Coastguard Worker          t) ;&
271*333d2b36SAndroid Build Coastguard Worker          targets)
272*333d2b36SAndroid Build Coastguard Worker            targets_out="${2?"${usage}"}"; shift;;
273*333d2b36SAndroid Build Coastguard Worker          t=*) ;&
274*333d2b36SAndroid Build Coastguard Worker          targets=)
275*333d2b36SAndroid Build Coastguard Worker            targets_out=$(expr "${flag}" : '^.*=\(.*\)$');;
276*333d2b36SAndroid Build Coastguard Worker          n) ;&
277*333d2b36SAndroid Build Coastguard Worker          notices)
278*333d2b36SAndroid Build Coastguard Worker            notices_out="${2?"${usage}"}"; shift;;
279*333d2b36SAndroid Build Coastguard Worker          n=*) ;&
280*333d2b36SAndroid Build Coastguard Worker          notices=)
281*333d2b36SAndroid Build Coastguard Worker            notices_out=$(expr "${flag}" : '^.*=\(.*\)$');;
282*333d2b36SAndroid Build Coastguard Worker          *)
283*333d2b36SAndroid Build Coastguard Worker            die "${usage}\n\nUnknown flag ${1}";;
284*333d2b36SAndroid Build Coastguard Worker        esac
285*333d2b36SAndroid Build Coastguard Worker      ;;
286*333d2b36SAndroid Build Coastguard Worker      *)
287*333d2b36SAndroid Build Coastguard Worker        targets+=("${1:-}")
288*333d2b36SAndroid Build Coastguard Worker      ;;
289*333d2b36SAndroid Build Coastguard Worker    esac
290*333d2b36SAndroid Build Coastguard Worker    shift
291*333d2b36SAndroid Build Coastguard Workerdone
292*333d2b36SAndroid Build Coastguard Worker
293*333d2b36SAndroid Build Coastguard Worker
294*333d2b36SAndroid Build Coastguard Worker# fail fast if command-line arguments are invalid
295*333d2b36SAndroid Build Coastguard Worker
296*333d2b36SAndroid Build Coastguard Workerif [ ! -v targets[0] ] && ! ${use_stdin}; then
297*333d2b36SAndroid Build Coastguard Worker    die "${usage}\n\nNo target specified."
298*333d2b36SAndroid Build Coastguard Workerfi
299*333d2b36SAndroid Build Coastguard Worker
300*333d2b36SAndroid Build Coastguard Workerif [ -z "${projects_out}" ] \
301*333d2b36SAndroid Build Coastguard Worker  && [ -z "${directories_out}" ] \
302*333d2b36SAndroid Build Coastguard Worker  && [ -z "${targets_out}" ] \
303*333d2b36SAndroid Build Coastguard Worker  && [ -z "${notices_out}" ]
304*333d2b36SAndroid Build Coastguard Workerthen
305*333d2b36SAndroid Build Coastguard Worker    targets_out='/dev/stdout'
306*333d2b36SAndroid Build Coastguard Workerfi
307*333d2b36SAndroid Build Coastguard Worker
308*333d2b36SAndroid Build Coastguard Workerif [ -z "${container_types}" ]; then
309*333d2b36SAndroid Build Coastguard Worker  container_types='apex|apk|zip|jar|tar|tgz'
310*333d2b36SAndroid Build Coastguard Workerfi
311*333d2b36SAndroid Build Coastguard Worker
312*333d2b36SAndroid Build Coastguard Worker# showProgress when stderr is a tty
313*333d2b36SAndroid Build Coastguard Workerif [ -t 2 ] && ! ${quiet}; then
314*333d2b36SAndroid Build Coastguard Worker    showProgress=true
315*333d2b36SAndroid Build Coastguard Workerelse
316*333d2b36SAndroid Build Coastguard Worker    showProgress=false
317*333d2b36SAndroid Build Coastguard Workerfi
318*333d2b36SAndroid Build Coastguard Worker
319*333d2b36SAndroid Build Coastguard Worker# interactive when both stderr and stdin are tty
320*333d2b36SAndroid Build Coastguard Workerif ${showProgress} && [ -t 0 ]; then
321*333d2b36SAndroid Build Coastguard Worker    interactive=true
322*333d2b36SAndroid Build Coastguard Workerelse
323*333d2b36SAndroid Build Coastguard Worker    interactive=false
324*333d2b36SAndroid Build Coastguard Workerfi
325*333d2b36SAndroid Build Coastguard Worker
326*333d2b36SAndroid Build Coastguard Worker
327*333d2b36SAndroid Build Coastguard Workerreadonly tmpFiles=$(mktemp -d "${TMPDIR}.tdeps.XXXXXXXXX")
328*333d2b36SAndroid Build Coastguard Workerif [ -z "${tmpFiles}" ]; then
329*333d2b36SAndroid Build Coastguard Worker    die "${me}: unable to create temporary directory"
330*333d2b36SAndroid Build Coastguard Workerfi
331*333d2b36SAndroid Build Coastguard Worker
332*333d2b36SAndroid Build Coastguard Worker# The deps files contain unique (isnotice target) tuples where
333*333d2b36SAndroid Build Coastguard Worker# isnotice in {0,1} with 1 when ninja target 'target' is a license or notice.
334*333d2b36SAndroid Build Coastguard Workerreadonly oldDeps="${tmpFiles}/old"
335*333d2b36SAndroid Build Coastguard Workerreadonly newDeps="${tmpFiles}/new"
336*333d2b36SAndroid Build Coastguard Workerreadonly allDeps="${tmpFiles}/all"
337*333d2b36SAndroid Build Coastguard Worker
338*333d2b36SAndroid Build Coastguard Workerif ${use_stdin}; then # start deps by reading 1 target per line from stdin
339*333d2b36SAndroid Build Coastguard Worker  awk '
340*333d2b36SAndroid Build Coastguard Worker    NF > 0 {
341*333d2b36SAndroid Build Coastguard Worker      print ( \
342*333d2b36SAndroid Build Coastguard Worker          $0 ~ /NOTICE|LICEN[CS]E/ \
343*333d2b36SAndroid Build Coastguard Worker          || $0 ~ /(notice|licen[cs]e)[.]txt/ \
344*333d2b36SAndroid Build Coastguard Worker      )" "gensub(/\s*$/, "", "g", gensub(/^\s*/, "", "g"))
345*333d2b36SAndroid Build Coastguard Worker    }
346*333d2b36SAndroid Build Coastguard Worker  ' > "${newDeps}"
347*333d2b36SAndroid Build Coastguard Workerelse # start with no deps by clearing file
348*333d2b36SAndroid Build Coastguard Worker  : > "${newDeps}"
349*333d2b36SAndroid Build Coastguard Workerfi
350*333d2b36SAndroid Build Coastguard Worker
351*333d2b36SAndroid Build Coastguard Worker# extend deps by appending targets from command-line
352*333d2b36SAndroid Build Coastguard Workerfor idx in "${!targets[*]}"; do
353*333d2b36SAndroid Build Coastguard Worker    isnotice='0'
354*333d2b36SAndroid Build Coastguard Worker    case "${targets[${idx}]}" in
355*333d2b36SAndroid Build Coastguard Worker      *NOTICE*) ;&
356*333d2b36SAndroid Build Coastguard Worker      *LICEN[CS]E*) ;&
357*333d2b36SAndroid Build Coastguard Worker      *notice.txt) ;&
358*333d2b36SAndroid Build Coastguard Worker      *licen[cs]e.txt)
359*333d2b36SAndroid Build Coastguard Worker        isnotice='1';;
360*333d2b36SAndroid Build Coastguard Worker    esac
361*333d2b36SAndroid Build Coastguard Worker    echo "${isnotice} 1 ${targets[${idx}]}" >> "${newDeps}"
362*333d2b36SAndroid Build Coastguard Workerdone
363*333d2b36SAndroid Build Coastguard Worker
364*333d2b36SAndroid Build Coastguard Worker# remove duplicates and start with new, old and all the same
365*333d2b36SAndroid Build Coastguard Workersort -u < "${newDeps}" > "${allDeps}"
366*333d2b36SAndroid Build Coastguard Workercp "${allDeps}" "${newDeps}"
367*333d2b36SAndroid Build Coastguard Workercp "${allDeps}" "${oldDeps}"
368*333d2b36SAndroid Build Coastguard Worker
369*333d2b36SAndroid Build Coastguard Worker# report depth of dependenciens when showProgress
370*333d2b36SAndroid Build Coastguard Workerdepth=0
371*333d2b36SAndroid Build Coastguard Worker
372*333d2b36SAndroid Build Coastguard Worker# 1st iteration always unfiltered
373*333d2b36SAndroid Build Coastguard Workerfilter='cat'
374*333d2b36SAndroid Build Coastguard Workerwhile [ $(wc -l < "${newDeps}") -gt 0 ]; do
375*333d2b36SAndroid Build Coastguard Worker    if ${showProgress}; then
376*333d2b36SAndroid Build Coastguard Worker        echo "depth ${depth} has "$(wc -l < "${newDeps}")" targets" >&2
377*333d2b36SAndroid Build Coastguard Worker        depth=$(expr ${depth} + 1)
378*333d2b36SAndroid Build Coastguard Worker    fi
379*333d2b36SAndroid Build Coastguard Worker    ( # recalculate dependencies by combining unique inputs of new deps w. old
380*333d2b36SAndroid Build Coastguard Worker        set +e
381*333d2b36SAndroid Build Coastguard Worker        sh -c "${filter}" < "${newDeps}" | cut -d\  -f3- | getDeps
382*333d2b36SAndroid Build Coastguard Worker        set -e
383*333d2b36SAndroid Build Coastguard Worker        cat "${oldDeps}"
384*333d2b36SAndroid Build Coastguard Worker    ) | sort -u > "${allDeps}"
385*333d2b36SAndroid Build Coastguard Worker    # recalculate new dependencies as net additions to old dependencies
386*333d2b36SAndroid Build Coastguard Worker    set +e
387*333d2b36SAndroid Build Coastguard Worker    diff "${oldDeps}" "${allDeps}" --old-line-format='' --new-line-format='%L' \
388*333d2b36SAndroid Build Coastguard Worker      --unchanged-line-format='' > "${newDeps}"
389*333d2b36SAndroid Build Coastguard Worker    set -e
390*333d2b36SAndroid Build Coastguard Worker    # apply filters on subsequent iterations
391*333d2b36SAndroid Build Coastguard Worker    case "${nofollow}" in
392*333d2b36SAndroid Build Coastguard Worker      '')
393*333d2b36SAndroid Build Coastguard Worker        filter='cat';;
394*333d2b36SAndroid Build Coastguard Worker      *)
395*333d2b36SAndroid Build Coastguard Worker        filter="egrep -v '^[01] 0 (${nofollow})$'"
396*333d2b36SAndroid Build Coastguard Worker      ;;
397*333d2b36SAndroid Build Coastguard Worker    esac
398*333d2b36SAndroid Build Coastguard Worker    # recalculate old dependencies for next iteration
399*333d2b36SAndroid Build Coastguard Worker    cp "${allDeps}" "${oldDeps}"
400*333d2b36SAndroid Build Coastguard Workerdone
401*333d2b36SAndroid Build Coastguard Worker
402*333d2b36SAndroid Build Coastguard Worker# found all deps -- clean up last iteration of old and new
403*333d2b36SAndroid Build Coastguard Workerrm -f "${oldDeps}"
404*333d2b36SAndroid Build Coastguard Workerrm -f "${newDeps}"
405*333d2b36SAndroid Build Coastguard Worker
406*333d2b36SAndroid Build Coastguard Workerif ${showProgress}; then
407*333d2b36SAndroid Build Coastguard Worker    echo $(wc -l < "${allDeps}")" targets" >&2
408*333d2b36SAndroid Build Coastguard Workerfi
409*333d2b36SAndroid Build Coastguard Worker
410*333d2b36SAndroid Build Coastguard Workerif [ -n "${targets_out}" ]; then
411*333d2b36SAndroid Build Coastguard Worker    cut -d\  -f3- "${allDeps}" | sort -u > "${targets_out}"
412*333d2b36SAndroid Build Coastguard Workerfi
413*333d2b36SAndroid Build Coastguard Worker
414*333d2b36SAndroid Build Coastguard Workerif [ -n "${directories_out}" ] \
415*333d2b36SAndroid Build Coastguard Worker  || [ -n "${projects_out}" ] \
416*333d2b36SAndroid Build Coastguard Worker  || [ -n "${notices_out}" ]
417*333d2b36SAndroid Build Coastguard Workerthen
418*333d2b36SAndroid Build Coastguard Worker    readonly allDirs="${tmpFiles}/dirs"
419*333d2b36SAndroid Build Coastguard Worker    (
420*333d2b36SAndroid Build Coastguard Worker        cut -d\  -f3- "${allDeps}" | tr '\n' '\0' | xargs -0 dirname
421*333d2b36SAndroid Build Coastguard Worker    ) | sort -u > "${allDirs}"
422*333d2b36SAndroid Build Coastguard Worker    if ${showProgress}; then
423*333d2b36SAndroid Build Coastguard Worker        echo $(wc -l < "${allDirs}")" directories" >&2
424*333d2b36SAndroid Build Coastguard Worker    fi
425*333d2b36SAndroid Build Coastguard Worker
426*333d2b36SAndroid Build Coastguard Worker    case "${directories_out}" in
427*333d2b36SAndroid Build Coastguard Worker      '')        : do nothing;;
428*333d2b36SAndroid Build Coastguard Worker      *)
429*333d2b36SAndroid Build Coastguard Worker        cat "${allDirs}" > "${directories_out}"
430*333d2b36SAndroid Build Coastguard Worker      ;;
431*333d2b36SAndroid Build Coastguard Worker    esac
432*333d2b36SAndroid Build Coastguard Workerfi
433*333d2b36SAndroid Build Coastguard Worker
434*333d2b36SAndroid Build Coastguard Workerif [ -n "${projects_out}" ] \
435*333d2b36SAndroid Build Coastguard Worker  || [ -n "${notices_out}" ]
436*333d2b36SAndroid Build Coastguard Workerthen
437*333d2b36SAndroid Build Coastguard Worker    readonly allProj="${tmpFiles}/projects"
438*333d2b36SAndroid Build Coastguard Worker    set +e
439*333d2b36SAndroid Build Coastguard Worker    egrep -v '^out[/]' "${allDirs}" | getProjects > "${allProj}"
440*333d2b36SAndroid Build Coastguard Worker    set -e
441*333d2b36SAndroid Build Coastguard Worker    if ${showProgress}; then
442*333d2b36SAndroid Build Coastguard Worker        echo $(wc -l < "${allProj}")" projects" >&2
443*333d2b36SAndroid Build Coastguard Worker    fi
444*333d2b36SAndroid Build Coastguard Worker
445*333d2b36SAndroid Build Coastguard Worker    case "${projects_out}" in
446*333d2b36SAndroid Build Coastguard Worker      '')        : do nothing;;
447*333d2b36SAndroid Build Coastguard Worker      *)
448*333d2b36SAndroid Build Coastguard Worker        cat "${allProj}" > "${projects_out}"
449*333d2b36SAndroid Build Coastguard Worker      ;;
450*333d2b36SAndroid Build Coastguard Worker    esac
451*333d2b36SAndroid Build Coastguard Workerfi
452*333d2b36SAndroid Build Coastguard Worker
453*333d2b36SAndroid Build Coastguard Workercase "${notices_out}" in
454*333d2b36SAndroid Build Coastguard Worker  '')        : do nothing;;
455*333d2b36SAndroid Build Coastguard Worker  *)
456*333d2b36SAndroid Build Coastguard Worker    readonly allNotice="${tmpFiles}/notices"
457*333d2b36SAndroid Build Coastguard Worker    set +e
458*333d2b36SAndroid Build Coastguard Worker    egrep '^1' "${allDeps}" | cut -d\  -f3- | egrep -v '^out/' > "${allNotice}"
459*333d2b36SAndroid Build Coastguard Worker    set -e
460*333d2b36SAndroid Build Coastguard Worker    cat "${allProj}" | while read proj; do
461*333d2b36SAndroid Build Coastguard Worker        for f in LICENSE LICENCE NOTICE license.txt notice.txt; do
462*333d2b36SAndroid Build Coastguard Worker            if [ -f "${proj}/${f}" ]; then
463*333d2b36SAndroid Build Coastguard Worker                echo "${proj}/${f}"
464*333d2b36SAndroid Build Coastguard Worker            fi
465*333d2b36SAndroid Build Coastguard Worker        done
466*333d2b36SAndroid Build Coastguard Worker    done >> "${allNotice}"
467*333d2b36SAndroid Build Coastguard Worker    if ${showProgress}; then
468*333d2b36SAndroid Build Coastguard Worker      echo $(cat "${allNotice}" | sort -u | wc -l)" notice targets" >&2
469*333d2b36SAndroid Build Coastguard Worker    fi
470*333d2b36SAndroid Build Coastguard Worker    readonly hashedNotice="${tmpFiles}/hashednotices"
471*333d2b36SAndroid Build Coastguard Worker    ( # md5sum outputs checksum space indicator(space or *) filename newline
472*333d2b36SAndroid Build Coastguard Worker        set +e
473*333d2b36SAndroid Build Coastguard Worker        sort -u "${allNotice}" | tr '\n' '\0' | xargs -0 -r md5sum 2>/dev/null
474*333d2b36SAndroid Build Coastguard Worker        set -e
475*333d2b36SAndroid Build Coastguard Worker      # use sed to replace space and indicator with separator
476*333d2b36SAndroid Build Coastguard Worker    ) > "${hashedNotice}"
477*333d2b36SAndroid Build Coastguard Worker    if ${showProgress}; then
478*333d2b36SAndroid Build Coastguard Worker        echo $(cut -d\  -f2- "${hashedNotice}" | sort -u | wc -l)" notice files" >&2
479*333d2b36SAndroid Build Coastguard Worker        echo $(cut -d\  -f1 "${hashedNotice}" | sort -u | wc -l)" distinct notices" >&2
480*333d2b36SAndroid Build Coastguard Worker    fi
481*333d2b36SAndroid Build Coastguard Worker    sed 's/^\([^ ]*\) [* ]/\1'"${sep}"'/g' "${hashedNotice}" | sort > "${notices_out}"
482*333d2b36SAndroid Build Coastguard Worker  ;;
483*333d2b36SAndroid Build Coastguard Workeresac
484*333d2b36SAndroid Build Coastguard Worker
485*333d2b36SAndroid Build Coastguard Workerif ${interactive}; then
486*333d2b36SAndroid Build Coastguard Worker    echo -n "$(date '+%F %-k:%M:%S') Delete ${tmpFiles} ? [n] " >&2
487*333d2b36SAndroid Build Coastguard Worker    read answer
488*333d2b36SAndroid Build Coastguard Worker    case "${answer}" in [yY]*) rm -fr "${tmpFiles}";; esac
489*333d2b36SAndroid Build Coastguard Workerelse
490*333d2b36SAndroid Build Coastguard Worker    rm -fr "${tmpFiles}"
491*333d2b36SAndroid Build Coastguard Workerfi
492