update Mon Mar 15 12:37:00 PDT 2010
[pkgsrc.git] / mk / checksum / distinfo.awk
1 #!/usr/bin/awk -f
2 #
3 # $NetBSD: distinfo.awk,v 1.4 2007/08/16 16:29:27 jlam Exp $
4 #
5 # Copyright (c) 2007 The NetBSD Foundation, Inc.
6 # All rights reserved.
7 #
8 # This code is derived from software contributed to The NetBSD Foundation
9 # by Johnny C. Lam.
10 #
11 # Redistribution and use in source and binary forms, with or without
12 # modification, are permitted provided that the following conditions
13 # are met:
14 # 1. Redistributions of source code must retain the above copyright
15 #    notice, this list of conditions and the following disclaimer.
16 # 2. Redistributions in binary form must reproduce the above copyright
17 #    notice, this list of conditions and the following disclaimer in the
18 #    documentation and/or other materials provided with the distribution.
19 # 3. All advertising materials mentioning features or use of this software
20 #    must display the following acknowledgement:
21 #        This product includes software developed by the NetBSD
22 #        Foundation, Inc. and its contributors.
23 # 4. Neither the name of The NetBSD Foundation nor the names of its
24 #    contributors may be used to endorse or promote products derived
25 #    from this software without specific prior written permission.
26 #
27 # THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 # PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 # POSSIBILITY OF SUCH DAMAGE.
38 #
39
40 ###########################################################################
41 #
42 # NAME
43 #       distinfo.awk -- print distinfo information to standard output
44 #
45 # SYNOPSIS
46 #       distinfo.awk -- [options] [patch ...]
47 #
48 # DESCRIPTION
49 #       distinfo.awk generates distinfo information for the named
50 #       cksumfiles, ignorefiles and patches.  The format of a distinfo
51 #       file is:
52 #
53 #          1. NetBSD RCS ID header
54 #          2. a blank line
55 #          3. digests and size information for each cksumfile and ignorefile
56 #          4. digests for patches
57 #
58 #       For example:
59 #
60 #       $NetBSD: distinfo.awk,v 1.4 2007/08/16 16:29:27 jlam Exp $
61 #
62 #       SHA1 (make-3.81.tar.gz) = cd4fa5a3184176492bf0799593a8f250a728210c
63 #       RMD160 (make-3.81.tar.gz) = a713a72875cb9a29568677c98022465c6f55cbbf
64 #       Size (make-3.81.tar.gz) = 1564560 bytes
65 #       SHA1 (patch-aa) = ba88ee2175c7c2258fc647b3654b2f725cf75a50
66 #       SHA1 (patch-ac) = de18956fde66fa3fc61a991bb3e6724d9c5b1eac
67 #       SHA1 (patch-af) = 067cac366694ce33e5bc52ef937603ae17d3bc2e
68 #
69 # OPTIONS
70 #       The following command line arguments are supported.
71 #
72 #       --              This is a mandatory option and must always be the
73 #                       first option specified.
74 #
75 #       -a algorithm    Generate a digest for the specified distfiles
76 #                       using the named digest algorithm.  If this option
77 #                       is given more than once, then digests are
78 #                       generated using each algorithm in the order
79 #                       given.
80 #
81 #       -c cksumfile    Generate distinfo information for the named
82 #                       cksumfile.  If this option is given more than
83 #                       once, then generate information for each
84 #                       cksumfile in alphabetical order.
85 #
86 #       -d distdir      Directory under which cksumfiles and ignorefiles
87 #                       are found.
88 #
89 #       -f distinfo     Path to an existing distinfo file.  If this
90 #                       option is given, then it is used to provide the
91 #                       distinfo information for either cksumfiles and
92 #                       ignorefiles or patches, depending on which
93 #                       are not given on the command line.  Also, using
94 #                       this option causes the return code to be 0 if
95 #                       the generated distinfo information matches the
96 #                       contents of the existing distinfo file, or
97 #                       non-zero otherwise.
98 #
99 #       -i ignorefile   Generate distinfo information to ignore checksum
100 #                       verification for ignorefile.  If this option is
101 #                       given more than once, then generate information
102 #                       for each ignore file in alphabetical order.
103 #
104 #       -p algorithm    Generate a digest for the patches using the named
105 #                       digest algorithm.  If this option is given more
106 #                       than once, then digests are generated using each
107 #                       algorithm in the order given.
108 #
109 #       patch ...       Generate distinfo information for the named
110 #                       patches in alphabetical order.
111 #
112 ###########################################################################
113
114 BEGIN {
115         DIGEST = ENVIRON["DIGEST"] ? ENVIRON["DIGEST"] : "digest"
116         SED = ENVIRON["SED"] ? ENVIRON["SED"] : "sed"
117         TEST = ENVIRON["TEST"] ? ENVIRON["TEST"] : "test"
118         WC = ENVIRON["WC"] ? ENVIRON["WC"] : "wc"
119
120         self = "distinfo.awk"
121         ARGSTART = 1
122         A = 0           # size of algorithms array
123         D = 0           # size of distfiles array
124         L = 0           # size of lines array
125         P = 0           # size of patch_algorithms array
126         N = 0           # size of patchfiles array
127         F = 0           # size of distinfo_lines array
128
129         distdir = "."
130         distinfo = ""
131         exitcode = 0
132
133         parse_options()
134
135         if (length(distdir) > 0) {
136                 cmd = TEST " -d " distdir
137                 if (system(cmd) != 0) {
138                         print self ": " distdir " not found"
139                         exitcode = 128
140                 }
141         }
142         if (length(distinfo) > 0) {
143                 cmd = TEST " -f " distinfo
144                 if (system(cmd) != 0) {
145                         print self ": " distinfo " not found"
146                         exitcode = 128
147                 }
148                 while(getline < distinfo) { distinfo_lines[F++] = $0 }
149                 close(distinfo)
150         }
151
152         if (exitcode > 0) exit(exitcode)
153
154         if (length(distinfo) == 0) {            # no distinfo file
155                 header()
156                 distsum()
157                 patchsum()
158                 exitcode = 1
159         } else {
160                 if (D > 0 && N > 0) {           # distfiles & patches
161                         header()
162                         distsum()
163                         patchsum()
164                 } else if (D > 0 && N == 0) {   # distfiles only
165                         header()
166                         distsum()
167                         #
168                         # Grab the patch distinfo lines from the existing
169                         # distinfo file.
170                         #
171                         for (l = 0; l < F; l++) {
172                                 file = distinfo_lines[l]
173                                 sub("^[^(]*[(]", "", file)
174                                 sub("[)][^)]*$", "", file)
175                                 if (is_patch(file))
176                                         lines[L++] = distinfo_lines[l]
177                         }
178                 } else if (D == 0 && N > 0) {   # patches only
179                         #
180                         # Grab the non-patch distinfo lines from the
181                         # existing distinfo file.
182                         #
183                         for (l = 0; l < F; l++) {
184                                 file = distinfo_lines[l]
185                                 sub("^[^(]*[(]", "", file)
186                                 sub("[)][^)]*$", "", file)
187                                 if (!is_patch(file))
188                                         lines[L++] = distinfo_lines[l]
189                         }
190                         patchsum()
191                 }
192                 exitcode = is_same_distinfo() ? 0 : 1
193         }
194
195         # Print the new distinfo content to standard output.
196         for (l = 0; l < L; l++) { print lines[l] }
197
198         exit(exitcode)
199 }
200
201 function insertion_sort(a, nelem,        temp, i, j) {
202         for (i = 1; i < nelem; ++i) {
203                 for (j = i; a[j-1] > a[j]; --j) {
204                         temp = a[j]
205                         a[j] = a[j-1]
206                         a[j-1] = temp
207                 }
208         }
209         return
210 }
211
212 function parse_options(         option) {
213         while (ARGSTART < ARGC) {
214                 option = ARGV[ARGSTART]
215                 if (option == "-a") {
216                         algorithms[A++] = ARGV[ARGSTART + 1]
217                         ARGSTART += 2
218                 } else if (option == "-c") {
219                         distfiles[D++] = ARGV[ARGSTART + 1]
220                         cksumfiles[ARGV[ARGSTART + 1]] = 1
221                         ARGSTART += 2
222                 } else if (option == "-d") {
223                         distdir = ARGV[ARGSTART + 1]
224                         ARGSTART += 2
225                 } else if (option == "-f") {
226                         distinfo = ARGV[ARGSTART + 1]
227                         ARGSTART += 2
228                 } else if (option == "-i") {
229                         distfiles[D++] = ARGV[ARGSTART + 1]
230                         ignorefiles[ARGV[ARGSTART + 1]] = 1
231                         ARGSTART += 2
232                 } else if (option == "-p") {
233                         patch_algorithms[P++] = ARGV[ARGSTART + 1]
234                         ARGSTART += 2
235                 } else if (option == "--") {
236                         ARGSTART++
237                         break
238                 } else if (match(option, /^-.*/) != 0) {
239                         option = substr(option, RSTART + 1, RLENGTH)
240                         print self ": unknown option -- " option > "/dev/stderr"
241                         print "usage: " self " -- [-a alg] [-c file] [-d distdir] [-f distinfo] [-i ignore] [-p alg] [patch ...]" > "/dev/stderr"
242                         exit 1
243                 } else {
244                         break
245                 }
246         }
247         while (ARGSTART < ARGC) {
248                 patchfiles[N++] = ARGV[ARGSTART++]
249         }
250
251         # Sort each of the resulting arrays.
252         #insertion_sort(algorithms, A)
253         #insertion_sort(patch_algorithms, P)
254         insertion_sort(distfiles, D)
255         insertion_sort(patchfiles, N)
256 }
257
258 ###
259 ###     header()
260 ###             Pull the NetBSD RCS ID file from the existing distinfo file
261 ###             if it's available, otherwise generate a new one.
262 ###
263 function header() {
264         if (length(distinfo) > 0) {
265                 cmd = SED " 1q " distinfo
266                 cmd | getline; close(cmd)
267                 if ($0 ~ /^[$]NetBSD/) {
268                         lines[L++] = $0
269                         lines[L++] = ""
270                         return
271                 }
272         }
273         lines[L++] = "$" "NetBSD" "$"
274         lines[L++] = ""
275 }
276
277 ###
278 ###     is_patch(file)
279 ###             Return 1 if the file is a valid patch name, or 0 otherwise.
280 ###
281 function is_patch(file) {
282         if (file ~ /^patch-local-|[.]orig$|[.]rej$|~$/) return 0
283         if (file ~ /^patch-|^emul-.*-patch-/) return 1
284         return 0
285 }
286
287 ###
288 ###     distsum()
289 ###             Generate digests using the ones named in the algorithms
290 ###             array, and size information for each cksumfile.  Generate
291 ###             an IGNORE line for each ignorefile.
292 ###
293 function distsum(               alg, file, cmd, a, i) {
294         for (i = 0; i < D; i++) {
295                 file = distfiles[i]
296                 cmd = "cd " distdir " && " TEST " -f " file
297                 if (system(cmd) != 0) continue
298                 for (a = 0; a < A; a++) {
299                         alg = algorithms[a]
300                         if (cksumfiles[file] == 1) {
301                                 cmd = "cd " distdir " && " DIGEST " " alg " " file
302                                 cmd | getline lines[L++]; close(cmd)
303                         } else if (ignorefiles[file] == 1) {
304                                 lines[L++] = alg " (" file ") = IGNORE"
305                         }
306                 }
307                 if (cksumfiles[file] == 1) {
308                         cmd = "cd " distdir " && " WC " -c " file
309                         cmd | getline; close(cmd)
310                         sub("^[ ]+", ""); sub("[ ].*", "")
311                         lines[L++] = "Size (" file ") = " $0 " bytes"
312                 }
313         }
314 }
315
316 ###
317 ###     patchsum()
318 ###             Generate digests using the ones named in patch_algorithms
319 ###             for each patch.
320 ###
321 function patchsum(              alg, dir, file, patch, cmd, a, i) {
322         for (i = 0; i < N; i++) {
323                 patch = patchfiles[i]
324                 dir = patch; sub("/[^/]*$", "", dir)
325                 file = patch; sub("^.*/", "", file)
326                 cmd = TEST " -f " patch
327                 if ((system(cmd) != 0) || !is_patch(file)) continue
328                 for (a = 0; a < P; a++) {
329                         alg = patch_algorithms[a]
330                         cmd = SED " -e '/[$]NetBSD.*/d' " patch " | " DIGEST " " alg
331                         cmd | getline; close(cmd)
332                         sub("^", alg " (" file ") = ")
333                         lines[L++] = $0
334                 }
335         }
336 }
337
338 ###
339 ###     is_same_distinfo()
340 ###             Return 1 if the distinfo_lines and lines array match
341 ###             (so the new distinfo content and the old distinfo
342 ###             content match), and zero otherwise.
343 ###
344 function is_same_distinfo(              l) {
345         if (L != F) { return 0 }
346         for (l = 0; l < L; l++) {
347                 if (distinfo_lines[l] != lines[l])
348                         return 0
349         }
350         return 1
351 }