replace with a perl script

- runs cksum just once per file
- optionally uses an sqlite db to store already seen files.
This commit is contained in:
espie 2011-09-04 17:01:19 +00:00
parent 3ae3bf0720
commit edfba53503

View File

@ -1,35 +1,121 @@
#! /bin/sh
# $OpenBSD: link-checksums,v 1.2 2010/09/08 11:06:12 espie Exp $
# Written by Marc Espie, 2000
# Public domain
#! /usr/bin/perl
# Sets up hard links under a distfiles mirror, so that
# files will be preserved against checksum changes as a last
# ditch attempt.
# ex:ts=8 sw=4:
# $OpenBSD: link-checksums,v 1.3 2011/09/04 17:01:19 espie Exp $
#
# Copyright (c) 2011 Marc Espie <espie@openbsd.org>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
# Also see REFETCH in bsd.port.mk, and mirroring-ports (7)
eval 'exec perl $0 "$@"'
if 0;
DISTDIR=${DISTDIR:-/usr/ports/distfiles}
cd ${DISTDIR}
CIPHERS=${CIPHERS:-sha1 md5 rmd160 sha256}
use warnings;
use strict;
use File::Find;
use File::Path;
bdir=by_cipher
# Build the find so that existing cipher dirs are avoided
exclude="-type d -name $bdir -prune"
for ci in ${CIPHERS}
do
exclude="${exclude} -o -type d -name $ci -prune"
done
echo "find . \( $exclude \) -o -type f -print"
find . \( $exclude \) -o -type f -print | while read i
do
file=`basename $i`
for ci in ${CIPHERS}
do
result=`cksum -a $ci -b <$i`
res=`echo $result|sed -e 's,\(..\).*,\1,'`
dir=$bdir/$ci/$res/$result
mkdir -p $dir
ln -f $i $dir/$file
done
done
sub create_tables
{
my $db = shift;
}
my $distdir = $ENV{DISTDIR} // '/usr/ports/distfiles';
my $ciphers = $ENV{CIPHERS} // 'sha1 md5 rmd160 sha256';
my ($stat, $stat2) = (0, 0);
my ($db, $update, $check);
# set up DB if wanted (requires DBD::SQLite)
if (defined $ENV{CIPHER_CACHE}) {
require DBI;
$db = DBI->connect("dbi:SQLite:dbname=$ENV{CIPHER_CACHE}", '', '');
$db->do(q{CREATE TABLE IF NOT EXISTS
KNOWN(NAME TEXT PRIMARY KEY, TS INTEGER)});
$check = $db->prepare(q{SELECT TS FROM KNOWN WHERE NAME LIKE (?)});
$update = $db->prepare(q{INSERT OR REPLACE INTO KNOWN
(NAME, TS) VALUES (?, ?)});
}
my @ciphers = split(/\s+/, $ciphers);
my %ciphers = map {$_, 1} @ciphers;
find(sub {
# don't recurse down own results
if (-d $_) {
if ($_ eq 'by_cipher' || $ciphers{$_}) {
$File::Find::prune = 1;
}
return;
}
# avoid DPB partial fetches
return if m/\.part$/;
$stat++;
# avoid rechecksumming
my ($ts, $filename);
if (defined $db) {
$ts = (stat _)[9];
$filename = $File::Find::name;
$filename =~ s/^\Q$distdir\E\///;
$check->execute($filename);
my $a = $check->fetchrow_arrayref;
if (defined $a) {
return if $a->[0] == $ts;
}
}
# compute all checksums in one pipe
$stat2++;
my $pid = open(my $pipe, '-|');
die "Can't fork: $!" if !defined $pid;
if ($pid == 0) {
close STDIN;
open STDIN, '<', $_;
exec {'cksum'} ('cksum', '-a', join(',', @ciphers), '-b');
exit 1;
}
# and grab results in order
my @list = @ciphers;
while (defined(my $result = <$pipe>)) {
my $ci = shift @list;
chomp $result;
if ($result =~ m/^(..)/) {
my $target = "by_cipher/$ci/$1/$result";
File::Path::make_path($target);
next if -f "$target/$_";
link $_, "$target/$_" or die "link: $!";
} else {
die "Bad result $result";
}
}
if (@list != 0) {
die "Error: missing checksum for $File::Find::name";
}
if (!close $pipe) {
die "cksum aborted: $?";
}
if (defined $db) {
$update->execute($filename, $ts);
}
}, $distdir);
print "$stat files seen";
if (defined $db) {
print ", of which $stat2 new files\n";
} else {
print "\n";
}