about summary refs log tree commit homepage
path: root/lib/PublicInbox/Xapcmd.pm
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2019-05-23 09:36:43 +0000
committerEric Wong <e@80x24.org>2019-05-23 17:43:50 +0000
commit7e56f47848127b65979c786595244a552b164b3d (patch)
tree6edd36880c7b183dfd381376b290cf163aff1f4e /lib/PublicInbox/Xapcmd.pm
parent792c643ba76e8b06ae17d3653402d381f59857c2 (diff)
downloadpublic-inbox-7e56f47848127b65979c786595244a552b164b3d.tar.gz
Port public-inbox-compact(1) over to using it, and we will need
to wrap copydatabase(1) to ease glass migrations, too.
Diffstat (limited to 'lib/PublicInbox/Xapcmd.pm')
-rw-r--r--lib/PublicInbox/Xapcmd.pm65
1 files changed, 65 insertions, 0 deletions
diff --git a/lib/PublicInbox/Xapcmd.pm b/lib/PublicInbox/Xapcmd.pm
new file mode 100644
index 00000000..586d7e6a
--- /dev/null
+++ b/lib/PublicInbox/Xapcmd.pm
@@ -0,0 +1,65 @@
+# Copyright (C) 2018-2019 all contributors <meta@public-inbox.org>
+# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
+package PublicInbox::Xapcmd;
+use strict;
+use warnings;
+use PublicInbox::Spawn qw(which spawn);
+use PublicInbox::Over;
+use File::Temp qw(tempdir);
+use File::Path qw(remove_tree);
+
+sub commit_changes ($$$) {
+        my ($im, $old, $new) = @_;
+        my @st = stat($old) or die "failed to stat($old): $!\n";
+
+        my $over = "$old/over.sqlite3";
+        if (-f $over) {
+                $over = PublicInbox::Over->new($over);
+                $over->connect->sqlite_backup_to_file("$new/over.sqlite3");
+        }
+        rename($old, "$new/old") or die "rename $old => $new/old: $!\n";
+        chmod($st[2] & 07777, $new) or die "chmod $old: $!\n";
+        rename($new, $old) or die "rename $new => $old: $!\n";
+        $im->lock_release;
+        remove_tree("$old/old") or die "failed to remove $old/old: $!\n";
+}
+
+sub run {
+        my ($ibx, $cmd) = @_;
+        my $dir = $ibx->{mainrepo} or die "no mainrepo in inbox\n";
+        which($cmd->[0]) or die "$cmd->[0] not found in PATH\n";
+        $ibx->umask_prepare;
+        my $old = $ibx->search->xdir(1);
+        -d $old or die "$old does not exist\n";
+        my $new = tempdir($cmd->[0].'-XXXXXXXX', CLEANUP => 1, DIR => $dir);
+        my $v = $ibx->{version} || 1;
+        my @cmds;
+        if ($v == 1) {
+                push @cmds, [@$cmd, $old, $new];
+        } else {
+                opendir my $dh, $old or die "Failed to opendir $old: $!\n";
+                while (defined(my $dn = readdir($dh))) {
+                        if ($dn =~ /\A\d+\z/) {
+                                push @cmds, [@$cmd, "$old/$dn", "$new/$dn"];
+                        } elsif ($dn eq '.' || $dn eq '..') {
+                        } elsif ($dn =~ /\Aover\.sqlite3/) {
+                        } else {
+                                warn "W: skipping unknown dir: $old/$dn\n"
+                        }
+                }
+                die "No Xapian parts found in $old\n" unless @cmds;
+        }
+        my $im = $ibx->importer(0);
+        $ibx->with_umask(sub {
+                $im->lock_acquire;
+                my %pids = map {; spawn($_) => join(' ', @$_) } @cmds;
+                while (scalar keys %pids) {
+                        my $pid = waitpid(-1, 0);
+                        my $desc = delete $pids{$pid};
+                        die "$desc failed: $?\n" if $?;
+                }
+                commit_changes($im, $old, $new);
+        });
+}
+
+1;