1 | function die(msg) { |
---|
2 | print msg > "/dev/fd/2"; |
---|
3 | # awk will still do the END block before exiting... |
---|
4 | justexit = 1; |
---|
5 | exit(1); |
---|
6 | } |
---|
7 | |
---|
8 | # Ignore blank lines and comments. |
---|
9 | /^ *$/ { next; } |
---|
10 | /^#/ { next; } |
---|
11 | |
---|
12 | # Process normal lines. |
---|
13 | { |
---|
14 | packages[$1] = 1; |
---|
15 | n = 2; |
---|
16 | |
---|
17 | nparts = split($1, parts, /\//); |
---|
18 | if (expand[parts[nparts]]) |
---|
19 | expand[parts[nparts]] = "AMBIGUOUS"; |
---|
20 | else |
---|
21 | expand[parts[nparts]] = $1; |
---|
22 | expand[$1] = $1; |
---|
23 | |
---|
24 | package_names[$1] = parts[nparts]; |
---|
25 | |
---|
26 | while (n <= NF) { |
---|
27 | if ($n == "early") |
---|
28 | early[numearly++] = $1; |
---|
29 | else if ($n == "late") |
---|
30 | late[numlate++] = $1; |
---|
31 | else if ($n == "requires") |
---|
32 | prereqs[$1] = $++n; |
---|
33 | else if ($n == "on" || $n == "except") { |
---|
34 | built[$1] = $n == "on"; |
---|
35 | split($(n+1), oses, /,/); |
---|
36 | for (ind in oses) { |
---|
37 | if (os == oses[ind]) |
---|
38 | built[$1] = $n == "except"; |
---|
39 | } |
---|
40 | n++; |
---|
41 | } else if ($n == "package") |
---|
42 | package_names[$1] = $++n; |
---|
43 | else |
---|
44 | die("Bad packages line: " $0); |
---|
45 | n++; |
---|
46 | } |
---|
47 | } |
---|
48 | |
---|
49 | # Output a package name, preceded by all of its dependencies that haven't |
---|
50 | # already been output. |
---|
51 | function build(pkg) { |
---|
52 | if (built[pkg]) |
---|
53 | return; |
---|
54 | |
---|
55 | if (building[pkg]) |
---|
56 | die("Dependency loop for " pkg); |
---|
57 | building[pkg] = 1; |
---|
58 | |
---|
59 | while (prereqs[pkg]) { |
---|
60 | # We have to keep re-splitting prereqs because we don't have |
---|
61 | # local variables, so if we tried to keep more state the |
---|
62 | # recursive calls would write over it. |
---|
63 | comma = index(prereqs[pkg], ","); |
---|
64 | if (comma) { |
---|
65 | req = substr(prereqs[pkg], 0, comma - 1); |
---|
66 | prereqs[pkg] = substr(prereqs[pkg], comma + 1); |
---|
67 | } else { |
---|
68 | req = prereqs[pkg]; |
---|
69 | delete prereqs[pkg]; |
---|
70 | } |
---|
71 | build(expand[req]); |
---|
72 | } |
---|
73 | |
---|
74 | if (start == pkg) |
---|
75 | start = ""; |
---|
76 | |
---|
77 | # If we're not still waiting to see the start package, output name. |
---|
78 | if (!start) { |
---|
79 | if (pkgnames) |
---|
80 | print pkg " " package_names[pkg] |
---|
81 | else |
---|
82 | print pkg; |
---|
83 | } |
---|
84 | |
---|
85 | # If that was the end package, we're done. |
---|
86 | if (end == pkg) |
---|
87 | exit(0); |
---|
88 | |
---|
89 | built[pkg] = 1; |
---|
90 | building[pkg] = 0; |
---|
91 | } |
---|
92 | |
---|
93 | # At the end of the file, output the list of packages to build. |
---|
94 | END { |
---|
95 | # ...unless we're erroring out. |
---|
96 | if (justexit) |
---|
97 | exit; |
---|
98 | |
---|
99 | # Check dependencies. |
---|
100 | for (pkg in packages) { |
---|
101 | if (!prereqs[pkg]) |
---|
102 | continue; |
---|
103 | split(prereqs[pkg], reqs, /,/); |
---|
104 | for (ind in reqs) { |
---|
105 | if (expand[reqs[ind]] == "AMBIGUOUS") |
---|
106 | die("Ambiguous package name " reqs[ind]); |
---|
107 | else if (!(expand[reqs[ind]] in packages)) |
---|
108 | die("No such package " reqs[ind]); |
---|
109 | } |
---|
110 | } |
---|
111 | |
---|
112 | # Now remove the late packages from the packages list to keep |
---|
113 | # them from being built too soon. |
---|
114 | for (i = 0; i < numlate; i++) |
---|
115 | delete packages[late[i]]; |
---|
116 | |
---|
117 | |
---|
118 | # Do early packages, in order. |
---|
119 | for (i = 0; i < numearly; i++) |
---|
120 | build(early[i]); |
---|
121 | |
---|
122 | # Do normal packages. |
---|
123 | for (pkg in packages) |
---|
124 | build(pkg); |
---|
125 | |
---|
126 | # Do late packages, in order. |
---|
127 | for (i = 0; i < numlate; i++) |
---|
128 | build(late[i]); |
---|
129 | } |
---|