#!/usr/bin/perl -w # impibe - incrementally add messages from public-inbox V1/V2 to a Maildir # # To the extent possible under law, Leah Neukirchen # has waived all copyright and related or neighboring rights to this work. # # http://creativecommons.org/publicdomain/zero/1.0/ use v5.16; use Sys::Hostname; use File::Glob ':bsd_glob'; use autodie qw(open close); use Fcntl qw(O_WRONLY O_CREAT O_EXCL); if (@ARGV < 2) { die "Usage: $0 PUBLIC-INBOX MAILDIR\n"; } my ($pi, $md) = @ARGV; my $hostname = hostname; my $flags = ""; # default flags for new messages my $status = 0; my %have; for my $mail (bsd_glob("$md/cur/*:2*", GLOB_NOSORT)) { if ($mail =~ /,B=([0-9a-f]{40})/) { $have{$1} = 1; } } sub deliver { my ($repo, $blob, $time) = @_; state $delivery = 0; $delivery++; # Embed the blob hash into the file name so we can check easily # which blobs we have already. my $name = sprintf "%d.P%05dQ%d.%s,B=%s:2,%s", $time, $$, $delivery, $hostname, $blob, $flags; my $tmpmail = "$md/tmp/$name"; my $curmail = "$md/cur/$name"; my $pid = fork; if ($pid == 0) { sysopen(STDOUT, $tmpmail, O_WRONLY | O_CREAT | O_EXCL) or die "$0: couldn't create $tmpmail: $!\n"; exec "git", "-C", "$repo", "cat-file", "blob", $blob or die "$0: couldn't exec git: $!\n"; } else { waitpid $pid, 0; if ($? == 0) { if (rename($tmpmail, $curmail)) { say $curmail; } else { warn "$0: rename failed: $!\n"; $status = 1; } } else { $status = 1; } } } my @repos; if (-f "$pi/HEAD") { # V1 format push @repos, $pi; } else { # V2 format push @repos, bsd_glob("$pi/[0-9]*.git"); unless (@repos) { die "$0: no V2 *.git repositories found.\n"; } } for my $repo (@repos) { open(my $git_fh, "-|", "git", "-C", $repo, qw(log --reverse --raw --format=%H:%at --no-abbrev)); my $time; while (<$git_fh>) { chomp; if (/^[\da-f]{40}:(\d+)$/) { $time = $1; } elsif (/^:\d{6} \d+ [\da-f]+ ([\da-f]{40}) ([AM]\tm$|A\t[\da-f]{2}\/)/) { my $blob = $1; next if $have{$blob}; deliver($repo, $blob, $time); } } close($git_fh); } exit $status;