]> git.ipfire.org Git - thirdparty/public-inbox.git/commitdiff
use git(1) for configs if libgit2 <1.8
authorEric Wong <e@80x24.org>
Fri, 28 Mar 2025 03:32:09 +0000 (03:32 +0000)
committerEric Wong <e@80x24.org>
Fri, 28 Mar 2025 10:38:33 +0000 (10:38 +0000)
libgit2 multiline support appeared broken before 1.8.  I noticed
the following commits in libgit2 seemed relevant to us, at least:

dff05bc30 (Multiline config values not preserved on saving, 2021-11-25)
de9a76b92 (config: properly handle multiline quotes, 2023-12-14)

MANIFEST
lib/PublicInbox/Lg2.pm
lib/PublicInbox/lg2.h
lib/PublicInbox/lg2_cfg.h [new file with mode: 0644]
t/lg2_cfg.t

index 5e599990deb36eec9f988158fe38f15486a16808..c6142398282969550e220ada83815f2ed57e8058 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -392,6 +392,7 @@ lib/PublicInbox/XhcMsetIterator.pm
 lib/PublicInbox/approxidate.h
 lib/PublicInbox/khashl.h
 lib/PublicInbox/lg2.h
+lib/PublicInbox/lg2_cfg.h
 lib/PublicInbox/xap_helper.h
 lib/PublicInbox/xh_cidx.h
 lib/PublicInbox/xh_date.h
index a4ea4b763a11348b748638a51d46eec7d3de16a4..d952f14c182c28c38fe39b2119c11a47bd1ba5fe 100644 (file)
@@ -34,8 +34,17 @@ BEGIN {
                die "E: libgit2 not installed: $err\n" if $?;
                $vals->{$k} = $val;
        }
+       my $modversion = $vals->{modversion};
+       *modversion = sub { $modversion };
+       my $lg2_ver = eval("v$modversion");
        my $f = "$dir/lg2.h";
        $c_src = PublicInbox::IO::try_cat $f or die "cat $f: $!";
+       # old versions were broken w/ multi-line, and also lacked the
+       # LIBGIT2_VERSION_CHECK macro (and Inline::C won't let us hide
+       # functions via CPP #if blocks)
+       if ($lg2_ver ge v1.8) {
+               $c_src .= PublicInbox::IO::try_cat "$dir/lg2_cfg.h";
+       }
        # append pkg-config results to the source to ensure Inline::C
        # can rebuild if there's changes (it doesn't seem to detect
        # $CFG{CCFLAGSEX} nor $CFG{CPPFLAGS} changes)
@@ -49,8 +58,7 @@ BEGIN {
        $CFG{CCFLAGSEX} = $vals->{cflags};
        $CFG{LIBS} = $vals->{libs};
        my $boot = 'git_libgit2_init();';
-       eval("v$vals->{modversion}") ge v0.26 and
-               $boot .= <<EOM;
+       $boot .= <<EOM if $lg2_ver ge v0.26;
 git_libgit2_opts(GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION, 0);
 EOM
        eval <<EOM;
index fb771bd476a010e6fe1d4ee896c34d5ba7fb4464..b897759511b1638b3a24b4480ef18d1f3858de33 100644 (file)
@@ -140,59 +140,3 @@ int cat_oid(SV *self, int fd, SV *oidsv)
 
        return rc == GIT_OK;
 }
-
-#define CFG_OP_EQ(op, cmd0, dlen) \
-       (dlen == (sizeof(op) - 1) && !memcmp(op, cmd0, sizeof(op) - 1))
-
-/* leaks on internal bugs: */
-#define FETCH_CSTR(var, ary, i) do { \
-       SV **s = av_fetch(ary, i, 0); \
-       if (!s) croak("BUG: " #var " = ary[%d] is NULL", i); \
-       var = SvPV_nolen(*s); \
-} while (0)
-
-void cfgwr_commit(const char *f, AV *todo)
-{
-       I32 i, todo_max = av_len(todo);
-       SV **sv;
-       git_config *cfg;
-       const git_error *e;
-       const char *cmd0, *name, *val, *re;
-       int rc = git_config_open_ondisk(&cfg, f);
-       STRLEN dlen;
-       AV *cmd;
-
-       for (i = 0; rc == GIT_OK && i <= todo_max; i++) {
-               sv = av_fetch(todo, i, 0);
-               /* leaks on internal bugs: */
-               if (!SvROK(*sv)) croak("BUG: not a ref");
-               cmd = (AV *)SvRV(*sv);
-               sv = av_fetch(cmd, 0, 0);
-               if (!sv) croak("BUG: cmd0 = $todo->[%d]->[0] is NULL", i);
-               cmd0 = SvPV(*sv, dlen);
-               if (CFG_OP_EQ("--add", cmd0, dlen)) {
-                       FETCH_CSTR(name, cmd, 1);
-                       FETCH_CSTR(val, cmd, 2);
-                       rc = git_config_set_multivar(cfg, name, "$^", val);
-               } else if (CFG_OP_EQ("--unset-all", cmd0, dlen)) {
-                       FETCH_CSTR(name, cmd, 1);
-                       rc = git_config_delete_multivar(cfg, name, ".*");
-                       if (rc == GIT_ENOTFOUND)
-                               rc = GIT_OK;
-               } else if (CFG_OP_EQ("--replace-all", cmd0, dlen)) {
-                       FETCH_CSTR(name, cmd, 1);
-                       FETCH_CSTR(val, cmd, 2);
-                       FETCH_CSTR(re, cmd, 3);
-                       rc = git_config_set_multivar(cfg, name, re, val);
-               } else {
-                       name = cmd0;
-                       FETCH_CSTR(val, cmd, 1);
-                       rc = git_config_set_string(cfg, name, val);
-               }
-       }
-       e = rc == GIT_OK ? NULL : giterr_last();
-       git_config_free(cfg);
-       if (rc != GIT_OK)
-               croak("config -f %s (%d %s)",
-                       f, rc, e ? e->message : "unknown");
-}
diff --git a/lib/PublicInbox/lg2_cfg.h b/lib/PublicInbox/lg2_cfg.h
new file mode 100644 (file)
index 0000000..f8fa482
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) all contributors <meta@public-inbox.org>
+ * License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
+ *
+ * multiline configs broken before 1.8, I only noticed the former myself:
+ * dff05bc30 (Multiline config values not preserved on saving, 2021-11-25)
+ * de9a76b92 (config: properly handle multiline quotes, 2023-12-14)
+ */
+#define CFG_OP_EQ(op, cmd0, dlen) \
+       (dlen == (sizeof(op) - 1) && !memcmp(op, cmd0, sizeof(op) - 1))
+
+/* leaks on internal bugs: */
+#define FETCH_CSTR(var, ary, i) do { \
+       SV **s = av_fetch(ary, i, 0); \
+       if (!s) croak("BUG: " #var " = ary[%d] is NULL", i); \
+       var = SvPV_nolen(*s); \
+} while (0)
+
+void cfgwr_commit(const char *f, AV *todo)
+{
+       I32 i, todo_max = av_len(todo);
+       SV **sv;
+       git_config *cfg;
+       const git_error *e;
+       const char *cmd0, *name, *val, *re;
+       int rc = git_config_open_ondisk(&cfg, f);
+       STRLEN dlen;
+       AV *cmd;
+
+       for (i = 0; rc == GIT_OK && i <= todo_max; i++) {
+               sv = av_fetch(todo, i, 0);
+               /* leaks on internal bugs: */
+               if (!SvROK(*sv)) croak("BUG: not a ref");
+               cmd = (AV *)SvRV(*sv);
+               sv = av_fetch(cmd, 0, 0);
+               if (!sv) croak("BUG: cmd0 = $todo->[%d]->[0] is NULL", i);
+               cmd0 = SvPV(*sv, dlen);
+               if (CFG_OP_EQ("--add", cmd0, dlen)) {
+                       FETCH_CSTR(name, cmd, 1);
+                       FETCH_CSTR(val, cmd, 2);
+                       rc = git_config_set_multivar(cfg, name, "$^", val);
+               } else if (CFG_OP_EQ("--unset-all", cmd0, dlen)) {
+                       FETCH_CSTR(name, cmd, 1);
+                       rc = git_config_delete_multivar(cfg, name, ".*");
+                       if (rc == GIT_ENOTFOUND)
+                               rc = GIT_OK;
+               } else if (CFG_OP_EQ("--replace-all", cmd0, dlen)) {
+                       FETCH_CSTR(name, cmd, 1);
+                       FETCH_CSTR(val, cmd, 2);
+                       FETCH_CSTR(re, cmd, 3);
+                       rc = git_config_set_multivar(cfg, name, re, val);
+               } else {
+                       name = cmd0;
+                       FETCH_CSTR(val, cmd, 1);
+                       rc = git_config_set_string(cfg, name, val);
+               }
+       }
+       e = rc == GIT_OK ? NULL : giterr_last();
+       git_config_free(cfg);
+       if (rc != GIT_OK)
+               croak("config -f %s (%d %s)",
+                       f, rc, e ? e->message : "unknown");
+}
index e8cdff4ae220eb1d9a80e88bf41aa76f3d777a80..067bc866f5ed1c25028aa17da3c704fde3f846da 100644 (file)
@@ -24,6 +24,9 @@ my $cfgwr_commit = $ENV{TEST_VALIDATE_GIT_BEHAVIOR} ? sub {
        }
 } : PublicInbox::Lg2->can('cfgwr_commit');
 
+SKIP: {
+$cfgwr_commit or skip 'libgit2 '.PublicInbox::Lg2->modversion.
+               ' < 1.8 too old for multiline configs', 1;
 my $cfg; # for explain() if needed
 my $get = sub {
        my (@key) = @_;
@@ -57,4 +60,16 @@ $cfgwr_commit->($f, [ [ qw(x.b d) ], [ qw(--add x.b e) ],
        [ qw(--add x.b f) ] ]);
 is_xdeeply $get->('x.b'), [ qw(d e f) ], 'multiple changes chained';
 
+use PublicInbox::IO qw(write_file try_cat);
+my $src = <<EOM;
+[foo]
+       bar = some \\
+very \\
+long line
+EOM
+write_file '>', $f, $src;
+$cfgwr_commit->($f, [ [ qw(x.b d) ], [ qw(--add x.b e) ] ]);
+like try_cat($f), qr/^\Q$src\E$/sm, 'newlines preserved';
+} # SKIP
+
 done_testing;