App-tpnotify
view release on metacpan or search on metacpan
$archive_file = download($source);
info("scanning $archive_file") if $verbose;
open(my $fd, '-|', "tar tf $archive_file")
or abend(EX_NOINPUT, "can't open $archive_file: $!");
while (<$fd>) {
chomp;
unless (m#^(?<dir>.+?)/(?<file>.*)$#) {
abend(EX_DATAERR, "$archive_file content suspicious: member $_");
}
if (defined($topdir)) {
unless ($+{dir} eq $topdir) {
abend(EX_DATAERR,
"$archive_file content suspicious: $+{dir} does not match $topdir");
}
} else {
$topdir = $+{dir};
}
my $f = $+{file};
if ($f eq 'configure.ac' || $f =~ m#po/.*\.pot#) {
$files{$f} = $_;
}
}
close $fd;
info("top level directory: $topdir") if $verbose;
# Verify available files
unless (exists($files{'configure.ac'})) {
abend(EX_DATAERR, "no configure.ac in $archive_file");
}
unless (keys(%files) > 1) {
abend(EX_DATAERR, "no potfile in $archive_file");
}
my $filelist = join(' ', values(%files));
info("extracting from $archive_file") if $verbose;
my $cmd = "tar xf $archive_file $filelist";
system($cmd);
check_command_status($cmd);
}
# check_command_status($STAT)
# ---------------------------
# Handles the result of the system or wait function call.
sub check_command_status {
my $cmd = shift;
my $status = shift || $?;
if ($status == -1) {
abend(EX_OSERR, "failed to run $cmd");
} elsif ($status & 127) {
abend(EX_UNAVAILABLE, "$cmd exited on signal " . ($status & 127));
} elsif (my $e = ($status >> 8)) {
abend(EX_UNAVAILABLE, "$cmd exited with status $e");
}
}
# verify
# ------
# Verifies the tarball. Determines canonical package name, extracts the POT
# file and checks if it lists the correct package name in its
# "Project-Id-Version" header and that its msgids differ from the ones
# already registered on the TP.
sub verify {
my ($in, $out);
my $pid = open2($out, $in, "m4 -P - $files{'configure.ac'}")
or abend(EX_NOINPUT, "can't open $files{'configure.ac'}: $!");
print $in <<'EOT';
m4_divert(-1)
m4_changequote([,])
m4_define([AC_INIT],[m4_divert(0)$1
$2[]m4_divert(-1)])
EOT
close $in;
waitpid($pid, 0);
check_command_status("m4");
chomp(my @lines = <$out>);
abend(EX_DATAERR, "can't parse $files{'configure.ac'}")
unless $#lines == 1;
($package_name, $package_version) = @lines;
$package_tarname = $package_name;
$package_tarname =~ s/GNU\s+//;
$package_tarname = lc $package_tarname; # FIXME: this is not always right,
# perhaps
info("package $package_name, tarname $package_tarname, version $package_version") if $verbose;
$package_base = "$package_tarname-$package_version";
unless (defined($release_type)) {
if ($package_version =~ m/\d+\.\d+\.(\d+)/ && int($1) >= 90) {
$release_type = 'alpha';
} else {
$release_type = 'stable';
}
}
if (substr($archive_file, 0, length($package_base)) ne $package_base) {
abend(EX_DATAERR,
"filename $archive_file does not begin with $package_base");
}
if ($package_base ne $topdir) {
abend(EX_DATAERR,
"toplevel directory $topdir does not begin with $package_base");
}
my $potfile = "po/$package_tarname.pot";
unless ($files{$potfile}) {
abend(EX_DATAERR, "potfile $potfile not found in archive");
}
verify_potfile($files{$potfile});
}
# po_header($FILENAME)
# --------------------
# Extract the PO header from the POT file $FILENAME.
# Returns a reference to a hash: header-name => value.
sub po_header {
my $name = shift;
(my $h = Locale::PO->load_file_asarray($name)->[0]->msgstr)
=~ s/^"(.*)"$/$1/;
my %ret;
foreach my $s (split /\\n/, $h) {
if ($s =~ /^(.+?):\s*(.*)$/) {
$ret{lc $1}=$2;
}
}
\%ret;
}
# po_serialize($FILENAME)
# -----------------------
# Serializes the pot file in the unambiguous way.
# Extracts the msgids, sorts them lexicographically and concatenates them.
sub po_serialize {
my $name = shift;
join("\n", sort map { ($_->msgid // '') . ':' . ($_->msgid_plural // '') } @{Locale::PO->load_file_asarray($name)});
}
# po_cmp($A, $B)
# --------------
# Compares two POT files. Returns 'true' if the two files contain exactly
# the same set of msgids.
sub po_cmp {
my ($a,$b) = @_;
po_serialize($a) eq po_serialize($b);
}
# verify_potfile($FILENAME)
# -------------------------
# Verifies the potfile extracted from the archive.
# Checks if the POT file mentions the correct package string in its
# Project-Id-Version header. Downloads the POT file registered on the
# TP and makes sure its msgids are not the same as defined in the POT
# file from the archive.
sub verify_potfile {
my $potname = shift;
my $hdr = po_header($potname);
my $vs = $hdr->{'project-id-version'};
if ($vs ne "$package_name $package_version") {
err("$potname: Project-Id-Version does not match \"$package_name $package_version\"");
exit(EX_DATAERR) unless $force_option;
}
(my $url = $tp_url) =~ s/\$\{domain\}/$package_tarname/;
download($url, dest => \my $content);
if ($content =~ m{$pot_regex_str}) {
my $tp_potname = download($1);
if (po_cmp($potname, $tp_potname)) {
err("potfile contains no new msgids; no need to upload");
exit(0) unless $force_option;
}
}
}
# Reads the signature file from $signature_file.
sub read_signature {
if (defined($signature_file)) {
if (open(my $fd, '<', $signature_file)) {
local $/;
chomp(my $sig = <$fd>);
close($fd);
return $sig;
}
}
return undef;
}
# Expands the message template.
# Returns the expanded text. Abends on failure.
sub expand_template {
my $cpt = new Safe;
$cpt->share(qw($sender
$fullname
$localdomain
$recipient
$archive_file
$archive_url
$package_name
$package_version
$package_base
$release_type
$topdir
$signature));
${$cpt->varglob('signature')} = read_signature;
(my $tmpl = $template) =~ s/\@/\\\@/g;
if ($cpt->reval("\$_ = qq{$tmpl}",1)) {
return $_;
} else {
abend(EX_DATAERR, "while expanding template: $@");
}
}
# Reads the current value of the MH Path setting.
sub read_mh_path {
my $file = File::Spec->catfile($ENV{HOME}, '.mh_profile');
if (-f $file) {
if (open(my $fd, '<', $file)) {
my $prev;
while (<$fd>) {
chomp;
if (s/^\s+//) {
$prev .= ' ' . $_;
} else {
last if defined($prev) && $prev =~ /^Path:/;
$prev = $_;
}
}
( run in 1.354 second using v1.01-cache-2.11-cpan-5735350b133 )