]> git.ipfire.org Git - thirdparty/public-inbox.git/commitdiff
cfgwrite: new module to batch commit writes
authorEric Wong <e@80x24.org>
Sat, 15 Feb 2025 11:10:09 +0000 (11:10 +0000)
committerEric Wong <e@80x24.org>
Mon, 17 Feb 2025 20:09:09 +0000 (20:09 +0000)
Hoisting git config writing code into a separate module will
make it easier to use libgit2 to avoid process spawning overhead
in a future change.

MANIFEST
lib/PublicInbox/CfgWr.pm [new file with mode: 0644]
lib/PublicInbox/LeiMirror.pm
lib/PublicInbox/LeiSavedSearch.pm
lib/PublicInbox/MultiGit.pm
script/public-inbox-init

index 2ca7755ce46b2e5fb302f0a99682b94e89d96883..f0b42826a2b04c227ec059137b51ec53d110ca4a 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -164,6 +164,7 @@ lib/PublicInbox/AdminEdit.pm
 lib/PublicInbox/AltId.pm
 lib/PublicInbox/Aspawn.pm
 lib/PublicInbox/AutoReap.pm
+lib/PublicInbox/CfgWr.pm
 lib/PublicInbox/Cgit.pm
 lib/PublicInbox/CidxComm.pm
 lib/PublicInbox/CidxLogP.pm
diff --git a/lib/PublicInbox/CfgWr.pm b/lib/PublicInbox/CfgWr.pm
new file mode 100644 (file)
index 0000000..2b3fd50
--- /dev/null
@@ -0,0 +1,54 @@
+# Copyright (C) all contributors <meta@public-inbox.org>
+# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
+
+# config writer, may use libgit2 in the future
+package PublicInbox::CfgWr;
+use v5.12;
+use PublicInbox::Git qw(git_exe);
+use PublicInbox::Spawn qw(run_die run_wait);
+
+sub new {
+       my ($cls, $f) = @_;
+       bless { -f => $f }, $cls;
+}
+
+sub set {
+       my ($self, $k, $v) = @_;
+       push @{$self->{todo}}, [ $k, $v ];
+       $self;
+}
+
+sub add {
+       my ($self, $k, $v) = @_;
+       push @{$self->{todo}}, [ '--add', $k, $v ];
+       $self;
+}
+
+sub replace_all {
+       my ($self, $k, $v, $re) = @_;
+       push @{$self->{todo}}, [ '--replace-all', $k, $v, $re ];
+       $self;
+}
+
+sub unset_all {
+       my ($self, $k) = @_;
+       push @{$self->{todo}}, [ '--unset-all', $k ];
+       $self;
+}
+
+sub commit {
+       my ($self, $opt) = @_;
+       my @x = (git_exe, 'config', '-f', $self->{-f});
+       for my $c (@{delete $self->{todo} // []}) {
+               unshift @$c, @x;
+               if ($c->[scalar(@x)] eq '--unset-all') {
+                       run_wait $c, undef, $opt;
+                       # ignore ret=5 if no matches (see git-config(1))
+                       die "E: @$c \$?=$?" if ($? && ($? >> 8) != 5);
+               } else {
+                       run_die $c, undef, $opt;
+               }
+       }
+}
+
+1;
index 0f14cebae4e85dac7e357eef0adc7d78da01423f..51d0d9ac4a728a4b89ae564d2040b39e9acbd6fe 100644 (file)
@@ -19,6 +19,7 @@ use PublicInbox::Config qw(glob2re);
 use PublicInbox::Inbox;
 use PublicInbox::LeiCurl;
 use PublicInbox::OnDestroy;
+use PublicInbox::CfgWr;
 use PublicInbox::SHA qw(sha256_hex sha_all);
 use POSIX qw(strftime);
 use PublicInbox::Admin qw(fmt_localtime);
@@ -415,16 +416,13 @@ sub fgrp_fetch_all {
                my ($old, $new) = @$fgrp_old_new;
                @$old = sort { $b->{-sort} <=> $a->{-sort} } @$old;
                # $new is ordered by {references}
-               my $cmd = [ git_exe, "--git-dir=$osdir", qw(config -f), $f ];
+               my $cfgwr = PublicInbox::CfgWr->new($f);
 
                # clobber settings from previous run atomically
                for ("remotes.$grp", 'fetch.hideRefs') {
-                       my $c = [ @$cmd, '--unset-all', $_ ];
-                       $self->{lei}->qerr("# @$c");
-                       next if $self->{dry_run};
-                       run_wait($c, undef, $opt);
-                       die "E: @$c \$?=$?" if ($? && ($? >> 8) != 5);
+                       $cfgwr->unset_all($_) if !$self->{dry_run};
                }
+               $cfgwr->commit($opt);
 
                # permanent configs:
                my $cfg = PublicInbox::Config->git_config_dump($f);
@@ -436,12 +434,10 @@ sub fgrp_fetch_all {
                                my ($k, $v) = split(/=/, $_, 2);
                                $k = "remote.$rn.$k";
                                next if ($cfg->{$k} // '') eq $v;
-                               my $c = [@$cmd, $k, $v];
-                               $fgrp->{lei}->qerr("# @$c");
-                               next if $fgrp->{dry_run};
-                               run_die($c, undef, $opt);
+                               $cfgwr->set($k, $v) if !$fgrp->{dry_run};
                        }
                }
+               $cfgwr->commit($opt);
 
                if (!$self->{dry_run}) {
                        # update the config atomically via O_APPEND while
@@ -460,7 +456,7 @@ sub fgrp_fetch_all {
                        write_file '>>', $f, @buf;
                        unlink("$f.lock");
                }
-               $cmd  = [ @git, "--git-dir=$osdir", @fetch, $grp ];
+               my $cmd = [ @git, "--git-dir=$osdir", @fetch, $grp ];
                push @$old, @$new;
                my $end = on_destroy \&fgrpv_done, $old;
                start_cmd($self, $cmd, $opt, $end);
@@ -809,9 +805,8 @@ sub update_ent {
        $cur = $self->{-local_manifest}->{$key}->{owner} // "\0";
        return if $cur eq $new;
        utf8::encode($new); # to octets
-       my $cmd = [ git_exe, qw(config -f), "$dst/config",
-                       'gitweb.owner', $new ];
-       start_cmd($self, $cmd, { 2 => $self->{lei}->{2} });
+       PublicInbox::CfgWr->new(
+               "$dst/config")->set('gitweb.owner', $new)->commit;
 }
 
 sub v1_done { # called via OnDestroy
index 612d1f439dd1146147b176f6cf4b7beb8e24f5b3..574cf9aa89ec570c90faa822e7e3adb0e321d35b 100644 (file)
@@ -10,6 +10,7 @@ use PublicInbox::Git qw(git_exe);
 use PublicInbox::OverIdx;
 use PublicInbox::LeiSearch;
 use PublicInbox::Config;
+use PublicInbox::CfgWr;
 use PublicInbox::Spawn qw(run_die);
 use PublicInbox::ContentHash qw(git_sha);
 use PublicInbox::MID qw(mids_for_index);
@@ -179,9 +180,9 @@ EOM
 sub description { $_[0]->{qstr} } # for WWW
 
 sub cfg_set { # called by LeiXSearch
-       my ($self, @args) = @_;
+       my ($self, $k, $v) = @_;
        my $lk = $self->lock_for_scope; # git-config doesn't wait
-       run_die([git_exe, qw(config -f), $self->{'-f'}, @args]);
+       PublicInbox::CfgWr->new($self->{-f})->set($k, $v)->commit;
 }
 
 # drop-in for LeiDedupe API
index 9be3a876e49d99cfeca747a7cc6eeb6dbdefd400..c99a11cbe375c656684353275b7ac844a7b4a718 100644 (file)
@@ -7,6 +7,7 @@ use strict;
 use v5.10.1;
 use PublicInbox::Spawn qw(run_die run_qx);
 use PublicInbox::Import;
+use PublicInbox::CfgWr;
 use PublicInbox::Git qw(git_exe);
 use File::Temp 0.19;
 use List::Util qw(max);
@@ -116,7 +117,7 @@ sub epoch_cfg_set {
                chomp(my $x = run_qx(\@cmd));
                return if $x eq $v;
        }
-       run_die [@cmd, $v];
+       PublicInbox::CfgWr->new($f)->set('include.path', $v)->commit;
 }
 
 sub add_epoch {
index b9e234e30872c6aded7c093192796b94cfc71bd3..b959fd917d6ea7bc8c82adfd2e2a3a10cb3c8344 100755 (executable)
@@ -163,7 +163,8 @@ my $pi_config_tmp = $fh->filename;
 close($fh);
 
 my $pfx = "publicinbox.$name";
-my @x = (qw/git config/, "--file=$pi_config_tmp");
+require PublicInbox::CfgWr;
+my $cfgwr = PublicInbox::CfgWr->new($pi_config_tmp);
 
 $inboxdir = PublicInbox::Config::rel2abs_collapsed($inboxdir);
 die "`\\n' not allowed in `$inboxdir'\n" if index($inboxdir, "\n") >= 0;
@@ -225,15 +226,15 @@ require PublicInbox::Spawn;
 PublicInbox::Spawn->import(qw(run_die));
 
 for my $addr (grep { !$seen{lc $_} } @address) {
-       run_die([@x, "--add", "$pfx.address", $addr]);
+       $cfgwr->add("$pfx.address", $addr);
 }
-run_die([@x, "$pfx.url", $http_url]) if
+$cfgwr->set("$pfx.url", $http_url) if
        (!$old_ibx || !grep(/\Q$http_url\E/, @{$old_ibx->{url} // []}));
-run_die([@x, "$pfx.inboxdir", $inboxdir]) if
+$cfgwr->set("$pfx.inboxdir", $inboxdir) if
        (!$old_ibx || ($old_ibx->{inboxdir} ne $inboxdir));
-run_die([@x, "$pfx.indexlevel", $indexlevel]) if defined($indexlevel) &&
+$cfgwr->set("$pfx.indexlevel", $indexlevel) if defined($indexlevel) &&
        (!$old_ibx || (($old_ibx->{indexlevel} // '') ne $indexlevel));
-run_die([@x, "$pfx.newsgroup", $ng]) if $ng ne '' &&
+$cfgwr->set("$pfx.newsgroup", $ng) if $ng ne '' &&
        (!$old_ibx || (($old_ibx->{newsgroup} // '') ne $ng));
 
 for my $kv (@c_extra) {
@@ -242,8 +243,9 @@ for my $kv (@c_extra) {
        # but that's too new to depend on in 2021.  Perl quotemeta
        # seems compatible enough for POSIX ERE which git uses
        my $re = '^'.quotemeta($v).'$';
-       run_die([@x, qw(--replace-all), "$pfx.$k", $v, $re]);
+       $cfgwr->replace_all("$pfx.$k", $v, $re);
 }
+$cfgwr->commit;
 
 # needed for git prior to v2.1.0
 chmod($perm & 07777, $pi_config_tmp);