CPAN-Checksums-2.14/0000755000175000017500000000000014152635307011360 5ustar kkCPAN-Checksums-2.14/lib/0000755000175000017500000000000014152635276012133 5ustar kkCPAN-Checksums-2.14/lib/CPAN/0000755000175000017500000000000014152635276012654 5ustar kkCPAN-Checksums-2.14/lib/CPAN/Checksums.pm0000644000175000017500000003174314152500120015122 0ustar kk# -*- cperl-indent-level: 2 -*- package CPAN::Checksums; use strict; use vars qw( $CAUTION $DIRNAME $IGNORE_MATCH $MIN_MTIME_CHECKSUMS $SIGNING_KEY $SIGNING_PROGRAM $TRY_SHORTNAME $VERSION @EXPORT_OK @ISA ); require Exporter; @ISA = qw(Exporter); @EXPORT_OK = qw(updatedir); $VERSION = "2.14"; $VERSION =~ s/_//; $CAUTION ||= 0; $TRY_SHORTNAME ||= 0; $SIGNING_PROGRAM ||= 'gpg --clearsign --default-key '; $SIGNING_KEY ||= ''; $MIN_MTIME_CHECKSUMS ||= 0; $IGNORE_MATCH = qr{(?i-xsm:readme$)}; use DirHandle (); use IO::File (); use Digest::MD5 (); use Compress::Bzip2(); use Compress::Zlib (); use File::Spec (); use File::Temp; use Data::Dumper (); use Data::Compare (); use Digest::SHA (); sub _dir_to_dref { my($dirname,$old_dref,$root) = @_; my $cpan_path = File::Spec->abs2rel( $dirname, $root ) ; my($dref) = {}; my($dh)= DirHandle->new; my($fh) = new IO::File; $dh->open($dirname) or die "Couldn't opendir $dirname\: $!"; my(%shortnameseen); DIRENT: for my $de ($dh->read) { next DIRENT if $de =~ /^\./; next DIRENT if substr($de,0,9) eq "CHECKSUMS"; next DIRENT if $IGNORE_MATCH && $de =~ $IGNORE_MATCH; my $abs = File::Spec->catfile($dirname,$de); # # SHORTNAME offers an 8.3 name, probably not needed but it was # always there,,, # if ($TRY_SHORTNAME) { my $shortname = lc $de; $shortname =~ s/\.tar[._-]gz$/\.tgz/; my $suffix; ($suffix = $shortname) =~ s/.*\.//; substr($suffix,3) = "" if length($suffix) > 3; my @p; if ($shortname =~ /\-/) { @p = $shortname =~ /(.{1,16})-.*?([\d\.]{2,8})/; } else { @p = $shortname =~ /(.{1,8}).*?([\d\.]{2,8})/; } $p[0] ||= lc $de; $p[0] =~ s/[^a-z0-9]//g; $p[1] ||= 0; $p[1] =~ s/\D//g; my $counter = 7; while (length($p[0]) + length($p[1]) > 8) { substr($p[0], $counter) = "" if length($p[0]) > $counter; substr($p[1], $counter) = "" if length($p[1]) > $counter--; } my $dot = $suffix ? "." : ""; $shortname = "$p[0]$p[1]$dot$suffix"; while (exists $shortnameseen{$shortname}) { my($modi) = $shortname =~ /([a-z\d]+)/; $modi++; $shortname = "$modi$dot$suffix"; if (++$counter > 1000){ # avoid endless loops and accept the buggy choice warn "Warning: long loop on shortname[$shortname]de[$de]"; last; } } $dref->{$de}->{shortname} = $shortname; $shortnameseen{$shortname} = undef; # for exists check good enough } # # STAT facts # if (-l File::Spec->catdir($dirname,$de)){ # Symlinks are a mess on a replicated, database driven system, # but as they are not forbidden, we cannot ignore them. We do # have a directory with nothing but a symlink in it. When we # ignored the symlink, we did not write a CHECKSUMS file and # CPAN.pm issued lots of warnings:-( $dref->{$de}{issymlink} = 1; } if (-d File::Spec->catdir($dirname,$de)){ $dref->{$de}{isdir} = 1; } else { my @stat = stat $abs or next DIRENT; $dref->{$de}{size} = $stat[7]; my(@gmtime) = gmtime $stat[9]; $gmtime[4]++; $gmtime[5]+=1900; $dref->{$de}{mtime} = sprintf "%04d-%02d-%02d", @gmtime[5,4,3]; _add_digests($de,$dref,"Digest::SHA",[256],"sha256",$abs,$old_dref); my $can_reuse_old_md5 = 1; COMPARE: for my $param (qw(size mtime sha256)) { if (!exists $old_dref->{$de}{$param} || $dref->{$de}{$param} ne $old_dref->{$de}{$param}) { $can_reuse_old_md5 = 0; last COMPARE; } } if ($can_reuse_old_md5 and $de =~ /\.(gz|tgz|bz2|tbz)$/ and exists $old_dref->{$de}{md5} and !exists $old_dref->{$de}{"md5-ungz"} and !exists $old_dref->{$de}{"md5-unbz2"} ) { $can_reuse_old_md5 = 0; } if ( $can_reuse_old_md5 ) { MD5KEY: for my $param (qw(md5 md5-ungz md5-unbz2)) { next MD5KEY unless exists $old_dref->{$de}{$param}; $dref->{$de}{$param} = $old_dref->{$de}{$param}; } } else { _add_digests($de,$dref,"Digest::MD5",[],"md5",$abs,$old_dref); } } # ! -d $dref->{$de}{cpan_path} = $cpan_path; } $dh->close; $dref; } sub _read_old_ddump { my($ckfn) = @_; my $is_signed = 0; my($fh) = new IO::File; my $old_ddump = ""; if ($fh->open($ckfn)) { local $/ = "\n"; while (<$fh>) { next if /^\#/; $is_signed = 1 if /SIGNED MESSAGE/; $old_ddump .= $_; } close $fh; } return($old_ddump,$is_signed); } sub updatedir ($;$) { my($dirname, $root) = @_; my $ckfn = File::Spec->catfile($dirname, "CHECKSUMS"); # checksum-file-name my($old_ddump,$is_signed) = _read_old_ddump($ckfn); my($old_dref) = makehashref($old_ddump); my $dref = _dir_to_dref($dirname,$old_dref,$root); local $Data::Dumper::Indent = 1; local $Data::Dumper::Quotekeys = 1; local $Data::Dumper::Sortkeys = 1; my $ddump = Data::Dumper->new([$dref],["cksum"])->Dump; my @ckfnstat = stat $ckfn; if ($old_ddump) { local $DIRNAME = $dirname; if ( !!$SIGNING_KEY == !!$is_signed ) { # either both or neither if (!$MIN_MTIME_CHECKSUMS || $ckfnstat[9] > $MIN_MTIME_CHECKSUMS ) { # recent enough return 1 if $old_ddump eq $ddump; return 1 if ckcmp($old_dref,$dref); } } if ($CAUTION) { my $report = investigate($old_dref,$dref); warn $report if $report; } } my $ft = File::Temp->new( DIR => $dirname, TEMPLATE => "CHECKSUMS.XXXX", CLEANUP => 0, ) or die; my $tckfn = $ft->filename; close $ft; my($fh) = new IO::File; open $fh, ">$tckfn\0" or die "Couldn't open >$tckfn\: $!"; local $\; if ($SIGNING_KEY) { print $fh "0&&<<''; # this PGP-signed message is also valid perl\n"; close $fh; open $fh, "| $SIGNING_PROGRAM $SIGNING_KEY >> $tckfn" or die "Could not call gpg: $!"; $ddump .= "__END__\n"; } my $message = sprintf "# CHECKSUMS file written on %s GMT by CPAN::Checksums (v%s)\n%s", scalar gmtime, $VERSION, $ddump; print $fh $message; my $success = close $fh; if ($SIGNING_KEY && !$success) { warn "Couldn't run '$SIGNING_PROGRAM $SIGNING_KEY'! Writing to $tckfn directly"; open $fh, ">$tckfn\0" or die "Couldn't open >$tckfn\: $!"; print $fh $message; close $fh or warn "Couldn't close $tckfn: $!"; } chmod 0644, $ckfn or die "Couldn't chmod to 0644 for $ckfn\: $!" if -f $ckfn; rename $tckfn, $ckfn or die "Could not rename: $!"; chmod 0444, $ckfn or die "Couldn't chmod to 0444 for $ckfn\: $!"; return 2; } sub _add_digests ($$$$$$$) { my($de,$dref,$module,$constructor_args,$keyname,$abs,$old_dref) = @_; my($fh) = new IO::File; my $dig = $module->new(@$constructor_args); $fh->open("$abs\0") or die "Couldn't open $abs: $!"; binmode($fh); # make sure it's called as a function, solaris with # perl 5.8.4 complained about missing method in # IO::File $dig->addfile($fh); $fh->close; my $digest = $dig->hexdigest; $dref->{$de}{$keyname} = $digest; $dig = $module->new(@$constructor_args); if ($de =~ /\.(gz|tgz)$/) { my($buffer, $zip); if (exists $old_dref->{$de}{$keyname} && $dref->{$de}{$keyname} eq $old_dref->{$de}{$keyname} && exists $old_dref->{$de}{"$keyname-ungz"} ) { $dref->{$de}{"$keyname-ungz"} = $old_dref->{$de}{"$keyname-ungz"}; return; } if ($zip = Compress::Zlib::gzopen($abs, "rb")) { $dig->add($buffer) while $zip->gzread($buffer) > 0; $dref->{$de}{"$keyname-ungz"} = $dig->hexdigest; $zip->gzclose; } } elsif ($de =~ /\.(bz2|tbz)$/) { my($buffer, $zip); if (exists $old_dref->{$de}{$keyname} && $dref->{$de}{$keyname} eq $old_dref->{$de}{$keyname} && exists $old_dref->{$de}{"$keyname-unbz2"} ) { $dref->{$de}{"$keyname-unbz2"} = $old_dref->{$de}{"$keyname-unbz2"}; return; } if ($zip = Compress::Bzip2::bzopen($abs, "rb")) { $dig->add($buffer) while $zip->bzread($buffer) > 0; $dref->{$de}{"$keyname-unbz2"} = $dig->hexdigest; $zip->bzclose; } } } sub ckcmp ($$) { my($old,$new) = @_; for ($old,$new) { $_ = makehashref($_); } Data::Compare::Compare($old,$new); } # see if a file changed but the name not sub investigate ($$) { my($old,$new) = @_; for ($old,$new) { $_ = makehashref($_); } my $complain = ""; for my $dist (sort keys %$new) { if (exists $old->{$dist}) { my $headersaid; for my $diff (qw/md5 sha256 size md5-ungz sha256-ungz mtime/) { next unless exists $old->{$dist}{$diff} && exists $new->{$dist}{$diff}; next if $old->{$dist}{$diff} eq $new->{$dist}{$diff}; $complain .= scalar gmtime(). " GMT:\ndiffering old/new version of same file $dist:\n" unless $headersaid++; $complain .= qq{\t$diff "$old->{$dist}{$diff}" -> "$new->{$dist}{$diff}"\n}; #}; } } } $complain; } sub makehashref ($) { local($_) = shift; unless (ref $_ eq "HASH") { require Safe; my($comp) = Safe->new("CPAN::Checksums::reval"); my $cksum; # used by Data::Dumper $_ = $comp->reval($_) || {}; die "CPAN::Checksums: Caught error[$@] while checking $DIRNAME" if $@; } $_; } 1; __END__ =head1 NAME CPAN::Checksums - Write a C file for a directory as on CPAN =head1 SYNOPSIS use CPAN::Checksums qw(updatedir); my $success = updatedir($directory, $root); =head1 INCOMPATIBILITY ALERT Since version 1.0 the generation of the attribute C is turned off by default. It was too slow and was not used as far as I know, and above all, it could fail on large directories. The shortname feature can still be turned on by setting the global variable $TRY_SHORTNAME to a true value. =head1 DESCRIPTION =over 2 =item $success = updatedir($dir[, $root]) $dir is a directory. Updatedir() writes a C file into that directory, unless a previously written C file is there that is still valid. Returns 2 if a new C file has been written, 1 if a valid C file is already there, otherwise dies. If $root is given, the hash entry with the key C is relative to this root directory. Note: since version 2.0 updatedir on empty directories behaves just the same. In older versions it silently did nothing. =back =head2 Global Variables in package CPAN::Checksums =over =item $IGNORE_MATCH If the global variable $IGNORE_MATCH is set, then all files matching this expression will be completely ignored and will not be included in the CPAN C files. Per default this variable is set to qr{(?i-xsm:readme$)} =item $CAUTION Setting the global variable $CAUTION causes updatedir() to report changes of files in the attributes C, C, C, or C to STDERR. =item $TRY_SHORTNAME By setting the global variable $TRY_SHORTNAME to a true value, you can tell updatedir() to include an attribute C in the resulting hash that is 8.3-compatible. Please note, that updatedir() in this case may be slow and may even fail on large directories, because it will always only try 1000 iterations to find a name that is not yet taken and then give up. =item $SIGNING_KEY Setting the global variable $SIGNING_KEY makes the generated C file to be clear-signed by the command specified in $SIGNING_PROGRAM (defaults to C), passing the signing key as an extra argument. The resulting C file should look like: 0&&<<''; # this PGP-signed message is also valid perl -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 # CHECKSUMS file written on ... by CPAN::Checksums (v...) $cksum = { ... }; __END__ -----BEGIN PGP SIGNATURE----- ... -----END PGP SIGNATURE----- note that the actual data remains intact, but two extra lines are added to make it legal for both OpenPGP and perl syntax. =item $MIN_MTIME_CHECKSUMS If the global variable $MIN_MTIME_CHECKSUMS is set, then updatedir will renew signatures on checksum files that have an older mtime than the given value. =back =head1 PREREQUISITES DirHandle, IO::File, Digest::MD5, Digest::SHA, Compress::Bzip2, Compress::Zlib, File::Spec, Data::Dumper, Data::Compare, File::Temp =head1 BUGS If updatedir is interrupted, it may leave a temporary file lying around. These files have the File::Temp template C and should be harvested by a cronjob. =head1 AUTHOR Andreas Koenig, andreas.koenig@anima.de; GnuPG support by Autrijus Tang =head1 COPYRIGHT & LICENSE Copyright (c) 2002-2008 Andreas Koenig, Audrey Tang, Steve Peters. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO perl(1). =cut CPAN-Checksums-2.14/META.json0000644000175000017500000000267514152635276013020 0ustar kk{ "abstract" : "unknown", "author" : [ "unknown" ], "dynamic_config" : 1, "generated_by" : "ExtUtils::MakeMaker version 7.34, CPAN::Meta::Converter version 2.150010", "keywords" : [ "CPAN infrastructure", "per-directory indexing and signing" ], "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : 2 }, "name" : "CPAN-Checksums", "no_index" : { "directory" : [ "t", "inc" ] }, "prereqs" : { "build" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "configure" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "runtime" : { "requires" : { "Compress::Bzip2" : "0", "Compress::Zlib" : "0", "Data::Compare" : "0", "Data::Dumper" : "0", "Digest::MD5" : "2.36", "Digest::SHA" : "0", "DirHandle" : "0", "File::Spec" : "0", "File::Temp" : "0", "IO::File" : "1.14", "Module::Signature" : "0" } } }, "release_status" : "stable", "resources" : { "repository" : { "type" : "git", "url" : "git://github.com/andk/cpan-checksums.git" } }, "version" : "2.14", "x_serialization_backend" : "JSON::PP version 4.00" } CPAN-Checksums-2.14/META.yml0000644000175000017500000000153114152635276012636 0ustar kk--- abstract: unknown author: - unknown build_requires: ExtUtils::MakeMaker: '0' configure_requires: ExtUtils::MakeMaker: '0' dynamic_config: 1 generated_by: 'ExtUtils::MakeMaker version 7.34, CPAN::Meta::Converter version 2.150010' keywords: - 'CPAN infrastructure' - 'per-directory indexing and signing' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: CPAN-Checksums no_index: directory: - t - inc requires: Compress::Bzip2: '0' Compress::Zlib: '0' Data::Compare: '0' Data::Dumper: '0' Digest::MD5: '2.36' Digest::SHA: '0' DirHandle: '0' File::Spec: '0' File::Temp: '0' IO::File: '1.14' Module::Signature: '0' resources: repository: git://github.com/andk/cpan-checksums.git version: '2.14' x_serialization_backend: 'CPAN::Meta::YAML version 0.018' CPAN-Checksums-2.14/SIGNATURE0000644000175000017500000000533314152635307012650 0ustar kkThis file contains message digests of all files listed in MANIFEST, signed via the Module::Signature module, version 0.87. To verify the content in this distribution, first make sure you have Module::Signature installed, then type: % cpansign -v It will check each file's integrity, as well as the signature's validity. If "==> Signature verified OK! <==" is not displayed, the distribution may already have been compromised, and you should not run its Makefile.PL or Build.PL. -----BEGIN PGP SIGNED MESSAGE----- Hash: RIPEMD160 SHA256 e73f85a1cbb9db2b55fb42c24fc9fff06590ae9696e1066597ac2cd9357b7235 Changes SHA256 c858e5e8997ccc41a294f16c9671b150fead6ec9a158191e5f97018a0241ff00 MANIFEST SHA256 f3b9a999309093e7842f73d131bfc996492e0d324898403644ccf782d98dc8a2 MANIFEST.SKIP SHA256 abca20c6f31d1181e5f63752f6ca65a53fa309a8445042383a78b59f6fda7dbb META.json SHA256 3fa0eaabda5bd7d063a92cf00d10a2bbd3535d7b8a409d750fc15e1eb76784bc META.yml SHA256 0f49bdeca6cf0f013c2256082c8a319e3337d8a7136c4abdde887713a5229d98 Makefile.PL SHA256 f95d80602f31c696996b98d1994ffd80aba8f3292f29b7673f01fa3e504f99de README SHA256 3b714c8edf70cd5eb3b862486f7e3bdcfec748436e840e2363880307de1c0e8d Todo SHA256 2cef02449ea190580a6f5a3296394029b0831d52d4de6c33b9e08605cfd9a705 lib/CPAN/Checksums.pm SHA256 0a7eb8f011b252d11252f9e2629b0509c6031f95564ac2694f9f7b91c1c47d48 t/00signature.t SHA256 787e758a975d04560f6a9d4671646a48c4e9da4f40d4e102bc4562cd15c71ab5 t/42.gz SHA256 0e55092af0746630c98d1b2e0d960617c33f8ea7b55739fd18cb7cd5342a28ca t/43 SHA256 09f646275a0b0622418ed364affe3c2df7dbb02c01862d84d7d06e6b6605c790 t/44.bz2 SHA256 558d9083fe9dfa6aa66806caf4545bee35f2cac36592627aeed3b8cf0ca4fdf2 t/52podcover.t SHA256 6a988cbf3d9a3a26f6b83bf562443343b4d2f510e05f4bbf1496233faf37a9d5 t/CHECKSUMS SHA256 6109dadab614d170fc3db10b00a4c41c221860b1b1085a54af9a5f9f52480494 t/pod.t SHA256 0b20f57520fcbfc97f7fcfee65d6fb155f69c00de6fc161e6d7f2aaa474b22e9 t/updatedir.t -----BEGIN PGP SIGNATURE----- iQIzBAEBAwAdFiEEVMYN6fBgCISqyqMhxSAmq5pABr0FAmGrOr8ACgkQxSAmq5pA Br3KLg/+Jb9IM20UEsoMsly7BIiC4RhAFUaLj4ul/UWf5rMVEXKvq0LMTHXARERa 4aLZsliAr5FoxSHwVjyA6rZKdizznUnkdLyR/cKkvj4AY62dQZjmmw3CVOOa6m5W ruvpFCURtMPkUOsjCqVULTm7p9M+lqO6ZmvqE5wp8GFl6q43v34v4ZQ6A7jCFkSQ rCJQaGD57Z/x37G0/InZcITUYsBy6yWUuOhQOL8kksF0DyIAGMg0YMksxawNeXyx o4az2LbcLcnJAvEtKwH8ENnQaXFZKAuLiPGqIdwhDNlaXSFO3vb821O9117uAu79 auSxksCZbyL/cSOIMZIBkH2XOOAf6GYgzX9zkgizucwhuFB/ioWRri062pj8RXgD ElRMmX0Ni/exUhD6dl1lzYnql7CXRVPZele22VJxKvuDd958zJOsepk2lrwQietm g9X6QEQbOAZlBbH8dAbM9FYWZ0lfM835cBDV1qyW7N/sraNlbgz6V03qr9zMQqRt TKcKzPmycXg1cCqMjqkpg+iG2Q0Ui0gv5NoaUWS4nHuVadXgtwvsfNkbZ1ss0sPa fmc8N9qIYQBd24FmHbzYub0MibPKlbfeejkiN8XwEL01INMACwD+BRvLH1SOGM+x CijzU3MpIlmJ+CuXX2I3LJFzroMaOFKmhAHhumNG9/ZL/L5VGH4= =5Ll9 -----END PGP SIGNATURE----- CPAN-Checksums-2.14/MANIFEST0000644000175000017500000000041314152635276012514 0ustar kkChanges lib/CPAN/Checksums.pm Makefile.PL MANIFEST MANIFEST.SKIP META.yml README SIGNATURE t/00signature.t t/42.gz t/43 t/44.bz2 t/52podcover.t t/CHECKSUMS t/pod.t t/updatedir.t Todo META.json Module JSON meta-data (added by MakeMaker) CPAN-Checksums-2.14/Makefile.PL0000644000175000017500000001303312702112241013314 0ustar kk#!/usr/bin/perl -w -*- mode: cperl -*- use strict; use ExtUtils::MakeMaker qw(:DEFAULT); my $version_diff = 0; # we'll have to die if this becomes true { my $version_from = q(lib/CPAN/Checksums.pm); { local $^W; $ExtUtils::MakeMaker::VERSION = eval $ExtUtils::MakeMaker::VERSION; warn "Your MakeMaker is a bit dated[$ExtUtils::MakeMaker::VERSION].\nYou should get a new one\n" if $ExtUtils::MakeMaker::VERSION < 6.0; } if ($ARGV[0] && $ARGV[0] eq "--setversion") { die "Your perl is a bit dated[$]].\nDo not make a release with it\n" if $] < 5.016; die "Your MakeMaker is a bit dated[$ExtUtils::MakeMaker::VERSION].\nDo not make a release with it\n" if $ExtUtils::MakeMaker::VERSION < 7; die "Your MakeMaker doesn't do the sign woodoo" unless MM->can("signature_target"); shift @ARGV; local $ENV{LANG} = "C"; my $dirty = `git status --porcelain --untracked-files=no`; die "Not everything checked in?" if $dirty; my $version_set_manually = 1; if ($version_set_manually) { # we must control that the VERSION in this .pm is the same as in the Makefile unshift @INC, "lib"; require $version_from; open my $fh, "make the-release-name|" or die; my $have_version; while (<$fh>) { next unless /^version\s+([\d\._]+)/; $have_version = eval $1; } die "could not determine current version from Makefile" unless $have_version; eval q{ no warnings "numeric"; if ($CPAN::Checksums::VERSION != $have_version) { warn "Not equal: CPAN::Checksums::VERSION[$CPAN::Checksums::VERSION] Makefile version[$have_version]"; $version_diff = 1; } }; die $@ if $@; } else { die; } exit unless $version_diff; } } my $prereq_pm = { 'Compress::Bzip2' => 0, 'Compress::Zlib' => 0, 'Data::Compare' => 0, 'Data::Dumper' => 0, 'Digest::MD5' => "2.36", 'Digest::SHA' => 0, 'DirHandle' => 0, 'File::Spec' => 0, 'File::Temp' => 0, 'IO::File' => "1.14", }; for my $interesting_module (qw( Module::Signature )) { eval "require $interesting_module"; if (!$@) { $prereq_pm->{$interesting_module} ||= 0; } } WriteMakefile( 'NAME' => 'CPAN::Checksums', 'VERSION_FROM' => 'lib/CPAN/Checksums.pm', (MM->can("signature_target") ? (SIGN => 1) : ()), 'PREREQ_PM' => $prereq_pm, ($ExtUtils::MakeMaker::VERSION >= 6.3002 ? (LICENSE => "perl") : (), ), 'dist' => { DIST_DEFAULT => join(" ", "verify-changes-date", "verify-changes-version", 'Makefile', "META.yml", "setversion", "README", "all", 'tardist', ), COMPRESS => 'gzip -9f' }, # I took it from RT-CPAN ticket 30098: ($ExtUtils::MakeMaker::VERSION >= 6.4502 ? (META_ADD => { resources => { repository => "git://github.com/andk/cpan-checksums.git", }, keywords => ['CPAN infrastructure','per-directory indexing and signing'], }) : ()), ); if ($version_diff){ die " ==> I had to update some \$VERSIONs <== ==> Your Makefile has been rebuilt. <== ==> Please rerun the make command. <== "; } package MY; sub postamble { q{ setversion: $(PERL) Makefile.PL --setversion Makefile : lib/CPAN/Checksums.pm README: Makefile $(PERL) -MPod::Text -e 'Pod::Text->new->parse_from_file(\*ARGV)' lib/CPAN/Checksums.pm > $@ the-release-name : $(NOECHO) $(ECHO) 'version ' $(VERSION) $(NOECHO) $(ECHO) 'release-name ' $(DISTVNAME).tar$(SUFFIX) release :: disttest ls -l $(DISTVNAME).tar$(SUFFIX) rm -rf $(DISTVNAME) $(NOECHO) $(ECHO) ' git tag -m "This is $(VERSION)" "$(VERSION)"' $(NOECHO) $(ECHO) ' xxx-upload $(DISTVNAME).tar$(SUFFIX)' $(NOECHO) $(ECHO) ' git push --tags' sign: `dirname $(PERL)`/cpansign -s META.yml: metafile $(CP) $(DISTVNAME)/META.yml ./META.yml verify-changes-date: @$(PERL) -ne 'BEGIN{my@t=(localtime)[5,4,3];$$t[0]+=1900;$$t[1]++;$$t=sprintf"%04d-%02d-%02d",@t}' \ -e '$$ok++,exit if /^$$t\s/; END{die "Alert: did not find <$$t> in Changes file" unless $$ok}' Changes verify-changes-version: @$(PERL) -ne '$$ok++,exit if /\b$(VERSION)\b/; END{die "Alert: did not find <$(VERSION)> in Changes file" unless $$ok}' Changes } } sub dist_test { return q{ # if we depend on $(DISTVNAME).tar$(SUFFIX), then the rest of the # Makefile breaks our intent to NOT remake dist disttest : rm -rf $(DISTVNAME) tar xvzf $(DISTVNAME).tar$(SUFFIX) cd $(DISTVNAME) && $(ABSPERLRUN) Makefile.PL cd $(DISTVNAME) && $(MAKE) $(PASTHRU) cd $(DISTVNAME) && $(MAKE) test $(PASTHRU) } } sub distsignature { my($self) = shift; my $ret = $self->SUPER::distsignature_target(@_); $ret =~ s|cpansign|\`dirname \$(PERL)\`/cpansign|g; return $ret; } CPAN-Checksums-2.14/MANIFEST.SKIP0000644000175000017500000000022612512130450013241 0ustar kk_eumm MYMETA.(yml|json) ChangeLog.old DISTS MANIFEST.bak Makefile.old ^Makefile$ \.lwpcookies \.releaserc \.svn/ blib/ pm_to_blib ~$ \.tar\.gz$ \.git CPAN-Checksums-2.14/Changes0000644000175000017500000000564514152543602012661 0ustar kk2021-12-04 k * Version 2.14 * fix test t/updatedir.t for old CPAN versions: we cannot predict the name of the parent directory, so simplify the test; 2021-11-20 k * Version 2.13 * add new key 'cpan_path' to specify the relative path to the well known CPAN directory '/authors/id'. 2016-06-14 k * Version 2.12 * more on #113615: Fix recalc being too lazy (bug analysis by Ralf Neubauer, code by Andreas Koenig) 2016-04-09 k * Version 2.11 * address #113615: extend the production rules for compressed file to .tgz and .tbz. Up to now those did not get a checksum for the uncompress file (requested by Ralf Neubauer) * bump the Module::Signature version that decides whether to test or not to test (Salve J. Nilsen) * never let t/00signature.t actually fail 2015-04-11 k * Version 2.10; no functional change * 00signature.t: survive recent changes in ExtUtils::MakeMaker (_eumm) and in Module::Signature ($ENV{TEST_SIGNATURE}) * add repository address to the Makefile.PL * add Changes file to the MANIFEST 2014-04-04 k * Version 2.09; no functional change * improve test signature.t (Petr PísaÅ™) 2011-08-30 Andreas J. Koenig * Version 2.08; no functional change * survive newest toolchain that creates a MYMETA.json 2010-11-20 Andreas J. Koenig * Version 2.07; no functional change * survive the signature test under bad conditions 2010-10-24 Andreas J. Koenig * Version 2.06 * add MYMETA.yml to MANIFEST.SKIP 2010-01-23 Andreas J. Koenig * Version 2.05 * Addressing the test failure in http://www.nntp.perl.org/group/perl.cpan.testers/2010/01/msg6705220.html 2009-09-28 Andreas J. Koenig * Version 2.04 * Adding a signature verification test. The previous release had two files missing. Signature verification would have notified me. 2009-09-20 Andreas J. Koenig * Version 2.03 * Adding a Copyright statement. Up to now we only had a license but not the copyright statement which makes it difficult for the reader to understand the license. Thanks to Ryan Niebur for bringing this to my attention. 2008-10-31 Andreas J. Koenig * Version 2.02 * Bugfix: call binmode as a function and at the same time demand a newer IO::File as prereq. (addressing http://www.nntp.perl.org/group/perl.cpan.testers/2008/10/msg2516449.html) 2008-09-03 Andreas J. Koenig * Version 2.01 * add missing binmode() for Windows (courtesy Elliot Shank) 2008-05-17 Andreas J. Koenig * Version 2.00 * empty directories can now also get a checksums file. Local Variables: mode: change-log change-log-default-name: "Changes" tab-width: 2 left-margin: 2 End: CPAN-Checksums-2.14/t/0000755000175000017500000000000014152635276011630 5ustar kkCPAN-Checksums-2.14/t/44.bz20000644000175000017500000000004712317424600012463 0ustar kkBZh91AY&SY3:29H !‚,]ÉáB@ÌèÈäCPAN-Checksums-2.14/t/updatedir.t0000644000175000017500000000622714152544724014002 0ustar kk# -*- Mode: cperl; cperl-indent-level: 4 -*- # Before `make install' is performed this script should be runnable with # `make test'. use File::Path qw(mkpath rmtree); use File::Spec; use Test::More; my $HAVE_TIME_HIRES = 0; my $absroot = File::Spec->rel2abs("."); sub _f ($) {File::Spec->catfile(split /\//, shift);} sub _d ($) {File::Spec->catdir(split /\//, shift);} if (eval { require Time::HiRes; 1; }) { $HAVE_TIME_HIRES = 1; } use_ok("CPAN::Checksums"); my $ret = CPAN::Checksums::updatedir("t", $absroot); ok($ret >= 1, "ret[$ret]"); my $warn; { chmod 0644, _f"t/43"; local *F; open F, ">", _f"t/43" or die; print F "4321\n" x 1_000_000; close F; local $CPAN::Checksums::CAUTION; $CPAN::Checksums::CAUTION=1; $SIG{__WARN__} = sub { $warn = shift; }; $ret = CPAN::Checksums::updatedir("t", $absroot); is($ret,2,"changed once"); like($warn,qr/^differing old\/new/m,"warning emitted"); my $start = $HAVE_TIME_HIRES ? Time::HiRes::time() : time; $ret = CPAN::Checksums::updatedir("t", $absroot); my $tooktime = ($HAVE_TIME_HIRES ? Time::HiRes::time() : time) - $start; is($ret,1,"no change tooktime[$tooktime]"); open F, ">", _f"t/43"; print F "43\n"; close F; $warn=""; } $ret = CPAN::Checksums::updatedir("t", $absroot); is($ret,2,"changed again"); is($warn,"","no warning"); my @stat = stat _f"t/CHECKSUMS"; sleep 2; $ret = CPAN::Checksums::updatedir("t", $absroot); is($ret,1,"no change"); my @stat2 = stat _f"t/CHECKSUMS"; for my $s (0..7,9..11) { # 8==atime not our business; 12==blocks may magically change is($stat[$s],$stat2[$s],"unchanged stat element $s"); } mkpath _d"t/emptydir"; $ret = CPAN::Checksums::updatedir(_d"t/emptydir", $absroot); is($ret,2,"empty dir gives also 2"); ok(-f _f"t/emptydir/CHECKSUMS", "found the checksums file"); { rename _d"t/emptydir", _d"t/tdir" or die "Could not rename: $!"; $ret = CPAN::Checksums::updatedir(_d"t/tdir", $absroot); is($ret,1,"after a rename gives 1"); open my $fh, ">", _f"t/tdir/1"; print $fh "1"; close $fh or die "Could not close: $!"; open $fh, ">", _f"t/tdir/2"; print $fh "2\n"; close $fh or die "Could not close: $!"; $ret = CPAN::Checksums::updatedir(_d"t/tdir", $absroot); is($ret,2,"tdir with files returns 2"); my $checksums = do { open $fh, "<", _f"t/tdir/CHECKSUMS" or die "Could not open: $!"; local $/; <$fh> }; my $cksum; eval $checksums; ok exists $cksum->{1}, "checksums file contains file 1"; is $cksum->{1}{size}, 1, "size of file 1 is 1"; like $cksum->{1}{cpan_path}, qr{t/tdir$}, "cpan_path is as expected" or diag explain $cksum; ok exists $cksum->{2}, "checksums file contains file 2"; is $cksum->{2}{size}, 2, "size of file 2 is 2"; unlink, _f"t/tdir/2"; $ret = CPAN::Checksums::updatedir(_d"t/tdir", $absroot); is($ret,1,"tdir with one deleted file returns 1"); @stat = stat _f"t/tdir/CHECKSUMS"; $CPAN::Checksums::MIN_MTIME_CHECKSUMS = $stat[9]+1; $ret = CPAN::Checksums::updatedir(_d"t/tdir", $absroot); is($ret,2,"tdir with bumped minimum mtime returns 2"); } rmtree _d"t/tdir"; done_testing(); CPAN-Checksums-2.14/t/pod.t0000644000175000017500000000023012317424600012556 0ustar kk# -*- mode: cperl -*- use Test::More; eval "use Test::Pod 1.00"; plan skip_all => "Test::Pod 1.00 required for testing POD" if $@; all_pod_files_ok(); CPAN-Checksums-2.14/t/00signature.t0000644000175000017500000000565614146225654014170 0ustar kk# -*- mode: cperl -*- use strict; BEGIN { sub find_exe { my($exe,$path) = @_; my($dir); #warn "in find_exe exe[$exe] path[@$path]"; for $dir (@$path) { my $abs = File::Spec->catfile($dir,$exe); require ExtUtils::MakeMaker; if (($abs = MM->maybe_command($abs))) { return $abs; } } } my $found_prereq = 0; unless ($found_prereq) { $found_prereq = eval { require Digest::SHA; 1 }; } unless ($found_prereq) { $found_prereq = eval { require Digest::SHA1; 1 }; } unless ($found_prereq) { $found_prereq = eval { require Digest::SHA::PurePerl; 1 }; } my $exit_message = ""; unless ($found_prereq) { $exit_message = "None of the supported SHA modules (Digest::SHA,Digest::SHA1,Digest::SHA::PurePerl) found"; } unless ($exit_message) { if (!-f 'SIGNATURE') { $exit_message = "No signature file"; } } unless ($exit_message) { if (!-s 'SIGNATURE') { $exit_message = "Empty signature file"; } } unless ($exit_message) { if (eval { require Module::Signature; 1 }) { my $min = "0.79"; # heya. Just found that CPAN::Checksum fails it's t/00signature.t # test if Module::Signature is version 0.68. if ($Module::Signature::VERSION < $min-0.0000001) { $exit_message = "Signature testing disabled for Module::Signature versions < $min"; } } else { $exit_message = "No Module::Signature found [INC = @INC]"; } } unless ($exit_message) { if (!eval { use Socket qw(AF_INET SOCK_STREAM pack_sockaddr_in inet_aton); my $socket; socket($socket, AF_INET, SOCK_STREAM, 0) and connect( $socket, pack_sockaddr_in( scalar getservbyname('hkp', 'tcp'), inet_aton('pgpkeys.eu') ) ) and close($socket) }) { $exit_message = "Cannot connect to the keyserver"; } } unless ($exit_message) { require Config; my(@path) = split /$Config::Config{'path_sep'}/, $ENV{'PATH'}; if (!find_exe('gpg',\@path)) { $exit_message = "Signature testing disabled without gpg program available"; } } if ($exit_message) { $|=1; print "1..0 # SKIP $exit_message\n"; eval "require POSIX; 1" and POSIX::_exit(0); } } $ENV{TEST_SIGNATURE} = 1; if (Module::Signature::verify() == Module::Signature::SIGNATURE_OK()) { print "1..1\n"; print "ok 1 # Valid signature\n"; } else { print "1..0 # SKIP verify failed, so only collect diagnostics\n"; } # Local Variables: # mode: cperl # cperl-indent-level: 4 # End: CPAN-Checksums-2.14/t/52podcover.t0000644000175000017500000000106712317424600013775 0ustar kk# -*- mode: cperl -*- use Test::More; eval "use 5.00504"; plan skip_all => "perl 5.00504 required for this test" if $@; eval "use Test::Pod::Coverage 0.18"; # 0.15 was misbehaving according to David Cantrell plan skip_all => "Test::Pod::Coverage 0.18 required for testing pod coverage" if $@; plan tests => 1; my $trustme = { trustme => [ qw{ ckcmp investigate makehashref }] }; pod_coverage_ok( "CPAN::Checksums", $trustme ); CPAN-Checksums-2.14/t/42.gz0000644000175000017500000000003212317424600012376 0ustar kk‹Þ3:4231â1)†ÑCPAN-Checksums-2.14/t/430000644000175000017500000000000314152634740011765 0ustar kk43 CPAN-Checksums-2.14/t/CHECKSUMS0000444000175000017500000000444214152634740013075 0ustar kk# CHECKSUMS file written on Sat Dec 4 09:50:24 2021 GMT by CPAN::Checksums (v2.14) $cksum = { '00signature.t' => { 'cpan_path' => 't', 'md5' => '9cf677f32e958d6b4f869387bb6b2f89', 'mtime' => '2021-11-20', 'sha256' => '0a7eb8f011b252d11252f9e2629b0509c6031f95564ac2694f9f7b91c1c47d48', 'size' => 2990 }, '42.gz' => { 'cpan_path' => 't', 'md5' => '915cdde7181ab542763969e063b7a9a9', 'md5-ungz' => '50a2fabfdd276f573ff97ace8b11c5f4', 'mtime' => '2014-04-04', 'sha256' => '787e758a975d04560f6a9d4671646a48c4e9da4f40d4e102bc4562cd15c71ab5', 'sha256-ungz' => '084c799cd551dd1d8d5c5f9a5d593b2e931f5e36122ee5c793c1d08a19839cc0', 'size' => 26 }, '43' => { 'cpan_path' => 't', 'md5' => 'f0287f33eba7192e2a9c6a14f829aa1a', 'mtime' => '2021-12-04', 'sha256' => '0e55092af0746630c98d1b2e0d960617c33f8ea7b55739fd18cb7cd5342a28ca', 'size' => 3 }, '44.bz2' => { 'cpan_path' => 't', 'md5' => 'b3c551bfbf1d15ce93b47346a11cc87a', 'md5-unbz2' => 'e760668b6273d38c832c153fde5725da', 'mtime' => '2014-04-04', 'sha256' => '09f646275a0b0622418ed364affe3c2df7dbb02c01862d84d7d06e6b6605c790', 'sha256-unbz2' => 'b1ce0aa6fdf3cf349d773243dab9fbbe09d30619f38b0c1e8977e28c4f0bc495', 'size' => 39 }, '45.tgz' => { 'cpan_path' => 't', 'md5' => '451f5c94254854f9b50e0e0d815efc25', 'md5-ungz' => '40b724cf2b5b077219e99409e33f233f', 'mtime' => '2021-12-03', 'sha256' => '00a153865e3f7bd5dd0627767a1763404d36fa34793db95ba6d403530d09cdfd', 'sha256-ungz' => '75e63a955767ae72abf0675e666ae6f3774dce667cb3503d5af6b936ae05a785', 'size' => 115 }, '52podcover.t' => { 'cpan_path' => 't', 'md5' => '9845f6c5f049d637c92ae34e67328c77', 'mtime' => '2014-04-04', 'sha256' => '558d9083fe9dfa6aa66806caf4545bee35f2cac36592627aeed3b8cf0ca4fdf2', 'size' => 567 }, 'pod.t' => { 'cpan_path' => 't', 'md5' => '45b17e11a9736a0c485f861f95f063b9', 'mtime' => '2014-04-04', 'sha256' => '6109dadab614d170fc3db10b00a4c41c221860b1b1085a54af9a5f9f52480494', 'size' => 152 }, 'updatedir.t' => { 'cpan_path' => 't', 'md5' => 'ae0611d75e829ff8e7b873787e93a81b', 'mtime' => '2021-12-04', 'sha256' => '0b20f57520fcbfc97f7fcfee65d6fb155f69c00de6fc161e6d7f2aaa474b22e9', 'size' => 3223 } }; CPAN-Checksums-2.14/Todo0000644000175000017500000000257112317424600012206 0ustar kk2009-09-20 Andreas J. Koenig * Ryan Niebur sent me a note that we have no copyright information in the whole package. So although I have LICENSE stuff in the Makefile.PL, the copyrigth escaped me somehow. How many other distros will have this deficiency! "In Debian we need copyright/license information for all of the packages we upload. Could you give us (replying to this email is fine): years of copyright, copyright holders' names, copyright holders' e-mail addresses. Unfortunately without this information we cannot upload it." That's only Audrey and Steve Peters and me. 2005-12-11 Andreas Koenig * running updateddir on all 4012 checksummed directories on CPAN takes a hell lot of time (over an hour) and slows other processes down, so I wonder where the time is spent. If it were ungzip, we could lax our interest to only computing it for files that have a new ungzip checksum or so ($SKIP_UNGZ_IF_GZ_UNCHANGED or so). But if we can make sure that updatedir is always run after a change (both upload and delete), we can run the whole find/update thing just once a week. For now I have reduced it to every 6 hours so I can investigate changes better. ######################################################################### Local Variables: mode: change-log change-log-default-name: "Todo" tab-width: 2 left-margin: 2 End: CPAN-Checksums-2.14/README0000644000175000017500000000732414152635276012253 0ustar kkNAME CPAN::Checksums - Write a "CHECKSUMS" file for a directory as on CPAN SYNOPSIS use CPAN::Checksums qw(updatedir); my $success = updatedir($directory, $root); INCOMPATIBILITY ALERT Since version 1.0 the generation of the attribute "shortname" is turned off by default. It was too slow and was not used as far as I know, and above all, it could fail on large directories. The shortname feature can still be turned on by setting the global variable $TRY_SHORTNAME to a true value. DESCRIPTION $success = updatedir($dir[, $root]) $dir is a directory. Updatedir() writes a "CHECKSUMS" file into that directory, unless a previously written "CHECKSUMS" file is there that is still valid. Returns 2 if a new "CHECKSUMS" file has been written, 1 if a valid "CHECKSUMS" file is already there, otherwise dies. If $root is given, the hash entry with the key "cpan_path" is relative to this root directory. Note: since version 2.0 updatedir on empty directories behaves just the same. In older versions it silently did nothing. Global Variables in package CPAN::Checksums $IGNORE_MATCH If the global variable $IGNORE_MATCH is set, then all files matching this expression will be completely ignored and will not be included in the CPAN "CHECKSUMS" files. Per default this variable is set to qr{(?i-xsm:readme$)} $CAUTION Setting the global variable $CAUTION causes updatedir() to report changes of files in the attributes "size", "mtime", "md5", or "md5-ungz" to STDERR. $TRY_SHORTNAME By setting the global variable $TRY_SHORTNAME to a true value, you can tell updatedir() to include an attribute "shortname" in the resulting hash that is 8.3-compatible. Please note, that updatedir() in this case may be slow and may even fail on large directories, because it will always only try 1000 iterations to find a name that is not yet taken and then give up. $SIGNING_KEY Setting the global variable $SIGNING_KEY makes the generated "CHECKSUMS" file to be clear-signed by the command specified in $SIGNING_PROGRAM (defaults to "gpg --clearsign --default-key "), passing the signing key as an extra argument. The resulting "CHECKSUMS" file should look like: 0&&<<''; # this PGP-signed message is also valid perl -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 # CHECKSUMS file written on ... by CPAN::Checksums (v...) $cksum = { ... }; __END__ -----BEGIN PGP SIGNATURE----- ... -----END PGP SIGNATURE----- note that the actual data remains intact, but two extra lines are added to make it legal for both OpenPGP and perl syntax. $MIN_MTIME_CHECKSUMS If the global variable $MIN_MTIME_CHECKSUMS is set, then updatedir will renew signatures on checksum files that have an older mtime than the given value. PREREQUISITES DirHandle, IO::File, Digest::MD5, Digest::SHA, Compress::Bzip2, Compress::Zlib, File::Spec, Data::Dumper, Data::Compare, File::Temp BUGS If updatedir is interrupted, it may leave a temporary file lying around. These files have the File::Temp template "CHECKSUMS.XXXX" and should be harvested by a cronjob. AUTHOR Andreas Koenig, andreas.koenig@anima.de; GnuPG support by Autrijus Tang COPYRIGHT & LICENSE Copyright (c) 2002-2008 Andreas Koenig, Audrey Tang, Steve Peters. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. SEE ALSO perl(1).