summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.mailmap1
-rw-r--r--Documentation/BreakingChanges.txt20
-rw-r--r--Documentation/CodingGuidelines8
-rw-r--r--Documentation/RelNotes/2.47.0.txt42
-rw-r--r--Documentation/git-cat-file.txt6
-rw-r--r--Documentation/git-check-mailmap.txt18
-rw-r--r--Documentation/git-config.txt6
-rw-r--r--Documentation/technical/api-trace2.txt17
-rw-r--r--Makefile16
-rw-r--r--archive.c10
-rw-r--r--builtin/archive.c7
-rw-r--r--builtin/bundle.c2
-rw-r--r--builtin/check-mailmap.c25
-rw-r--r--builtin/config.c2
-rw-r--r--builtin/diff-index.c4
-rw-r--r--builtin/fetch-pack.c20
-rw-r--r--builtin/fetch.c24
-rw-r--r--builtin/gc.c18
-rw-r--r--builtin/index-pack.c9
-rw-r--r--builtin/merge-tree.c13
-rw-r--r--builtin/remote.c23
-rw-r--r--builtin/repack.c36
-rw-r--r--builtin/send-pack.c1
-rw-r--r--builtin/upload-archive.c8
-rw-r--r--bundle-uri.c4
-rw-r--r--bundle.c4
-rw-r--r--compat/mingw.c15
-rw-r--r--compat/mingw.h18
-rw-r--r--compat/nedmalloc/nedmalloc.c2
-rw-r--r--compat/regex/regcomp.c2
-rw-r--r--compat/stub/procinfo.c2
-rw-r--r--compat/terminal.c2
-rw-r--r--compat/win32/headless.c2
-rw-r--r--compat/win32/pthread.c2
-rw-r--r--compat/win32/pthread.h4
-rw-r--r--compat/win32/syslog.c2
-rw-r--r--compat/win32mmap.c2
-rw-r--r--compat/winansi.c2
-rw-r--r--config.mak.dev1
-rw-r--r--config.mak.uname1
-rw-r--r--contrib/completion/git-prompt.sh191
-rw-r--r--convert.c3
-rw-r--r--exec-cmd.c23
-rw-r--r--git-compat-util.h24
-rwxr-xr-xgit-send-email.perl20
-rw-r--r--grep.c4
-rw-r--r--mailinfo.c36
-rw-r--r--mailmap.c9
-rw-r--r--mailmap.h7
-rw-r--r--mergetools/vscode19
-rw-r--r--midx-write.c24
-rw-r--r--pager.c2
-rw-r--r--pretty.c13
-rw-r--r--refs/files-backend.c7
-rw-r--r--reftable/block_test.c123
-rw-r--r--reftable/blocksource.c20
-rw-r--r--reftable/blocksource.h2
-rw-r--r--reftable/dump.c111
-rw-r--r--reftable/generic.c231
-rw-r--r--reftable/generic.h37
-rw-r--r--reftable/iter.c126
-rw-r--r--reftable/iter.h30
-rw-r--r--reftable/merged.c72
-rw-r--r--reftable/merged.h4
-rw-r--r--reftable/reader.c219
-rw-r--r--reftable/reader.h9
-rw-r--r--reftable/record.c127
-rw-r--r--reftable/record.h1
-rw-r--r--reftable/reftable-generic.h47
-rw-r--r--reftable/reftable-merged.h26
-rw-r--r--reftable/reftable-reader.h28
-rw-r--r--reftable/reftable-record.h8
-rw-r--r--reftable/reftable-stack.h3
-rw-r--r--reftable/reftable-tests.h2
-rw-r--r--reftable/stack.c184
-rw-r--r--reftable/stack_test.c145
-rw-r--r--remote.c85
-rw-r--r--revision.c1
-rw-r--r--send-pack.c16
-rw-r--r--sequencer.c7
-rw-r--r--sideband.c15
-rw-r--r--t/helper/test-oid-array.c49
-rw-r--r--t/helper/test-read-midx.c8
-rw-r--r--t/helper/test-reftable.c190
-rw-r--r--t/helper/test-tool.c2
-rw-r--r--t/helper/test-tool.h2
-rw-r--r--t/helper/test-urlmatch-normalization.c56
-rwxr-xr-xt/t0064-oid-array.sh122
-rwxr-xr-xt/t0110-urlmatch-normalization.sh182
-rw-r--r--t/t0110/README9
-rw-r--r--t/t0110/url-11
-rw-r--r--t/t0110/url-101
-rw-r--r--t/t0110/url-111
-rw-r--r--t/t0110/url-21
-rw-r--r--t/t0110/url-31
-rw-r--r--t/t0110/url-41
-rw-r--r--t/t0110/url-51
-rw-r--r--t/t0110/url-61
-rw-r--r--t/t0110/url-71
-rw-r--r--t/t0110/url-81
-rw-r--r--t/t0110/url-91
-rwxr-xr-xt/t1092-sparse-checkout-compatibility.sh15
-rwxr-xr-xt/t3400-rebase.sh6
-rwxr-xr-xt/t4150-am.sh1
-rwxr-xr-xt/t4203-mailmap.sh42
-rwxr-xr-xt/t4205-log-pretty-formats.sh2
-rwxr-xr-xt/t4301-merge-tree-write-tree.sh1
-rwxr-xr-xt/t5000-tar-tree.sh1
-rwxr-xr-xt/t5003-archive-zip.sh1
-rwxr-xr-xt/t5100-mailinfo.sh1
-rwxr-xr-xt/t5300-pack-object.sh39
-rwxr-xr-xt/t5319-multi-pack-index.sh2
-rwxr-xr-xt/t5400-send-pack.sh1
-rwxr-xr-xt/t5401-update-hooks.sh2
-rwxr-xr-xt/t5408-send-pack-stdin.sh2
-rwxr-xr-xt/t5409-colorize-remote-messages.sh1
-rwxr-xr-xt/t5501-fetch-push-alternates.sh1
-rwxr-xr-xt/t5505-remote.sh1
-rwxr-xr-xt/t5510-fetch.sh1
-rwxr-xr-xt/t5519-push-alternates.sh1
-rwxr-xr-xt/t5536-fetch-conflicts.sh1
-rwxr-xr-xt/t5548-push-porcelain.sh1
-rwxr-xr-xt/t5553-set-upstream.sh1
-rwxr-xr-xt/t5574-fetch-output.sh1
-rwxr-xr-xt/t5703-upload-pack-ref-in-want.sh1
-rwxr-xr-xt/t5812-proto-disable-http.sh2
-rwxr-xr-xt/t6050-replace.sh1
-rwxr-xr-xt/t7704-repack-cruft.sh1
-rwxr-xr-xt/t9001-send-email.sh122
-rw-r--r--t/unit-tests/lib-oid.c2
-rw-r--r--t/unit-tests/lib-oid.h8
-rw-r--r--t/unit-tests/t-oid-array.c126
-rw-r--r--t/unit-tests/t-reftable-block.c371
-rw-r--r--t/unit-tests/t-reftable-merged.c27
-rw-r--r--t/unit-tests/t-reftable-readwrite.c92
-rw-r--r--t/unit-tests/t-urlmatch-normalization.c271
-rw-r--r--trace2/tr2_tgt_event.c22
-rw-r--r--transport.c8
138 files changed, 2465 insertions, 1807 deletions
diff --git a/.mailmap b/.mailmap
index 18128a1250..96c2740fbb 100644
--- a/.mailmap
+++ b/.mailmap
@@ -257,6 +257,7 @@ Stefan Naewe <stefan.naewe@gmail.com> <stefan.naewe@googlemail.com>
Stefan Sperling <stsp@elego.de> <stsp@stsp.name>
Štěpán Němec <stepnem@gmail.com> <stepan.nemec@gmail.com>
Stephen Boyd <bebarino@gmail.com> <sboyd@codeaurora.org>
+Stephen P. Smith <ishchis2@gmail.com> <ischis2@cox.net>
Steven Drake <sdrake@xnet.co.nz> <sdrake@ihug.co.nz>
Steven Grimm <koreth@midwinter.com> <sgrimm@sgrimm-mbp.local>
Steven Grimm <koreth@midwinter.com> koreth@midwinter.com
diff --git a/Documentation/BreakingChanges.txt b/Documentation/BreakingChanges.txt
index 0532bfcf7f..2b64665694 100644
--- a/Documentation/BreakingChanges.txt
+++ b/Documentation/BreakingChanges.txt
@@ -115,6 +115,26 @@ info/grafts as outdated, 2014-03-05) and will be removed.
+
Cf. <20140304174806.GA11561@sigill.intra.peff.net>.
+* The git-pack-redundant(1) command can be used to remove redundant pack files.
+ The subcommand is unusably slow and the reason why nobody reports it as a
+ performance bug is suspected to be the absense of users. We have nominated
+ the command for removal and have started to emit a user-visible warning in
+ c3b58472be (pack-redundant: gauge the usage before proposing its removal,
+ 2020-08-25) whenever the command is executed.
++
+So far there was a single complaint about somebody still using the command, but
+that complaint did not cause us to reverse course. On the contrary, we have
+doubled down on the deprecation and starting with 4406522b76 (pack-redundant:
+escalate deprecation warning to an error, 2023-03-23), the command dies unless
+the user passes the `--i-still-use-this` option.
++
+There have not been any subsequent complaints, so this command will finally be
+removed.
++
+Cf. <xmqq1rjuz6n3.fsf_-_@gitster.c.googlers.com>,
+ <CAKvOHKAFXQwt4D8yUCCkf_TQL79mYaJ=KAKhtpDNTvHJFuX1NA@mail.gmail.com>,
+ <20230323204047.GA9290@coredump.intra.peff.net>,
+
== Superseded features that will not be deprecated
Some features have gained newer replacements that aim to improve the design in
diff --git a/Documentation/CodingGuidelines b/Documentation/CodingGuidelines
index ccaea39752..3263245b03 100644
--- a/Documentation/CodingGuidelines
+++ b/Documentation/CodingGuidelines
@@ -258,6 +258,14 @@ For C programs:
ensure your patch is clear of all compiler warnings we care about,
by e.g. "echo DEVELOPER=1 >>config.mak".
+ - When using DEVELOPER=1 mode, you may see warnings from the compiler
+ like "error: unused parameter 'foo' [-Werror=unused-parameter]",
+ which indicates that a function ignores its argument. If the unused
+ parameter can't be removed (e.g., because the function is used as a
+ callback and has to match a certain interface), you can annotate
+ the individual parameters with the UNUSED (or MAYBE_UNUSED)
+ keyword, like "int foo UNUSED".
+
- We try to support a wide range of C compilers to compile Git with,
including old ones. As of Git v2.35.0 Git requires C99 (we check
"__STDC_VERSION__"). You should not use features from a newer C
diff --git a/Documentation/RelNotes/2.47.0.txt b/Documentation/RelNotes/2.47.0.txt
index ab706fc957..2aee05e09a 100644
--- a/Documentation/RelNotes/2.47.0.txt
+++ b/Documentation/RelNotes/2.47.0.txt
@@ -43,6 +43,18 @@ UI, Workflows & Features
that the history leading to a given commit "%(is-base:<commit>)" is
likely based on.
+ * The command line prompt support used to be littered with bash-isms,
+ which has been corrected to work with more shells.
+
+ * Support for the RUNTIME_PREFIX feature has been added to z/OS port.
+
+ * "git send-email" learned "--mailmap" option to allow rewriting the
+ recipient addresses.
+
+ * "git mergetool" learned to use VSCode as a merge backend.
+
+ * "git pack-redundant" has been marked for removal in Git 3.0.
+
Performance, Internal Implementation, Development Support etc.
--------------------------------------------------------------
@@ -93,9 +105,21 @@ Performance, Internal Implementation, Development Support etc.
object in the config subsystem has been rewritten to pass a
repository object through the callchain.
- * Drop unused parameters from functions.
+ * Unused parameters have been either marked as UNUSED to squelch
+ -Wunused warnings or dropped from many functions..
+
+ * The code in the reftable library has been cleaned up by discarding
+ unused "generic" interface.
- * Mark unused parameters as UNUSED to squelch -Wunused warnings.
+ * The underlying machinery for "git diff-index" has long been made to
+ expand the sparse index as needed, but the command fully expanded
+ the sparse index upfront, which now has been taught not to do.
+
+ * More trace2 events at key points on push and fetch code paths have
+ been added.
+
+ * Make our codebase compilable with the -Werror=unused-parameter
+ option.
Fixes since v2.46
@@ -171,6 +195,16 @@ Fixes since v2.46
which made no sense. These bugs have been corrected.
(merge a72dfab8b8 tb/pseudo-merge-bitmap-fixes later to maint).
+ * "git rebase -x --quiet" was not quiet, which was corrected.
+
+ * The code path for compacting reftable files saw some bugfixes
+ against concurrent operation.
+
+ * The code forgot to discard unnecessary in-core commit buffer data
+ for commits that "git log --skip=<number>" traversed but omitted
+ from the output, which has been corrected.
+ (merge 6bd2ae67a5 jk/free-commit-buffer-of-skipped-commits later to maint).
+
* Other code cleanup, docfix, build fix, etc.
(merge bb0498b1bb jc/how-to-maintain-updates later to maint).
(merge 0d66f601a9 jc/tests-no-useless-tee later to maint).
@@ -178,3 +212,7 @@ Fixes since v2.46
(merge 983555a1f2 jc/how-to-maintain-updates later to maint).
(merge e3209bd4df ps/stash-keep-untrack-empty-fix later to maint).
(merge 44db6f75cc jc/coding-style-c-operator-with-spaces later to maint).
+ (merge 596f4ff6ad cl/config-regexp-docfix later to maint).
+ (merge 4881328617 aa/cat-file-batch-output-doc later to maint).
+ (merge 1609470409 jc/config-doc-update later to maint).
+ (merge d4dc0efd7d rj/compat-terminal-unused-fix later to maint).
diff --git a/Documentation/git-cat-file.txt b/Documentation/git-cat-file.txt
index bd95a6c10a..d5890ae368 100644
--- a/Documentation/git-cat-file.txt
+++ b/Documentation/git-cat-file.txt
@@ -270,9 +270,9 @@ BATCH OUTPUT
------------
If `--batch` or `--batch-check` is given, `cat-file` will read objects
-from stdin, one per line, and print information about them. By default,
-the whole line is considered as an object, as if it were fed to
-linkgit:git-rev-parse[1].
+from stdin, one per line, and print information about them in the same
+order as they have been read. By default, the whole line is
+considered as an object, as if it were fed to linkgit:git-rev-parse[1].
When `--batch-command` is given, `cat-file` will read commands from stdin,
one per line, and print information based on the command given. With
diff --git a/Documentation/git-check-mailmap.txt b/Documentation/git-check-mailmap.txt
index 02f4418323..966c91c46a 100644
--- a/Documentation/git-check-mailmap.txt
+++ b/Documentation/git-check-mailmap.txt
@@ -15,10 +15,10 @@ SYNOPSIS
DESCRIPTION
-----------
-For each ``Name $$<user@host>$$'' or ``$$<user@host>$$'' from the command-line
-or standard input (when using `--stdin`), look up the person's canonical name
-and email address (see "Mapping Authors" below). If found, print them;
-otherwise print the input as-is.
+For each ``Name $$<user@host>$$'', ``$$<user@host>$$'', or ``$$user@host$$''
+from the command-line or standard input (when using `--stdin`), look up the
+person's canonical name and email address (see "Mapping Authors" below). If
+found, print them; otherwise print the input as-is.
OPTIONS
@@ -27,6 +27,16 @@ OPTIONS
Read contacts, one per line, from the standard input after exhausting
contacts provided on the command-line.
+--mailmap-file=<file>::
+ In addition to any configured mailmap files, read the specified
+ mailmap file. Entries in this file take precedence over entries in
+ either the default mailmap file or any configured mailmap file.
+
+--mailmap-blob=<blob>::
+ Like `--mailmap-file`, but consider the value as a reference to a
+ blob in the repository. If both `--mailmap-file` and
+ `--mailmap-blob` are specified, entries in `--mailmap-file` will
+ take precedence.
OUTPUT
------
diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt
index 65c645d461..7f81fbbea8 100644
--- a/Documentation/git-config.txt
+++ b/Documentation/git-config.txt
@@ -10,7 +10,7 @@ SYNOPSIS
--------
[verse]
'git config list' [<file-option>] [<display-option>] [--includes]
-'git config get' [<file-option>] [<display-option>] [--includes] [--all] [--regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] <name>
+'git config get' [<file-option>] [<display-option>] [--includes] [--all] [--regexp] [--value=<value>] [--fixed-value] [--default=<default>] <name>
'git config set' [<file-option>] [--type=<type>] [--all] [--value=<value>] [--fixed-value] <name> <value>
'git config unset' [<file-option>] [--all] [--value=<value>] [--fixed-value] <name> <value>
'git config rename-section' [<file-option>] <old-name> <new-name>
@@ -130,7 +130,7 @@ OPTIONS
--all::
With `get`, return all values for a multi-valued key.
----regexp::
+--regexp::
With `get`, interpret the name as a regular expression. Regular
expression matching is currently case-sensitive and done against a
canonicalized version of the key in which section and variable names
@@ -309,7 +309,7 @@ recommended to migrate to the new syntax.
Replaced by `git config get [--value=<pattern>] <name>`.
--get-all <name> [<value-pattern>]::
- Replaced by `git config get [--value=<pattern>] --all --show-names <name>`.
+ Replaced by `git config get [--value=<pattern>] --all <name>`.
--get-regexp <name-regexp>::
Replaced by `git config get --all --show-names --regexp <name-regexp>`.
diff --git a/Documentation/technical/api-trace2.txt b/Documentation/technical/api-trace2.txt
index de5fc25059..5817b18310 100644
--- a/Documentation/technical/api-trace2.txt
+++ b/Documentation/technical/api-trace2.txt
@@ -128,7 +128,7 @@ yields
------------
$ cat ~/log.event
-{"event":"version","sid":"20190408T191610.507018Z-H9b68c35f-P000059a8","thread":"main","time":"2019-01-16T17:28:42.620713Z","file":"common-main.c","line":38,"evt":"3","exe":"2.20.1.155.g426c96fcdb"}
+{"event":"version","sid":"20190408T191610.507018Z-H9b68c35f-P000059a8","thread":"main","time":"2019-01-16T17:28:42.620713Z","file":"common-main.c","line":38,"evt":"4","exe":"2.20.1.155.g426c96fcdb"}
{"event":"start","sid":"20190408T191610.507018Z-H9b68c35f-P000059a8","thread":"main","time":"2019-01-16T17:28:42.621027Z","file":"common-main.c","line":39,"t_abs":0.001173,"argv":["git","version"]}
{"event":"cmd_name","sid":"20190408T191610.507018Z-H9b68c35f-P000059a8","thread":"main","time":"2019-01-16T17:28:42.621122Z","file":"git.c","line":432,"name":"version","hierarchy":"version"}
{"event":"exit","sid":"20190408T191610.507018Z-H9b68c35f-P000059a8","thread":"main","time":"2019-01-16T17:28:42.621236Z","file":"git.c","line":662,"t_abs":0.001227,"code":0}
@@ -344,7 +344,7 @@ only present on the "start" and "atexit" events.
{
"event":"version",
...
- "evt":"3", # EVENT format version
+ "evt":"4", # EVENT format version
"exe":"2.20.1.155.g426c96fcdb" # git version
}
------------
@@ -835,6 +835,19 @@ The "value" field may be an integer or a string.
}
------------
+`"printf"`::
+ This event logs a human-readable message with no particular formatting
+ guidelines.
++
+------------
+{
+ "event":"printf",
+ ...
+ "t_abs":0.015905, # elapsed time in seconds
+ "msg":"Hello world" # optional
+}
+------------
+
== Example Trace2 API Usage
diff --git a/Makefile b/Makefile
index e298c8b55e..be643ef096 100644
--- a/Makefile
+++ b/Makefile
@@ -385,6 +385,10 @@ include shared.mak
# supports calling _NSGetExecutablePath to retrieve the path of the running
# executable.
#
+# When using RUNTIME_PREFIX, define HAVE_ZOS_GET_EXECUTABLE_PATH if your platform
+# supports calling __getprogramdir and getprogname to retrieve the path of the
+# running executable.
+#
# When using RUNTIME_PREFIX, define HAVE_WPGMPTR if your platform offers
# the global variable _wpgmptr containing the absolute path of the current
# executable (this is the case on Windows).
@@ -808,7 +812,6 @@ TEST_BUILTINS_OBJS += test-lazy-init-name-hash.o
TEST_BUILTINS_OBJS += test-match-trees.o
TEST_BUILTINS_OBJS += test-mergesort.o
TEST_BUILTINS_OBJS += test-mktemp.o
-TEST_BUILTINS_OBJS += test-oid-array.o
TEST_BUILTINS_OBJS += test-online-cpus.o
TEST_BUILTINS_OBJS += test-pack-mtimes.o
TEST_BUILTINS_OBJS += test-parse-options.o
@@ -843,7 +846,6 @@ TEST_BUILTINS_OBJS += test-submodule.o
TEST_BUILTINS_OBJS += test-subprocess.o
TEST_BUILTINS_OBJS += test-trace2.o
TEST_BUILTINS_OBJS += test-truncate.o
-TEST_BUILTINS_OBJS += test-urlmatch-normalization.o
TEST_BUILTINS_OBJS += test-userdiff.o
TEST_BUILTINS_OBJS += test-wildmatch.o
TEST_BUILTINS_OBJS += test-windows-named-pipe.o
@@ -1337,10 +1339,12 @@ UNIT_TEST_PROGRAMS += t-example-decorate
UNIT_TEST_PROGRAMS += t-hash
UNIT_TEST_PROGRAMS += t-hashmap
UNIT_TEST_PROGRAMS += t-mem-pool
+UNIT_TEST_PROGRAMS += t-oid-array
UNIT_TEST_PROGRAMS += t-oidmap
UNIT_TEST_PROGRAMS += t-oidtree
UNIT_TEST_PROGRAMS += t-prio-queue
UNIT_TEST_PROGRAMS += t-reftable-basics
+UNIT_TEST_PROGRAMS += t-reftable-block
UNIT_TEST_PROGRAMS += t-reftable-merged
UNIT_TEST_PROGRAMS += t-reftable-pq
UNIT_TEST_PROGRAMS += t-reftable-readwrite
@@ -1350,6 +1354,7 @@ UNIT_TEST_PROGRAMS += t-strbuf
UNIT_TEST_PROGRAMS += t-strcmp-offset
UNIT_TEST_PROGRAMS += t-strvec
UNIT_TEST_PROGRAMS += t-trailer
+UNIT_TEST_PROGRAMS += t-urlmatch-normalization
UNIT_TEST_PROGS = $(patsubst %,$(UNIT_TEST_BIN)/%$X,$(UNIT_TEST_PROGRAMS))
UNIT_TEST_OBJS = $(patsubst %,$(UNIT_TEST_DIR)/%.o,$(UNIT_TEST_PROGRAMS))
UNIT_TEST_OBJS += $(UNIT_TEST_DIR)/test-lib.o
@@ -2156,6 +2161,10 @@ ifdef HAVE_NS_GET_EXECUTABLE_PATH
BASIC_CFLAGS += -DHAVE_NS_GET_EXECUTABLE_PATH
endif
+ifdef HAVE_ZOS_GET_EXECUTABLE_PATH
+ BASIC_CFLAGS += -DHAVE_ZOS_GET_EXECUTABLE_PATH
+endif
+
ifdef HAVE_WPGMPTR
BASIC_CFLAGS += -DHAVE_WPGMPTR
endif
@@ -2678,13 +2687,10 @@ REFTABLE_OBJS += reftable/merged.o
REFTABLE_OBJS += reftable/pq.o
REFTABLE_OBJS += reftable/reader.o
REFTABLE_OBJS += reftable/record.o
-REFTABLE_OBJS += reftable/generic.o
REFTABLE_OBJS += reftable/stack.o
REFTABLE_OBJS += reftable/tree.o
REFTABLE_OBJS += reftable/writer.o
-REFTABLE_TEST_OBJS += reftable/block_test.o
-REFTABLE_TEST_OBJS += reftable/dump.o
REFTABLE_TEST_OBJS += reftable/stack_test.o
REFTABLE_TEST_OBJS += reftable/test_framework.o
diff --git a/archive.c b/archive.c
index 7bd60d0632..9ba96aae4f 100644
--- a/archive.c
+++ b/archive.c
@@ -736,6 +736,7 @@ int write_archive(int argc, const char **argv, const char *prefix,
struct pretty_print_describe_status describe_status = {0};
struct pretty_print_context ctx = {0};
struct archiver_args args;
+ const char **argv_copy;
int rc;
git_config_get_bool("uploadarchive.allowunreachable", &remote_allow_unreachable);
@@ -749,6 +750,14 @@ int write_archive(int argc, const char **argv, const char *prefix,
args.repo = repo;
args.prefix = prefix;
string_list_init_dup(&args.extra_files);
+
+ /*
+ * `parse_archive_args()` modifies contents of `argv`, which is what we
+ * want. Our callers may not want it though, so we create a copy here.
+ */
+ DUP_ARRAY(argv_copy, argv, argc);
+ argv = argv_copy;
+
argc = parse_archive_args(argc, argv, &ar, &args, name_hint, remote);
if (!startup_info->have_repository) {
/*
@@ -767,6 +776,7 @@ int write_archive(int argc, const char **argv, const char *prefix,
string_list_clear_func(&args.extra_files, extra_file_info_clear);
free(args.refname);
clear_pathspec(&args.pathspec);
+ free(argv_copy);
return rc;
}
diff --git a/builtin/archive.c b/builtin/archive.c
index b50981504f..63f02990d1 100644
--- a/builtin/archive.c
+++ b/builtin/archive.c
@@ -100,13 +100,16 @@ int cmd_archive(int argc, const char **argv, const char *prefix)
if (output)
create_output_file(output);
- if (remote)
- return run_remote_archiver(argc, argv, remote, exec, output);
+ if (remote) {
+ ret = run_remote_archiver(argc, argv, remote, exec, output);
+ goto out;
+ }
setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
ret = write_archive(argc, argv, prefix, the_repository, output, 0);
+out:
free(output);
return ret;
}
diff --git a/builtin/bundle.c b/builtin/bundle.c
index 86d0ed7049..b858552ee6 100644
--- a/builtin/bundle.c
+++ b/builtin/bundle.c
@@ -221,7 +221,9 @@ static int cmd_bundle_unbundle(int argc, const char **argv, const char *prefix)
&extra_index_pack_args, 0) ||
list_bundle_refs(&header, argc, argv);
bundle_header_release(&header);
+
cleanup:
+ strvec_clear(&extra_index_pack_args);
free(bundle_file);
return ret;
}
diff --git a/builtin/check-mailmap.c b/builtin/check-mailmap.c
index b8a05b8e07..2334b57222 100644
--- a/builtin/check-mailmap.c
+++ b/builtin/check-mailmap.c
@@ -9,6 +9,7 @@
#include "write-or-die.h"
static int use_stdin;
+static const char *mailmap_file, *mailmap_blob;
static const char * const check_mailmap_usage[] = {
N_("git check-mailmap [<options>] <contact>..."),
NULL
@@ -16,6 +17,8 @@ NULL
static const struct option check_mailmap_options[] = {
OPT_BOOL(0, "stdin", &use_stdin, N_("also read contacts from stdin")),
+ OPT_FILENAME(0, "mailmap-file", &mailmap_file, N_("read additional mailmap entries from file")),
+ OPT_STRING(0, "mailmap-blob", &mailmap_blob, N_("blob"), N_("read additional mailmap entries from blob")),
OPT_END()
};
@@ -25,13 +28,17 @@ static void check_mailmap(struct string_list *mailmap, const char *contact)
size_t namelen, maillen;
struct ident_split ident;
- if (split_ident_line(&ident, contact, strlen(contact)))
- die(_("unable to parse contact: %s"), contact);
-
- name = ident.name_begin;
- namelen = ident.name_end - ident.name_begin;
- mail = ident.mail_begin;
- maillen = ident.mail_end - ident.mail_begin;
+ if (!split_ident_line(&ident, contact, strlen(contact))) {
+ name = ident.name_begin;
+ namelen = ident.name_end - ident.name_begin;
+ mail = ident.mail_begin;
+ maillen = ident.mail_end - ident.mail_begin;
+ } else {
+ name = NULL;
+ namelen = 0;
+ mail = contact;
+ maillen = strlen(contact);
+ }
map_user(mailmap, &mail, &maillen, &name, &namelen);
@@ -52,6 +59,10 @@ int cmd_check_mailmap(int argc, const char **argv, const char *prefix)
die(_("no contacts specified"));
read_mailmap(&mailmap);
+ if (mailmap_blob)
+ read_mailmap_blob(&mailmap, mailmap_blob);
+ if (mailmap_file)
+ read_mailmap_file(&mailmap, mailmap_file, 0);
for (i = 0; i < argc; ++i)
check_mailmap(&mailmap, argv[i]);
diff --git a/builtin/config.c b/builtin/config.c
index e00d983596..95c8a00915 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -17,7 +17,7 @@
static const char *const builtin_config_usage[] = {
N_("git config list [<file-option>] [<display-option>] [--includes]"),
- N_("git config get [<file-option>] [<display-option>] [--includes] [--all] [--regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] <name>"),
+ N_("git config get [<file-option>] [<display-option>] [--includes] [--all] [--regexp] [--value=<value>] [--fixed-value] [--default=<default>] <name>"),
N_("git config set [<file-option>] [--type=<type>] [--all] [--value=<value>] [--fixed-value] <name> <value>"),
N_("git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] <name> <value>"),
N_("git config rename-section [<file-option>] <old-name> <new-name>"),
diff --git a/builtin/diff-index.c b/builtin/diff-index.c
index 3e05260ac0..685b60284f 100644
--- a/builtin/diff-index.c
+++ b/builtin/diff-index.c
@@ -25,6 +25,10 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix)
usage(diff_cache_usage);
git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
+
+ prepare_repo_settings(the_repository);
+ the_repository->settings.command_requires_full_index = 0;
+
repo_init_revisions(the_repository, &rev, prefix);
rev.abbrev = 0;
prefix = precompose_argv_prefix(argc, argv, prefix);
diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c
index af329e8d5c..fe404d1305 100644
--- a/builtin/fetch-pack.c
+++ b/builtin/fetch-pack.c
@@ -46,7 +46,7 @@ static void add_sought_entry(struct ref ***sought, int *nr, int *alloc,
int cmd_fetch_pack(int argc, const char **argv, const char *prefix UNUSED)
{
int i, ret;
- struct ref *ref = NULL;
+ struct ref *fetched_refs = NULL, *remote_refs = NULL;
const char *dest = NULL;
struct ref **sought = NULL;
int nr_sought = 0, alloc_sought = 0;
@@ -228,19 +228,20 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix UNUSED)
version = discover_version(&reader);
switch (version) {
case protocol_v2:
- get_remote_refs(fd[1], &reader, &ref, 0, NULL, NULL,
+ get_remote_refs(fd[1], &reader, &remote_refs, 0, NULL, NULL,
args.stateless_rpc);
break;
case protocol_v1:
case protocol_v0:
- get_remote_heads(&reader, &ref, 0, NULL, &shallow);
+ get_remote_heads(&reader, &remote_refs, 0, NULL, &shallow);
break;
case protocol_unknown_version:
BUG("unknown protocol version");
}
- ref = fetch_pack(&args, fd, ref, sought, nr_sought,
+ fetched_refs = fetch_pack(&args, fd, remote_refs, sought, nr_sought,
&shallow, pack_lockfiles_ptr, version);
+
if (pack_lockfiles.nr) {
int i;
@@ -260,7 +261,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix UNUSED)
if (finish_connect(conn))
return 1;
- ret = !ref;
+ ret = !fetched_refs;
/*
* If the heads to pull were given, we should have consumed
@@ -270,11 +271,14 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix UNUSED)
*/
ret |= report_unmatched_refs(sought, nr_sought);
- while (ref) {
+ for (struct ref *ref = fetched_refs; ref; ref = ref->next)
printf("%s %s\n",
oid_to_hex(&ref->old_oid), ref->name);
- ref = ref->next;
- }
+ for (size_t i = 0; i < nr_sought; i++)
+ free_one_ref(sought[i]);
+ free(sought);
+ free_refs(fetched_refs);
+ free_refs(remote_refs);
return ret;
}
diff --git a/builtin/fetch.c b/builtin/fetch.c
index c297569a47..b2b5aee5bf 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -1731,11 +1731,8 @@ static int do_fetch(struct transport *transport,
goto cleanup;
retcode = ref_transaction_commit(transaction, &err);
- if (retcode) {
- ref_transaction_free(transaction);
- transaction = NULL;
+ if (retcode)
goto cleanup;
- }
}
commit_fetch_head(&fetch_head);
@@ -1803,8 +1800,11 @@ cleanup:
if (transaction && ref_transaction_abort(transaction, &err) &&
err.len)
error("%s", err.buf);
+ transaction = NULL;
}
+ if (transaction)
+ ref_transaction_free(transaction);
display_state_release(&display_state);
close_fetch_head(&fetch_head);
strbuf_release(&err);
@@ -2408,6 +2408,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
struct oidset_iter iter;
const struct object_id *oid;
+ trace2_region_enter("fetch", "negotiate-only", the_repository);
if (!remote)
die(_("must supply remote when using --negotiate-only"));
gtransport = prepare_transport(remote, 1);
@@ -2416,6 +2417,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
} else {
warning(_("protocol does not support --negotiate-only, exiting"));
result = 1;
+ trace2_region_leave("fetch", "negotiate-only", the_repository);
goto cleanup;
}
if (server_options.nr)
@@ -2426,11 +2428,17 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
while ((oid = oidset_iter_next(&iter)))
printf("%s\n", oid_to_hex(oid));
oidset_clear(&acked_commits);
+ trace2_region_leave("fetch", "negotiate-only", the_repository);
} else if (remote) {
- if (filter_options.choice || repo_has_promisor_remote(the_repository))
+ if (filter_options.choice || repo_has_promisor_remote(the_repository)) {
+ trace2_region_enter("fetch", "setup-partial", the_repository);
fetch_one_setup_partial(remote);
+ trace2_region_leave("fetch", "setup-partial", the_repository);
+ }
+ trace2_region_enter("fetch", "fetch-one", the_repository);
result = fetch_one(remote, argc, argv, prune_tags_ok, stdin_refspecs,
&config);
+ trace2_region_leave("fetch", "fetch-one", the_repository);
} else {
int max_children = max_jobs;
@@ -2450,7 +2458,9 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
max_children = config.parallel;
/* TODO should this also die if we have a previous partial-clone? */
+ trace2_region_enter("fetch", "fetch-multiple", the_repository);
result = fetch_multiple(&list, max_children, &config);
+ trace2_region_leave("fetch", "fetch-multiple", the_repository);
}
/*
@@ -2472,6 +2482,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
max_children = config.parallel;
add_options_to_argv(&options, &config);
+ trace2_region_enter_printf("fetch", "recurse-submodule", the_repository, "%s", submodule_prefix);
result = fetch_submodules(the_repository,
&options,
submodule_prefix,
@@ -2479,6 +2490,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
recurse_submodules_default,
verbosity < 0,
max_children);
+ trace2_region_leave_printf("fetch", "recurse-submodule", the_repository, "%s", submodule_prefix);
strvec_clear(&options);
}
@@ -2502,9 +2514,11 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
if (progress)
commit_graph_flags |= COMMIT_GRAPH_WRITE_PROGRESS;
+ trace2_region_enter("fetch", "write-commit-graph", the_repository);
write_commit_graph_reachable(the_repository->objects->odb,
commit_graph_flags,
NULL);
+ trace2_region_leave("fetch", "write-commit-graph", the_repository);
}
if (enable_auto_gc) {
diff --git a/builtin/gc.c b/builtin/gc.c
index 427faf1cfe..7dac971405 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -260,7 +260,7 @@ static int pack_refs_condition(UNUSED struct gc_config *cfg)
return 1;
}
-static int maintenance_task_pack_refs(MAYBE_UNUSED struct maintenance_run_opts *opts,
+static int maintenance_task_pack_refs(struct maintenance_run_opts *opts,
UNUSED struct gc_config *cfg)
{
struct child_process cmd = CHILD_PROCESS_INIT;
@@ -967,7 +967,7 @@ static int dfs_on_ref(const char *refname UNUSED,
return result;
}
-static int should_write_commit_graph(struct gc_config *cfg)
+static int should_write_commit_graph(struct gc_config *cfg UNUSED)
{
int result;
struct cg_auto_data data;
@@ -1005,7 +1005,7 @@ static int run_write_commit_graph(struct maintenance_run_opts *opts)
}
static int maintenance_task_commit_graph(struct maintenance_run_opts *opts,
- struct gc_config *cfg)
+ struct gc_config *cfg UNUSED)
{
prepare_repo_settings(the_repository);
if (!the_repository->settings.core_commit_graph)
@@ -1040,7 +1040,7 @@ static int fetch_remote(struct remote *remote, void *cbdata)
}
static int maintenance_task_prefetch(struct maintenance_run_opts *opts,
- struct gc_config *cfg)
+ struct gc_config *cfg UNUSED)
{
if (for_each_remote(fetch_remote, opts)) {
error(_("failed to prefetch remotes"));
@@ -1051,7 +1051,7 @@ static int maintenance_task_prefetch(struct maintenance_run_opts *opts,
}
static int maintenance_task_gc(struct maintenance_run_opts *opts,
- struct gc_config *cfg)
+ struct gc_config *cfg UNUSED)
{
struct child_process child = CHILD_PROCESS_INIT;
@@ -1100,7 +1100,7 @@ static int loose_object_count(const struct object_id *oid UNUSED,
return 0;
}
-static int loose_object_auto_condition(struct gc_config *cfg)
+static int loose_object_auto_condition(struct gc_config *cfg UNUSED)
{
int count = 0;
@@ -1192,12 +1192,12 @@ static int pack_loose(struct maintenance_run_opts *opts)
}
static int maintenance_task_loose_objects(struct maintenance_run_opts *opts,
- struct gc_config *cfg)
+ struct gc_config *cfg UNUSED)
{
return prune_packed(opts) || pack_loose(opts);
}
-static int incremental_repack_auto_condition(struct gc_config *cfg)
+static int incremental_repack_auto_condition(struct gc_config *cfg UNUSED)
{
struct packed_git *p;
int incremental_repack_auto_limit = 10;
@@ -1317,7 +1317,7 @@ static int multi_pack_index_repack(struct maintenance_run_opts *opts)
}
static int maintenance_task_incremental_repack(struct maintenance_run_opts *opts,
- struct gc_config *cfg)
+ struct gc_config *cfg UNUSED)
{
prepare_repo_settings(the_repository);
if (!the_repository->settings.core_multi_pack_index) {
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index fd968d673d..763b01372a 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -1868,6 +1868,15 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
if (!index_name && pack_name)
index_name = derive_filename(pack_name, "pack", "idx", &index_name_buf);
+ /*
+ * Packfiles and indices do not carry enough information to be able to
+ * identify their object hash. So when we are neither in a repository
+ * nor has the user told us which object hash to use we have no other
+ * choice but to guess the object hash.
+ */
+ if (!the_repository->hash_algo)
+ repo_set_hash_algo(the_repository, GIT_HASH_SHA1);
+
opts.flags &= ~(WRITE_REV | WRITE_REV_VERIFY);
if (rev_index) {
opts.flags |= verify ? WRITE_REV_VERIFY : WRITE_REV;
diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
index 9bca9b5f33..c00469ed3d 100644
--- a/builtin/merge-tree.c
+++ b/builtin/merge-tree.c
@@ -533,6 +533,7 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix)
int expected_remaining_argc;
int original_argc;
const char *merge_base = NULL;
+ int ret;
const char * const merge_tree_usage[] = {
N_("git merge-tree [--write-tree] [<options>] <branch1> <branch2>"),
@@ -625,7 +626,9 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix)
strbuf_list_free(split);
}
strbuf_release(&buf);
- return 0;
+
+ ret = 0;
+ goto out;
}
/* Figure out which mode to use */
@@ -664,7 +667,11 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix)
/* Do the relevant type of merge */
if (o.mode == MODE_REAL)
- return real_merge(&o, merge_base, argv[0], argv[1], prefix);
+ ret = real_merge(&o, merge_base, argv[0], argv[1], prefix);
else
- return trivial_merge(argv[0], argv[1], argv[2]);
+ ret = trivial_merge(argv[0], argv[1], argv[2]);
+
+out:
+ strvec_clear(&xopts);
+ return ret;
}
diff --git a/builtin/remote.c b/builtin/remote.c
index d1f9292ed2..0acc547d69 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -164,6 +164,7 @@ static int add(int argc, const char **argv, const char *prefix)
struct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT;
const char *name, *url;
int i;
+ int result = 0;
struct option options[] = {
OPT_BOOL('f', "fetch", &fetch, N_("fetch the remote branches")),
@@ -230,8 +231,10 @@ static int add(int argc, const char **argv, const char *prefix)
fetch_tags == TAGS_SET ? "--tags" : "--no-tags");
}
- if (fetch && fetch_remote(name))
- return 1;
+ if (fetch && fetch_remote(name)) {
+ result = 1;
+ goto out;
+ }
if (master) {
strbuf_reset(&buf);
@@ -241,14 +244,15 @@ static int add(int argc, const char **argv, const char *prefix)
strbuf_addf(&buf2, "refs/remotes/%s/%s", name, master);
if (refs_update_symref(get_main_ref_store(the_repository), buf.buf, buf2.buf, "remote add"))
- return error(_("Could not setup master '%s'"), master);
+ result = error(_("Could not setup master '%s'"), master);
}
+out:
strbuf_release(&buf);
strbuf_release(&buf2);
string_list_clear(&track, 0);
- return 0;
+ return result;
}
struct branch_info {
@@ -715,6 +719,7 @@ static int mv(int argc, const char **argv, const char *prefix)
struct rename_info rename;
int i, refs_renamed_nr = 0, refspec_updated = 0;
struct progress *progress = NULL;
+ int result = 0;
argc = parse_options(argc, argv, prefix, options,
builtin_remote_rename_usage, 0);
@@ -747,9 +752,11 @@ static int mv(int argc, const char **argv, const char *prefix)
strbuf_addf(&buf, "remote.%s", rename.old_name);
strbuf_addf(&buf2, "remote.%s", rename.new_name);
- if (repo_config_rename_section(the_repository, buf.buf, buf2.buf) < 1)
- return error(_("Could not rename config section '%s' to '%s'"),
- buf.buf, buf2.buf);
+ if (repo_config_rename_section(the_repository, buf.buf, buf2.buf) < 1) {
+ result = error(_("Could not rename config section '%s' to '%s'"),
+ buf.buf, buf2.buf);
+ goto out;
+ }
if (oldremote->fetch.raw_nr) {
strbuf_reset(&buf);
@@ -870,7 +877,7 @@ out:
strbuf_release(&buf);
strbuf_release(&buf2);
strbuf_release(&buf3);
- return 0;
+ return result;
}
static int rm(int argc, const char **argv, const char *prefix)
diff --git a/builtin/repack.c b/builtin/repack.c
index 62cfa50c50..8bb875532b 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -732,14 +732,23 @@ static void midx_included_packs(struct string_list *include,
struct pack_geometry *geometry)
{
struct string_list_item *item;
+ struct strbuf buf = STRBUF_INIT;
+
+ for_each_string_list_item(item, &existing->kept_packs) {
+ strbuf_reset(&buf);
+ strbuf_addf(&buf, "%s.idx", item->string);
+ string_list_insert(include, buf.buf);
+ }
+
+ for_each_string_list_item(item, names) {
+ strbuf_reset(&buf);
+ strbuf_addf(&buf, "pack-%s.idx", item->string);
+ string_list_insert(include, buf.buf);
+ }
- for_each_string_list_item(item, &existing->kept_packs)
- string_list_insert(include, xstrfmt("%s.idx", item->string));
- for_each_string_list_item(item, names)
- string_list_insert(include, xstrfmt("pack-%s.idx", item->string));
if (geometry->split_factor) {
- struct strbuf buf = STRBUF_INIT;
uint32_t i;
+
for (i = geometry->split; i < geometry->pack_nr; i++) {
struct packed_git *p = geometry->pack[i];
@@ -754,17 +763,21 @@ static void midx_included_packs(struct string_list *include,
if (!p->pack_local)
continue;
+ strbuf_reset(&buf);
strbuf_addstr(&buf, pack_basename(p));
strbuf_strip_suffix(&buf, ".pack");
strbuf_addstr(&buf, ".idx");
- string_list_insert(include, strbuf_detach(&buf, NULL));
+ string_list_insert(include, buf.buf);
}
} else {
for_each_string_list_item(item, &existing->non_kept_packs) {
if (pack_is_marked_for_deletion(item))
continue;
- string_list_insert(include, xstrfmt("%s.idx", item->string));
+
+ strbuf_reset(&buf);
+ strbuf_addf(&buf, "%s.idx", item->string);
+ string_list_insert(include, buf.buf);
}
}
@@ -784,8 +797,13 @@ static void midx_included_packs(struct string_list *include,
*/
if (pack_is_marked_for_deletion(item))
continue;
- string_list_insert(include, xstrfmt("%s.idx", item->string));
+
+ strbuf_reset(&buf);
+ strbuf_addf(&buf, "%s.idx", item->string);
+ string_list_insert(include, buf.buf);
}
+
+ strbuf_release(&buf);
}
static int write_midx_included_packs(struct string_list *include,
@@ -1476,7 +1494,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
mark_packs_for_deletion(&existing, &names);
if (write_midx) {
- struct string_list include = STRING_LIST_INIT_NODUP;
+ struct string_list include = STRING_LIST_INIT_DUP;
midx_included_packs(&include, &existing, &names, &geometry);
ret = write_midx_included_packs(&include, &geometry, &names,
diff --git a/builtin/send-pack.c b/builtin/send-pack.c
index 17cae6bbbd..ef0df80824 100644
--- a/builtin/send-pack.c
+++ b/builtin/send-pack.c
@@ -338,5 +338,6 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
free_refs(remote_refs);
free_refs(local_refs);
+ refspec_clear(&rs);
return ret;
}
diff --git a/builtin/upload-archive.c b/builtin/upload-archive.c
index 1b09e5e1aa..313a8dfa81 100644
--- a/builtin/upload-archive.c
+++ b/builtin/upload-archive.c
@@ -22,6 +22,7 @@ int cmd_upload_archive_writer(int argc, const char **argv, const char *prefix)
{
struct strvec sent_argv = STRVEC_INIT;
const char *arg_cmd = "argument ";
+ int ret;
if (argc != 2 || !strcmp(argv[1], "-h"))
usage(upload_archive_usage);
@@ -46,8 +47,11 @@ int cmd_upload_archive_writer(int argc, const char **argv, const char *prefix)
}
/* parse all options sent by the client */
- return write_archive(sent_argv.nr, sent_argv.v, prefix,
- the_repository, NULL, 1);
+ ret = write_archive(sent_argv.nr, sent_argv.v, prefix,
+ the_repository, NULL, 1);
+
+ strvec_clear(&sent_argv);
+ return ret;
}
__attribute__((format (printf, 1, 2)))
diff --git a/bundle-uri.c b/bundle-uri.c
index 1e0ee156ba..dc0c96955b 100644
--- a/bundle-uri.c
+++ b/bundle-uri.c
@@ -13,6 +13,7 @@
#include "config.h"
#include "fetch-pack.h"
#include "remote.h"
+#include "trace2.h"
static struct {
enum bundle_list_heuristic heuristic;
@@ -799,6 +800,8 @@ int fetch_bundle_uri(struct repository *r, const char *uri,
.id = xstrdup(""),
};
+ trace2_region_enter("fetch", "fetch-bundle-uri", the_repository);
+
init_bundle_list(&list);
/*
@@ -824,6 +827,7 @@ cleanup:
for_all_bundles_in_list(&list, unlink_bundle, NULL);
clear_bundle_list(&list);
clear_remote_bundle_info(&bundle, NULL);
+ trace2_region_leave("fetch", "fetch-bundle-uri", the_repository);
return result;
}
diff --git a/bundle.c b/bundle.c
index b0a8a925cb..4773b51eb1 100644
--- a/bundle.c
+++ b/bundle.c
@@ -644,10 +644,8 @@ int unbundle(struct repository *r, struct bundle_header *header,
if (flags & VERIFY_BUNDLE_FSCK)
strvec_push(&ip.args, "--fsck-objects");
- if (extra_index_pack_args) {
+ if (extra_index_pack_args)
strvec_pushv(&ip.args, extra_index_pack_args->v);
- strvec_clear(extra_index_pack_args);
- }
ip.in = bundle_fd;
ip.no_stdout = 1;
diff --git a/compat/mingw.c b/compat/mingw.c
index 29d3f09768..eb13c02a76 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -243,7 +243,8 @@ static enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
static char *unset_environment_variables;
int mingw_core_config(const char *var, const char *value,
- const struct config_context *ctx, void *cb)
+ const struct config_context *ctx UNUSED,
+ void *cb UNUSED)
{
if (!strcmp(var, "core.hidedotfiles")) {
if (value && !strcasecmp(value, "dotgitonly"))
@@ -453,7 +454,7 @@ static int set_hidden_flag(const wchar_t *path, int set)
return -1;
}
-int mingw_mkdir(const char *path, int mode)
+int mingw_mkdir(const char *path, int mode UNUSED)
{
int ret;
wchar_t wpath[MAX_PATH];
@@ -597,7 +598,7 @@ int mingw_open (const char *filename, int oflags, ...)
return fd;
}
-static BOOL WINAPI ctrl_ignore(DWORD type)
+static BOOL WINAPI ctrl_ignore(DWORD type UNUSED)
{
return TRUE;
}
@@ -1085,7 +1086,7 @@ int mkstemp(char *template)
return git_mkstemp_mode(template, 0600);
}
-int gettimeofday(struct timeval *tv, void *tz)
+int gettimeofday(struct timeval *tv, void *tz UNUSED)
{
FILETIME ft;
long long hnsec;
@@ -2252,7 +2253,7 @@ char *mingw_query_user_email(void)
return get_extended_user_info(NameUserPrincipal);
}
-struct passwd *getpwuid(int uid)
+struct passwd *getpwuid(int uid UNUSED)
{
static unsigned initialized;
static char user_name[100];
@@ -2304,7 +2305,7 @@ static sig_handler_t timer_fn = SIG_DFL, sigint_fn = SIG_DFL;
* length to call the signal handler.
*/
-static unsigned __stdcall ticktack(void *dummy)
+static unsigned __stdcall ticktack(void *dummy UNUSED)
{
while (WaitForSingleObject(timer_event, timer_interval) == WAIT_TIMEOUT) {
mingw_raise(SIGALRM);
@@ -2352,7 +2353,7 @@ static inline int is_timeval_eq(const struct timeval *i1, const struct timeval *
return i1->tv_sec == i2->tv_sec && i1->tv_usec == i2->tv_usec;
}
-int setitimer(int type, struct itimerval *in, struct itimerval *out)
+int setitimer(int type UNUSED, struct itimerval *in, struct itimerval *out)
{
static const struct timeval zero;
static int atexit_done;
diff --git a/compat/mingw.h b/compat/mingw.h
index 27b61284f4..ebfb8ba423 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -122,17 +122,17 @@ struct utsname {
* trivial stubs
*/
-static inline int readlink(const char *path, char *buf, size_t bufsiz)
+static inline int readlink(const char *path UNUSED, char *buf UNUSED, size_t bufsiz UNUSED)
{ errno = ENOSYS; return -1; }
-static inline int symlink(const char *oldpath, const char *newpath)
+static inline int symlink(const char *oldpath UNUSED, const char *newpath UNUSED)
{ errno = ENOSYS; return -1; }
-static inline int fchmod(int fildes, mode_t mode)
+static inline int fchmod(int fildes UNUSED, mode_t mode UNUSED)
{ errno = ENOSYS; return -1; }
#ifndef __MINGW64_VERSION_MAJOR
static inline pid_t fork(void)
{ errno = ENOSYS; return -1; }
#endif
-static inline unsigned int alarm(unsigned int seconds)
+static inline unsigned int alarm(unsigned int seconds UNUSED)
{ return 0; }
static inline int fsync(int fd)
{ return _commit(fd); }
@@ -140,9 +140,9 @@ static inline void sync(void)
{}
static inline uid_t getuid(void)
{ return 1; }
-static inline struct passwd *getpwnam(const char *name)
+static inline struct passwd *getpwnam(const char *name UNUSED)
{ return NULL; }
-static inline int fcntl(int fd, int cmd, ...)
+static inline int fcntl(int fd UNUSED, int cmd, ...)
{
if (cmd == F_GETFD || cmd == F_SETFD)
return 0;
@@ -151,17 +151,17 @@ static inline int fcntl(int fd, int cmd, ...)
}
#define sigemptyset(x) (void)0
-static inline int sigaddset(sigset_t *set, int signum)
+static inline int sigaddset(sigset_t *set UNUSED, int signum UNUSED)
{ return 0; }
#define SIG_BLOCK 0
#define SIG_UNBLOCK 0
-static inline int sigprocmask(int how, const sigset_t *set, sigset_t *oldset)
+static inline int sigprocmask(int how UNUSED, const sigset_t *set UNUSED, sigset_t *oldset UNUSED)
{ return 0; }
static inline pid_t getppid(void)
{ return 1; }
static inline pid_t getpgid(pid_t pid)
{ return pid == 0 ? getpid() : pid; }
-static inline pid_t tcgetpgrp(int fd)
+static inline pid_t tcgetpgrp(int fd UNUSED)
{ return getpid(); }
/*
diff --git a/compat/nedmalloc/nedmalloc.c b/compat/nedmalloc/nedmalloc.c
index 2c0ace7075..145255da43 100644
--- a/compat/nedmalloc/nedmalloc.c
+++ b/compat/nedmalloc/nedmalloc.c
@@ -31,6 +31,8 @@ DEALINGS IN THE SOFTWARE.
/*#pragma optimize("a", on)*/
#endif
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+
/*#define FULLSANITYCHECKS*/
#include "nedmalloc.h"
diff --git a/compat/regex/regcomp.c b/compat/regex/regcomp.c
index 6c5d455e92..8d93a9b93f 100644
--- a/compat/regex/regcomp.c
+++ b/compat/regex/regcomp.c
@@ -17,6 +17,8 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+
#if defined __TANDEM
/* This is currently duplicated from git-compat-utils.h */
# ifdef NO_INTPTR_T
diff --git a/compat/stub/procinfo.c b/compat/stub/procinfo.c
index 12c0a23c9e..3168cd5714 100644
--- a/compat/stub/procinfo.c
+++ b/compat/stub/procinfo.c
@@ -6,6 +6,6 @@
* Stub. See sample implementations in compat/linux/procinfo.c and
* compat/win32/trace2_win32_process_info.c.
*/
-void trace2_collect_process_info(enum trace2_process_info_reason reason)
+void trace2_collect_process_info(enum trace2_process_info_reason reason UNUSED)
{
}
diff --git a/compat/terminal.c b/compat/terminal.c
index 0afda730f2..d54efa1c5d 100644
--- a/compat/terminal.c
+++ b/compat/terminal.c
@@ -594,7 +594,7 @@ void restore_term(void)
{
}
-char *git_terminal_prompt(const char *prompt, int echo)
+char *git_terminal_prompt(const char *prompt, int echo UNUSED)
{
return getpass(prompt);
}
diff --git a/compat/win32/headless.c b/compat/win32/headless.c
index 8b00dfe3bd..11392a0b9a 100644
--- a/compat/win32/headless.c
+++ b/compat/win32/headless.c
@@ -11,6 +11,8 @@
#include <stdlib.h>
#include <wchar.h>
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+
/*
* If `dir` contains the path to a Git exec directory, extend `PATH` to
* include the corresponding `bin/` directory (which is where all those
diff --git a/compat/win32/pthread.c b/compat/win32/pthread.c
index 85f8f7920c..58980a529c 100644
--- a/compat/win32/pthread.c
+++ b/compat/win32/pthread.c
@@ -21,7 +21,7 @@ static unsigned __stdcall win32_start_routine(void *arg)
return 0;
}
-int pthread_create(pthread_t *thread, const void *unused,
+int pthread_create(pthread_t *thread, const void *attr UNUSED,
void *(*start_routine)(void *), void *arg)
{
thread->arg = arg;
diff --git a/compat/win32/pthread.h b/compat/win32/pthread.h
index cc3221cb2c..e2b5c4f64c 100644
--- a/compat/win32/pthread.h
+++ b/compat/win32/pthread.h
@@ -18,7 +18,7 @@
*/
#define pthread_mutex_t CRITICAL_SECTION
-static inline int return_0(int i) {
+static inline int return_0(int i UNUSED) {
return 0;
}
#define pthread_mutex_init(a,b) return_0((InitializeCriticalSection((a)), 0))
@@ -70,7 +70,7 @@ static inline void NORETURN pthread_exit(void *ret)
}
typedef DWORD pthread_key_t;
-static inline int pthread_key_create(pthread_key_t *keyp, void (*destructor)(void *value))
+static inline int pthread_key_create(pthread_key_t *keyp, void (*destructor)(void *value) UNUSED)
{
return (*keyp = TlsAlloc()) == TLS_OUT_OF_INDEXES ? EAGAIN : 0;
}
diff --git a/compat/win32/syslog.c b/compat/win32/syslog.c
index 0af18d8882..4e4794743a 100644
--- a/compat/win32/syslog.c
+++ b/compat/win32/syslog.c
@@ -2,7 +2,7 @@
static HANDLE ms_eventlog;
-void openlog(const char *ident, int logopt, int facility)
+void openlog(const char *ident, int logopt UNUSED, int facility UNUSED)
{
if (ms_eventlog)
return;
diff --git a/compat/win32mmap.c b/compat/win32mmap.c
index 519d51f2b6..a4ab4cb939 100644
--- a/compat/win32mmap.c
+++ b/compat/win32mmap.c
@@ -40,7 +40,7 @@ void *git_mmap(void *start, size_t length, int prot, int flags, int fd, off_t of
return MAP_FAILED;
}
-int git_munmap(void *start, size_t length)
+int git_munmap(void *start, size_t length UNUSED)
{
return !UnmapViewOfFile(start);
}
diff --git a/compat/winansi.c b/compat/winansi.c
index 575813bde8..1b3f916b9f 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -340,7 +340,7 @@ enum {
TEXT = 0, ESCAPE = 033, BRACKET = '['
};
-static DWORD WINAPI console_thread(LPVOID unused)
+static DWORD WINAPI console_thread(LPVOID data UNUSED)
{
unsigned char buffer[BUFFER_SIZE];
DWORD bytes;
diff --git a/config.mak.dev b/config.mak.dev
index 5229c35484..50026d1e0e 100644
--- a/config.mak.dev
+++ b/config.mak.dev
@@ -54,7 +54,6 @@ ifeq ($(filter extra-all,$(DEVOPTS)),)
DEVELOPER_CFLAGS += -Wno-empty-body
DEVELOPER_CFLAGS += -Wno-missing-field-initializers
DEVELOPER_CFLAGS += -Wno-sign-compare
-DEVELOPER_CFLAGS += -Wno-unused-parameter
endif
endif
diff --git a/config.mak.uname b/config.mak.uname
index aa0fd26bd5..904bcf3598 100644
--- a/config.mak.uname
+++ b/config.mak.uname
@@ -648,6 +648,7 @@ ifeq ($(uname_S),OS/390)
NO_GECOS_IN_PWENT = YesPlease
HAVE_STRINGS_H = YesPlease
NEEDS_MODE_TRANSLATION = YesPlease
+ HAVE_ZOS_GET_EXECUTABLE_PATH = YesPlease
endif
ifeq ($(uname_S),MINGW)
ifeq ($(shell expr "$(uname_R)" : '1\.'),2)
diff --git a/contrib/completion/git-prompt.sh b/contrib/completion/git-prompt.sh
index 5330e769a7..6186c474ba 100644
--- a/contrib/completion/git-prompt.sh
+++ b/contrib/completion/git-prompt.sh
@@ -8,8 +8,8 @@
# To enable:
#
# 1) Copy this file to somewhere (e.g. ~/.git-prompt.sh).
-# 2) Add the following line to your .bashrc/.zshrc:
-# source ~/.git-prompt.sh
+# 2) Add the following line to your .bashrc/.zshrc/.profile:
+# . ~/.git-prompt.sh # dot path/to/this-file
# 3a) Change your PS1 to call __git_ps1 as
# command-substitution:
# Bash: PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '
@@ -30,6 +30,8 @@
# Optionally, you can supply a third argument with a printf
# format string to finetune the output of the branch status
#
+# See notes below about compatibility with other shells.
+#
# The repository status will be displayed only if you are currently in a
# git repository. The %s token is the placeholder for the shown status.
#
@@ -106,38 +108,78 @@
# directory is set up to be ignored by git, then set
# GIT_PS1_HIDE_IF_PWD_IGNORED to a nonempty value. Override this on the
# repository level by setting bash.hideIfPwdIgnored to "false".
+#
+# Compatibility with other shells (beyond bash/zsh):
+#
+# We require posix-ish shell plus "local" support, which is most
+# shells (even pdksh), but excluding ksh93 (because no "local").
+#
+# Prompt integration might differ between shells, but the gist is
+# to load it once on shell init with '. path/to/git-prompt.sh',
+# set GIT_PS1* vars once as needed, and either place $(__git_ps1..)
+# inside PS1 once (0/1 args), or, before each prompt is displayed,
+# call __git_ps1 (2/3 args) which sets PS1 with the status embedded.
+#
+# Many shells support the 1st method of command substitution,
+# though some might need to first enable cmd substitution in PS1.
+#
+# When using colors, each escape sequence is wrapped between byte
+# values 1 and 2 (control chars SOH, STX, respectively), which are
+# invisible at the output, but for bash/readline they mark 0-width
+# strings (SGR color sequences) when calculating the on-screen
+# prompt width, to maintain correct input editing at the prompt.
+#
+# To replace or disable the 0-width markers, set GIT_PS1_COLOR_PRE
+# and GIT_PS1_COLOR_POST to other markers, or empty (nul) to not
+# use markers. For instance, some shells support '\[' and '\]' as
+# start/end markers in PS1 - when invoking __git_ps1 with 3/4 args,
+# but it may or may not work in command substitution mode. YMMV.
+#
+# If the shell doesn't support 0-width markers and editing behaves
+# incorrectly when using colors in __git_ps1, then, other than
+# disabling color, it might be solved using multi-line prompt,
+# where the git status is not at the last line, e.g.:
+# PS1='\n\w \u@\h$(__git_ps1 " (%s)")\n\$ '
# check whether printf supports -v
__git_printf_supports_v=
printf -v __git_printf_supports_v -- '%s' yes >/dev/null 2>&1
+# like __git_SOH=$'\001' etc but works also in shells without $'...'
+eval "$(printf '
+ __git_SOH="\001" __git_STX="\002" __git_ESC="\033"
+ __git_LF="\n" __git_CRLF="\r\n"
+')"
+
# stores the divergence from upstream in $p
# used by GIT_PS1_SHOWUPSTREAM
__git_ps1_show_upstream ()
{
local key value
- local svn_remote svn_url_pattern count n
+ local svn_remotes="" svn_url_pattern="" count n
local upstream_type=git legacy="" verbose="" name=""
+ local LF="$__git_LF"
- svn_remote=()
# get some config options from git-config
local output="$(git config -z --get-regexp '^(svn-remote\..*\.url|bash\.showupstream)$' 2>/dev/null | tr '\0\n' '\n ')"
while read -r key value; do
case "$key" in
bash.showupstream)
GIT_PS1_SHOWUPSTREAM="$value"
- if [[ -z "${GIT_PS1_SHOWUPSTREAM}" ]]; then
+ if [ -z "${GIT_PS1_SHOWUPSTREAM}" ]; then
p=""
return
fi
;;
svn-remote.*.url)
- svn_remote[$((${#svn_remote[@]} + 1))]="$value"
+ svn_remotes=${svn_remotes}${value}${LF} # URI\nURI\n...
svn_url_pattern="$svn_url_pattern\\|$value"
upstream_type=svn+git # default upstream type is SVN if available, else git
;;
esac
- done <<< "$output"
+ done <<-OUTPUT
+ $output
+ OUTPUT
# parse configuration values
local option
@@ -154,33 +196,45 @@ __git_ps1_show_upstream ()
case "$upstream_type" in
git) upstream_type="@{upstream}" ;;
svn*)
- # get the upstream from the "git-svn-id: ..." in a commit message
- # (git-svn uses essentially the same procedure internally)
- local -a svn_upstream
- svn_upstream=($(git log --first-parent -1 \
- --grep="^git-svn-id: \(${svn_url_pattern#??}\)" 2>/dev/null))
- if [[ 0 -ne ${#svn_upstream[@]} ]]; then
- svn_upstream=${svn_upstream[${#svn_upstream[@]} - 2]}
- svn_upstream=${svn_upstream%@*}
- local n_stop="${#svn_remote[@]}"
- for ((n=1; n <= n_stop; n++)); do
- svn_upstream=${svn_upstream#${svn_remote[$n]}}
- done
+ # successful svn-upstream resolution:
+ # - get the list of configured svn-remotes ($svn_remotes set above)
+ # - get the last commit which seems from one of our svn-remotes
+ # - confirm that it is from one of the svn-remotes
+ # - use $GIT_SVN_ID if set, else "git-svn"
- if [[ -z "$svn_upstream" ]]; then
+ # get upstream from "git-svn-id: UPSTRM@N HASH" in a commit message
+ # (git-svn uses essentially the same procedure internally)
+ local svn_upstream="$(
+ git log --first-parent -1 \
+ --grep="^git-svn-id: \(${svn_url_pattern#??}\)" 2>/dev/null
+ )"
+
+ if [ -n "$svn_upstream" ]; then
+ # extract the URI, assuming --grep matched the last line
+ svn_upstream=${svn_upstream##*$LF} # last line
+ svn_upstream=${svn_upstream#*: } # UPSTRM@N HASH
+ svn_upstream=${svn_upstream%@*} # UPSTRM
+
+ case ${LF}${svn_remotes} in
+ *"${LF}${svn_upstream}${LF}"*)
+ # grep indeed matched the last line - it's our remote
# default branch name for checkouts with no layout:
upstream_type=${GIT_SVN_ID:-git-svn}
- else
+ ;;
+ *)
+ # the commit message includes one of our remotes, but
+ # it's not at the last line. is $svn_upstream junk?
upstream_type=${svn_upstream#/}
- fi
- elif [[ "svn+git" = "$upstream_type" ]]; then
+ ;;
+ esac
+ elif [ "svn+git" = "$upstream_type" ]; then
upstream_type="@{upstream}"
fi
;;
esac
# Find how many commits we are ahead/behind our upstream
- if [[ -z "$legacy" ]]; then
+ if [ -z "$legacy" ]; then
count="$(git rev-list --count --left-right \
"$upstream_type"...HEAD 2>/dev/null)"
else
@@ -192,8 +246,8 @@ __git_ps1_show_upstream ()
for commit in $commits
do
case "$commit" in
- "<"*) ((behind++)) ;;
- *) ((ahead++)) ;;
+ "<"*) behind=$((behind+1)) ;;
+ *) ahead=$((ahead+1)) ;;
esac
done
count="$behind $ahead"
@@ -203,7 +257,7 @@ __git_ps1_show_upstream ()
fi
# calculate the result
- if [[ -z "$verbose" ]]; then
+ if [ -z "$verbose" ]; then
case "$count" in
"") # no upstream
p="" ;;
@@ -229,10 +283,10 @@ __git_ps1_show_upstream ()
*) # diverged from upstream
upstream="|u+${count#* }-${count% *}" ;;
esac
- if [[ -n "$count" && -n "$name" ]]; then
+ if [ -n "$count" ] && [ -n "$name" ]; then
__git_ps1_upstream_name=$(git rev-parse \
--abbrev-ref "$upstream_type" 2>/dev/null)
- if [ $pcmode = yes ] && [ $ps1_expanded = yes ]; then
+ if [ "$pcmode" = yes ] && [ "$ps1_expanded" = yes ]; then
upstream="$upstream \${__git_ps1_upstream_name}"
else
upstream="$upstream ${__git_ps1_upstream_name}"
@@ -251,25 +305,29 @@ __git_ps1_show_upstream ()
# their own color.
__git_ps1_colorize_gitstring ()
{
- if [[ -n ${ZSH_VERSION-} ]]; then
+ if [ -n "${ZSH_VERSION-}" ]; then
local c_red='%F{red}'
local c_green='%F{green}'
local c_lblue='%F{blue}'
local c_clear='%f'
else
- # Using \001 and \002 around colors is necessary to prevent
- # issues with command line editing/browsing/completion!
- local c_red=$'\001\e[31m\002'
- local c_green=$'\001\e[32m\002'
- local c_lblue=$'\001\e[1;34m\002'
- local c_clear=$'\001\e[0m\002'
+ # \001 (SOH) and \002 (STX) are 0-width substring markers
+ # which bash/readline identify while calculating the prompt
+ # on-screen width - to exclude 0-screen-width esc sequences.
+ local c_pre="${GIT_PS1_COLOR_PRE-$__git_SOH}${__git_ESC}["
+ local c_post="m${GIT_PS1_COLOR_POST-$__git_STX}"
+
+ local c_red="${c_pre}31${c_post}"
+ local c_green="${c_pre}32${c_post}"
+ local c_lblue="${c_pre}1;34${c_post}"
+ local c_clear="${c_pre}0${c_post}"
fi
- local bad_color=$c_red
- local ok_color=$c_green
+ local bad_color="$c_red"
+ local ok_color="$c_green"
local flags_color="$c_lblue"
local branch_color=""
- if [ $detached = no ]; then
+ if [ "$detached" = no ]; then
branch_color="$ok_color"
else
branch_color="$bad_color"
@@ -298,7 +356,7 @@ __git_ps1_colorize_gitstring ()
# variable, in that order.
__git_eread ()
{
- test -r "$1" && IFS=$'\r\n' read -r "$2" <"$1"
+ test -r "$1" && IFS=$__git_CRLF read -r "$2" <"$1"
}
# see if a cherry-pick or revert is in progress, if the user has committed a
@@ -346,7 +404,7 @@ __git_sequencer_status ()
__git_ps1 ()
{
# preserve exit status
- local exit=$?
+ local exit="$?"
local pcmode=no
local detached=no
local ps1pc_start='\u@\h:\w '
@@ -365,7 +423,7 @@ __git_ps1 ()
;;
0|1) printf_format="${1:-$printf_format}"
;;
- *) return $exit
+ *) return "$exit"
;;
esac
@@ -403,7 +461,7 @@ __git_ps1 ()
# incorrect.)
#
local ps1_expanded=yes
- [ -z "${ZSH_VERSION-}" ] || [[ -o PROMPT_SUBST ]] || ps1_expanded=no
+ [ -z "${ZSH_VERSION-}" ] || eval '[[ -o PROMPT_SUBST ]]' || ps1_expanded=no
[ -z "${BASH_VERSION-}" ] || shopt -q promptvars || ps1_expanded=no
local repo_info rev_parse_exit_code
@@ -413,29 +471,30 @@ __git_ps1 ()
rev_parse_exit_code="$?"
if [ -z "$repo_info" ]; then
- return $exit
+ return "$exit"
fi
+ local LF="$__git_LF"
local short_sha=""
if [ "$rev_parse_exit_code" = "0" ]; then
- short_sha="${repo_info##*$'\n'}"
- repo_info="${repo_info%$'\n'*}"
+ short_sha="${repo_info##*$LF}"
+ repo_info="${repo_info%$LF*}"
fi
- local ref_format="${repo_info##*$'\n'}"
- repo_info="${repo_info%$'\n'*}"
- local inside_worktree="${repo_info##*$'\n'}"
- repo_info="${repo_info%$'\n'*}"
- local bare_repo="${repo_info##*$'\n'}"
- repo_info="${repo_info%$'\n'*}"
- local inside_gitdir="${repo_info##*$'\n'}"
- local g="${repo_info%$'\n'*}"
+ local ref_format="${repo_info##*$LF}"
+ repo_info="${repo_info%$LF*}"
+ local inside_worktree="${repo_info##*$LF}"
+ repo_info="${repo_info%$LF*}"
+ local bare_repo="${repo_info##*$LF}"
+ repo_info="${repo_info%$LF*}"
+ local inside_gitdir="${repo_info##*$LF}"
+ local g="${repo_info%$LF*}"
if [ "true" = "$inside_worktree" ] &&
[ -n "${GIT_PS1_HIDE_IF_PWD_IGNORED-}" ] &&
[ "$(git config --bool bash.hideIfPwdIgnored)" != "false" ] &&
git check-ignore -q .
then
- return $exit
+ return "$exit"
fi
local sparse=""
@@ -485,14 +544,16 @@ __git_ps1 ()
case "$ref_format" in
files)
if ! __git_eread "$g/HEAD" head; then
- return $exit
+ return "$exit"
fi
- if [[ $head == "ref: "* ]]; then
+ case $head in
+ "ref: "*)
head="${head#ref: }"
- else
+ ;;
+ *)
head=""
- fi
+ esac
;;
*)
head="$(git symbolic-ref HEAD 2>/dev/null)"
@@ -528,8 +589,8 @@ __git_ps1 ()
fi
local conflict="" # state indicator for unresolved conflicts
- if [[ "${GIT_PS1_SHOWCONFLICTSTATE-}" == "yes" ]] &&
- [[ $(git ls-files --unmerged 2>/dev/null) ]]; then
+ if [ "${GIT_PS1_SHOWCONFLICTSTATE-}" = "yes" ] &&
+ [ "$(git ls-files --unmerged 2>/dev/null)" ]; then
conflict="|CONFLICT"
fi
@@ -581,10 +642,10 @@ __git_ps1 ()
fi
fi
- local z="${GIT_PS1_STATESEPARATOR-" "}"
+ local z="${GIT_PS1_STATESEPARATOR- }"
b=${b##refs/heads/}
- if [ $pcmode = yes ] && [ $ps1_expanded = yes ]; then
+ if [ "$pcmode" = yes ] && [ "$ps1_expanded" = yes ]; then
__git_ps1_branch_name=$b
b="\${__git_ps1_branch_name}"
fi
@@ -596,7 +657,7 @@ __git_ps1 ()
local f="$h$w$i$s$u$p"
local gitstring="$c$b${f:+$z$f}${sparse}$r${upstream}${conflict}"
- if [ $pcmode = yes ]; then
+ if [ "$pcmode" = yes ]; then
if [ "${__git_printf_supports_v-}" != yes ]; then
gitstring=$(printf -- "$printf_format" "$gitstring")
else
@@ -607,5 +668,5 @@ __git_ps1 ()
printf -- "$printf_format" "$gitstring"
fi
- return $exit
+ return "$exit"
}
diff --git a/convert.c b/convert.c
index e6184d21f2..c9a31eb4f0 100644
--- a/convert.c
+++ b/convert.c
@@ -1371,6 +1371,9 @@ void reset_parsed_attributes(void)
for (drv = user_convert; drv; drv = next) {
next = drv->next;
free((void *)drv->name);
+ free((void *)drv->smudge);
+ free((void *)drv->clean);
+ free((void *)drv->process);
free(drv);
}
user_convert = NULL;
diff --git a/exec-cmd.c b/exec-cmd.c
index 909777f61f..507e67d528 100644
--- a/exec-cmd.c
+++ b/exec-cmd.c
@@ -150,6 +150,25 @@ static int git_get_exec_path_darwin(struct strbuf *buf)
}
#endif /* HAVE_NS_GET_EXECUTABLE_PATH */
+#ifdef HAVE_ZOS_GET_EXECUTABLE_PATH
+/*
+ * Resolves the executable path from current program's directory and name.
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+static int git_get_exec_path_zos(struct strbuf *buf)
+{
+ char *dir = __getprogramdir();
+ char *exe = getprogname();
+ if (dir && exe) {
+ strbuf_addf(buf, "%s/%s", dir, exe);
+ return 0;
+ }
+ return -1;
+}
+
+#endif /* HAVE_ZOS_GET_EXECUTABLE_PATH */
+
#ifdef HAVE_WPGMPTR
/*
* Resolves the executable path by using the global variable _wpgmptr.
@@ -206,6 +225,10 @@ static int git_get_exec_path(struct strbuf *buf, const char *argv0)
git_get_exec_path_wpgmptr(buf) &&
#endif /* HAVE_WPGMPTR */
+#ifdef HAVE_ZOS_GET_EXECUTABLE_PATH
+ git_get_exec_path_zos(buf) &&
+#endif /*HAVE_ZOS_GET_EXECUTABLE_PATH */
+
git_get_exec_path_from_argv0(buf, argv0)) {
return -1;
}
diff --git a/git-compat-util.h b/git-compat-util.h
index 71b4d23f03..e4a306dd56 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -195,6 +195,19 @@ struct strbuf;
#define _NETBSD_SOURCE 1
#define _SGI_SOURCE 1
+/*
+ * UNUSED marks a function parameter that is always unused. It also
+ * can be used to annotate a function, a variable, or a type that is
+ * always unused.
+ *
+ * A callback interface may dictate that a function accepts a
+ * parameter at that position, but the implementation of the function
+ * may not need to use the parameter. In such a case, mark the parameter
+ * with UNUSED.
+ *
+ * When a parameter may be used or unused, depending on conditional
+ * compilation, consider using MAYBE_UNUSED instead.
+ */
#if GIT_GNUC_PREREQ(4, 5)
#define UNUSED __attribute__((unused)) \
__attribute__((deprecated ("parameter declared as UNUSED")))
@@ -649,6 +662,17 @@ static inline int git_has_dir_sep(const char *path)
#define RESULT_MUST_BE_USED
#endif
+/*
+ * MAYBE_UNUSED marks a function parameter that may be unused, but
+ * whose use is not an error. It also can be used to annotate a
+ * function, a variable, or a type that may be unused.
+ *
+ * Depending on a configuration, all uses of such a thing may become
+ * #ifdef'ed away. Marking it with UNUSED would give a warning in a
+ * compilation where it is indeed used, and not marking it at all
+ * would give a warning in a compilation where it is unused. In such
+ * a case, MAYBE_UNUSED is the appropriate annotation to use.
+ */
#define MAYBE_UNUSED __attribute__((__unused__))
#include "compat/bswap.h"
diff --git a/git-send-email.perl b/git-send-email.perl
index cdcee1d0cf..c835d4c11a 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -47,6 +47,8 @@ git send-email --translate-aliases
--compose-encoding <str> * Encoding to assume for introduction.
--8bit-encoding <str> * Encoding to assume 8bit mails if undeclared
--transfer-encoding <str> * Transfer encoding to use (quoted-printable, 8bit, base64)
+ --[no-]mailmap * Use mailmap file to map all email addresses to canonical
+ real names and email addresses.
Sending:
--envelope-sender <str> * Email envelope sender.
@@ -278,12 +280,14 @@ my (@suppress_cc);
my ($auto_8bit_encoding);
my ($compose_encoding);
my ($sendmail_cmd);
+my ($mailmap_file, $mailmap_blob);
# Variables with corresponding config settings & hardcoded defaults
my ($debug_net_smtp) = 0; # Net::SMTP, see send_message()
my $thread = 1;
my $chain_reply_to = 0;
my $use_xmailer = 1;
my $validate = 1;
+my $mailmap = 0;
my $target_xfer_encoding = 'auto';
my $forbid_sendmail_variables = 1;
@@ -300,6 +304,7 @@ my %config_bool_settings = (
"annotate" => \$annotate,
"xmailer" => \$use_xmailer,
"forbidsendmailvariables" => \$forbid_sendmail_variables,
+ "mailmap" => \$mailmap,
);
my %config_settings = (
@@ -333,6 +338,8 @@ my %config_settings = (
my %config_path_settings = (
"aliasesfile" => \@alias_files,
"smtpsslcertpath" => \$smtp_ssl_cert_path,
+ "mailmap.file" => \$mailmap_file,
+ "mailmap.blob" => \$mailmap_blob,
);
# Handle Uncouth Termination
@@ -533,6 +540,8 @@ my %options = (
"thread!" => \$thread,
"validate!" => \$validate,
"transfer-encoding=s" => \$target_xfer_encoding,
+ "mailmap!" => \$mailmap,
+ "use-mailmap!" => \$mailmap,
"format-patch!" => \$format_patch,
"8bit-encoding=s" => \$auto_8bit_encoding,
"compose-encoding=s" => \$compose_encoding,
@@ -1104,6 +1113,16 @@ if ($compose && $compose > 0) {
our ($message_id, %mail, $subject, $in_reply_to, $references, $message,
$needs_confirm, $message_num, $ask_default);
+sub mailmap_address_list {
+ return @_ unless @_ and $mailmap;
+ my @options = ();
+ push(@options, "--mailmap-file=$mailmap_file") if $mailmap_file;
+ push(@options, "--mailmap-blob=$mailmap_blob") if $mailmap_blob;
+ my @addr_list = Git::command('check-mailmap', @options, @_);
+ s/^<(.*)>$/$1/ for @addr_list;
+ return @addr_list;
+}
+
sub extract_valid_address {
my $address = shift;
my $local_part_regexp = qr/[^<>"\s@]+/;
@@ -1313,6 +1332,7 @@ sub process_address_list {
@addr_list = expand_aliases(@addr_list);
@addr_list = sanitize_address_list(@addr_list);
@addr_list = validate_address_list(@addr_list);
+ @addr_list = mailmap_address_list(@addr_list);
return @addr_list;
}
diff --git a/grep.c b/grep.c
index 2f8b9553df..e5761426e4 100644
--- a/grep.c
+++ b/grep.c
@@ -245,7 +245,7 @@ static int is_fixed(const char *s, size_t len)
#ifdef USE_LIBPCRE2
#define GREP_PCRE2_DEBUG_MALLOC 0
-static void *pcre2_malloc(PCRE2_SIZE size, MAYBE_UNUSED void *memory_data)
+static void *pcre2_malloc(PCRE2_SIZE size, void *memory_data UNUSED)
{
void *pointer = malloc(size);
#if GREP_PCRE2_DEBUG_MALLOC
@@ -255,7 +255,7 @@ static void *pcre2_malloc(PCRE2_SIZE size, MAYBE_UNUSED void *memory_data)
return pointer;
}
-static void pcre2_free(void *pointer, MAYBE_UNUSED void *memory_data)
+static void pcre2_free(void *pointer, void *memory_data UNUSED)
{
#if GREP_PCRE2_DEBUG_MALLOC
static int count = 1;
diff --git a/mailinfo.c b/mailinfo.c
index 95228531a6..d1f42bd7e3 100644
--- a/mailinfo.c
+++ b/mailinfo.c
@@ -348,9 +348,8 @@ static void cleanup_subject(struct mailinfo *mi, struct strbuf *subject)
strbuf_trim(subject);
}
-#define MAX_HDR_PARSED 10
-static const char *header[MAX_HDR_PARSED] = {
- "From","Subject","Date",
+static const char * const header[] = {
+ "From", "Subject", "Date",
};
static inline int skip_header(const struct strbuf *line, const char *hdr,
@@ -585,7 +584,7 @@ static int check_header(struct mailinfo *mi,
struct strbuf sb = STRBUF_INIT;
/* search for the interesting parts */
- for (i = 0; header[i]; i++) {
+ for (i = 0; i < ARRAY_SIZE(header); i++) {
if ((!hdr_data[i] || overwrite) &&
parse_header(line, header[i], mi, &sb)) {
handle_header(&hdr_data[i], &sb);
@@ -627,7 +626,7 @@ static int is_inbody_header(const struct mailinfo *mi,
{
int i;
const char *val;
- for (i = 0; header[i]; i++)
+ for (i = 0; i < ARRAY_SIZE(header); i++)
if (!mi->s_hdr_data[i] && skip_header(line, header[i], &val))
return 1;
return 0;
@@ -774,7 +773,7 @@ static int check_inbody_header(struct mailinfo *mi, const struct strbuf *line)
return is_format_patch_separator(line->buf + 1, line->len - 1);
if (starts_with(line->buf, "[PATCH]") && isspace(line->buf[7])) {
int i;
- for (i = 0; header[i]; i++)
+ for (i = 0; i < ARRAY_SIZE(header); i++)
if (!strcmp("Subject", header[i])) {
handle_header(&mi->s_hdr_data[i], line);
return 1;
@@ -826,7 +825,7 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)
* We may have already read "secondary headers"; purge
* them to give ourselves a clean restart.
*/
- for (i = 0; header[i]; i++) {
+ for (i = 0; i < ARRAY_SIZE(header); i++) {
if (mi->s_hdr_data[i])
strbuf_release(mi->s_hdr_data[i]);
FREE_AND_NULL(mi->s_hdr_data[i]);
@@ -1157,7 +1156,7 @@ static void handle_info(struct mailinfo *mi)
struct strbuf *hdr;
int i;
- for (i = 0; header[i]; i++) {
+ for (i = 0; i < ARRAY_SIZE(header); i++) {
/* only print inbody headers if we output a patch file */
if (mi->patch_lines && mi->s_hdr_data[i])
hdr = mi->s_hdr_data[i];
@@ -1208,8 +1207,8 @@ int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)
return -1;
}
- mi->p_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->p_hdr_data)));
- mi->s_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->s_hdr_data)));
+ mi->p_hdr_data = xcalloc(ARRAY_SIZE(header), sizeof(*(mi->p_hdr_data)));
+ mi->s_hdr_data = xcalloc(ARRAY_SIZE(header), sizeof(*(mi->s_hdr_data)));
do {
peek = fgetc(mi->input);
@@ -1292,8 +1291,21 @@ void clear_mailinfo(struct mailinfo *mi)
strbuf_release(&mi->inbody_header_accum);
free(mi->message_id);
- strbuf_list_free(mi->p_hdr_data);
- strbuf_list_free(mi->s_hdr_data);
+ for (size_t i = 0; i < ARRAY_SIZE(header); i++) {
+ if (!mi->p_hdr_data[i])
+ continue;
+ strbuf_release(mi->p_hdr_data[i]);
+ free(mi->p_hdr_data[i]);
+ }
+ free(mi->p_hdr_data);
+
+ for (size_t i = 0; i < ARRAY_SIZE(header); i++) {
+ if (!mi->s_hdr_data[i])
+ continue;
+ strbuf_release(mi->s_hdr_data[i]);
+ free(mi->s_hdr_data[i]);
+ }
+ free(mi->s_hdr_data);
while (mi->content < mi->content_top) {
free(*(mi->content_top));
diff --git a/mailmap.c b/mailmap.c
index 2acf97f307..9f9fa3199a 100644
--- a/mailmap.c
+++ b/mailmap.c
@@ -142,11 +142,8 @@ static void read_mailmap_line(struct string_list *map, char *buffer)
add_mapping(map, name1, email1, name2, email2);
}
-/* Flags for read_mailmap_file() */
-#define MAILMAP_NOFOLLOW (1<<0)
-
-static int read_mailmap_file(struct string_list *map, const char *filename,
- unsigned flags)
+int read_mailmap_file(struct string_list *map, const char *filename,
+ unsigned flags)
{
char buffer[1024];
FILE *f;
@@ -186,7 +183,7 @@ static void read_mailmap_string(struct string_list *map, char *buf)
}
}
-static int read_mailmap_blob(struct string_list *map, const char *name)
+int read_mailmap_blob(struct string_list *map, const char *name)
{
struct object_id oid;
char *buf;
diff --git a/mailmap.h b/mailmap.h
index cbda9bc5e0..908365e1bf 100644
--- a/mailmap.h
+++ b/mailmap.h
@@ -6,6 +6,13 @@ struct string_list;
extern char *git_mailmap_file;
extern char *git_mailmap_blob;
+/* Flags for read_mailmap_file() */
+#define MAILMAP_NOFOLLOW (1<<0)
+
+int read_mailmap_file(struct string_list *map, const char *filename,
+ unsigned flags);
+int read_mailmap_blob(struct string_list *map, const char *name);
+
int read_mailmap(struct string_list *map);
void clear_mailmap(struct string_list *map);
diff --git a/mergetools/vscode b/mergetools/vscode
new file mode 100644
index 0000000000..3b39b458d6
--- /dev/null
+++ b/mergetools/vscode
@@ -0,0 +1,19 @@
+diff_cmd () {
+ "$merge_tool_path" --wait --diff "$LOCAL" "$REMOTE"
+}
+
+diff_cmd_help () {
+ echo "Use Visual Studio Code (requires a graphical session)"
+}
+
+merge_cmd () {
+ "$merge_tool_path" --wait --merge "$REMOTE" "$LOCAL" "$BASE" "$MERGED"
+}
+
+merge_cmd_help () {
+ echo "Use Visual Studio Code (requires a graphical session)"
+}
+
+translate_merge_tool_path () {
+ echo code
+}
diff --git a/midx-write.c b/midx-write.c
index c7413ae3ca..1ef62c4f4b 100644
--- a/midx-write.c
+++ b/midx-write.c
@@ -1306,6 +1306,18 @@ static int write_midx_internal(const char *object_dir,
pack_name_concat_len += MIDX_CHUNK_ALIGNMENT -
(pack_name_concat_len % MIDX_CHUNK_ALIGNMENT);
+ if (ctx.nr - dropped_packs == 0) {
+ error(_("no pack files to index."));
+ result = 1;
+ goto cleanup;
+ }
+
+ if (!ctx.entries_nr) {
+ if (flags & MIDX_WRITE_BITMAP)
+ warning(_("refusing to write multi-pack .bitmap without any objects"));
+ flags &= ~(MIDX_WRITE_REV_INDEX | MIDX_WRITE_BITMAP);
+ }
+
if (ctx.incremental) {
struct strbuf lock_name = STRBUF_INIT;
@@ -1331,18 +1343,6 @@ static int write_midx_internal(const char *object_dir,
f = hashfd(get_lock_file_fd(&lk), get_lock_file_path(&lk));
}
- if (ctx.nr - dropped_packs == 0) {
- error(_("no pack files to index."));
- result = 1;
- goto cleanup;
- }
-
- if (!ctx.entries_nr) {
- if (flags & MIDX_WRITE_BITMAP)
- warning(_("refusing to write multi-pack .bitmap without any objects"));
- flags &= ~(MIDX_WRITE_REV_INDEX | MIDX_WRITE_BITMAP);
- }
-
cf = init_chunkfile(f);
add_chunk(cf, MIDX_CHUNKID_PACKNAMES, pack_name_concat_len,
diff --git a/pager.c b/pager.c
index 896f40fcd2..9c24ce6263 100644
--- a/pager.c
+++ b/pager.c
@@ -234,6 +234,8 @@ int term_columns(void)
*/
void term_clear_line(void)
{
+ if (!isatty(2))
+ return;
if (is_terminal_dumb())
/*
* Fall back to print a terminal width worth of space
diff --git a/pretty.c b/pretty.c
index 44222fb83c..5e5ae45253 100644
--- a/pretty.c
+++ b/pretty.c
@@ -63,7 +63,7 @@ static int git_pretty_formats_config(const char *var, const char *value,
void *cb UNUSED)
{
struct cmt_fmt_map *commit_format = NULL;
- const char *name;
+ const char *name, *stripped;
char *fmt;
int i;
@@ -90,15 +90,21 @@ static int git_pretty_formats_config(const char *var, const char *value,
commit_formats_len++;
}
+ free((char *)commit_format->name);
commit_format->name = xstrdup(name);
commit_format->format = CMIT_FMT_USERFORMAT;
if (git_config_string(&fmt, var, value))
return -1;
- if (skip_prefix(fmt, "format:", &commit_format->user_format)) {
+ free((char *)commit_format->user_format);
+ if (skip_prefix(fmt, "format:", &stripped)) {
commit_format->is_tformat = 0;
- } else if (skip_prefix(fmt, "tformat:", &commit_format->user_format)) {
+ commit_format->user_format = xstrdup(stripped);
+ free(fmt);
+ } else if (skip_prefix(fmt, "tformat:", &stripped)) {
commit_format->is_tformat = 1;
+ commit_format->user_format = xstrdup(stripped);
+ free(fmt);
} else if (strchr(fmt, '%')) {
commit_format->is_tformat = 1;
commit_format->user_format = fmt;
@@ -1770,6 +1776,7 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
}
trailer_out:
string_list_clear(&filter_list, 0);
+ strbuf_release(&kvsepbuf);
strbuf_release(&sepbuf);
return ret;
}
diff --git a/refs/files-backend.c b/refs/files-backend.c
index 1cff65f6ae..4c5573b19c 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -1946,10 +1946,13 @@ static int commit_ref_update(struct files_ref_store *refs,
return 0;
}
+#ifdef NO_SYMLINK_HEAD
+#define create_ref_symlink(a, b) (-1)
+#else
static int create_ref_symlink(struct ref_lock *lock, const char *target)
{
int ret = -1;
-#ifndef NO_SYMLINK_HEAD
+
char *ref_path = get_locked_file_path(&lock->lk);
unlink(ref_path);
ret = symlink(target, ref_path);
@@ -1957,9 +1960,9 @@ static int create_ref_symlink(struct ref_lock *lock, const char *target)
if (ret)
fprintf(stderr, "no symlink - falling back to symbolic ref\n");
-#endif
return ret;
}
+#endif
static int create_symref_lock(struct ref_lock *lock, const char *target,
struct strbuf *err)
diff --git a/reftable/block_test.c b/reftable/block_test.c
deleted file mode 100644
index f8e31d2d3c..0000000000
--- a/reftable/block_test.c
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
-Copyright 2020 Google LLC
-
-Use of this source code is governed by a BSD-style
-license that can be found in the LICENSE file or at
-https://developers.google.com/open-source/licenses/bsd
-*/
-
-#include "block.h"
-
-#include "system.h"
-#include "blocksource.h"
-#include "basics.h"
-#include "constants.h"
-#include "record.h"
-#include "test_framework.h"
-#include "reftable-tests.h"
-
-static void test_block_read_write(void)
-{
- const int header_off = 21; /* random */
- char *names[30];
- const int N = ARRAY_SIZE(names);
- const int block_size = 1024;
- struct reftable_block block = { NULL };
- struct block_writer bw = {
- .last_key = STRBUF_INIT,
- };
- struct reftable_record rec = {
- .type = BLOCK_TYPE_REF,
- };
- int i = 0;
- int n;
- struct block_reader br = { 0 };
- struct block_iter it = BLOCK_ITER_INIT;
- int j = 0;
- struct strbuf want = STRBUF_INIT;
-
- REFTABLE_CALLOC_ARRAY(block.data, block_size);
- block.len = block_size;
- block.source = malloc_block_source();
- block_writer_init(&bw, BLOCK_TYPE_REF, block.data, block_size,
- header_off, hash_size(GIT_SHA1_FORMAT_ID));
-
- rec.u.ref.refname = (char *) "";
- rec.u.ref.value_type = REFTABLE_REF_DELETION;
- n = block_writer_add(&bw, &rec);
- EXPECT(n == REFTABLE_API_ERROR);
-
- for (i = 0; i < N; i++) {
- char name[100];
- snprintf(name, sizeof(name), "branch%02d", i);
-
- rec.u.ref.refname = name;
- rec.u.ref.value_type = REFTABLE_REF_VAL1;
- memset(rec.u.ref.value.val1, i, GIT_SHA1_RAWSZ);
-
- names[i] = xstrdup(name);
- n = block_writer_add(&bw, &rec);
- rec.u.ref.refname = NULL;
- rec.u.ref.value_type = REFTABLE_REF_DELETION;
- EXPECT(n == 0);
- }
-
- n = block_writer_finish(&bw);
- EXPECT(n > 0);
-
- block_writer_release(&bw);
-
- block_reader_init(&br, &block, header_off, block_size, GIT_SHA1_RAWSZ);
-
- block_iter_seek_start(&it, &br);
-
- while (1) {
- int r = block_iter_next(&it, &rec);
- EXPECT(r >= 0);
- if (r > 0) {
- break;
- }
- EXPECT_STREQ(names[j], rec.u.ref.refname);
- j++;
- }
-
- reftable_record_release(&rec);
- block_iter_close(&it);
-
- for (i = 0; i < N; i++) {
- struct block_iter it = BLOCK_ITER_INIT;
- strbuf_reset(&want);
- strbuf_addstr(&want, names[i]);
-
- n = block_iter_seek_key(&it, &br, &want);
- EXPECT(n == 0);
-
- n = block_iter_next(&it, &rec);
- EXPECT(n == 0);
-
- EXPECT_STREQ(names[i], rec.u.ref.refname);
-
- want.len--;
- n = block_iter_seek_key(&it, &br, &want);
- EXPECT(n == 0);
-
- n = block_iter_next(&it, &rec);
- EXPECT(n == 0);
- EXPECT_STREQ(names[10 * (i / 10)], rec.u.ref.refname);
-
- block_iter_close(&it);
- }
-
- reftable_record_release(&rec);
- reftable_block_done(&br.block);
- strbuf_release(&want);
- for (i = 0; i < N; i++) {
- reftable_free(names[i]);
- }
-}
-
-int block_test_main(int argc UNUSED, const char *argv[] UNUSED)
-{
- RUN_TEST(test_block_read_write);
- return 0;
-}
diff --git a/reftable/blocksource.c b/reftable/blocksource.c
index abce4bb2e1..e93cac9bb6 100644
--- a/reftable/blocksource.c
+++ b/reftable/blocksource.c
@@ -55,26 +55,6 @@ void block_source_from_strbuf(struct reftable_block_source *bs,
bs->arg = buf;
}
-static void malloc_return_block(void *b UNUSED, struct reftable_block *dest)
-{
- if (dest->len)
- memset(dest->data, 0xff, dest->len);
- reftable_free(dest->data);
-}
-
-static struct reftable_block_source_vtable malloc_vtable = {
- .return_block = &malloc_return_block,
-};
-
-static struct reftable_block_source malloc_block_source_instance = {
- .ops = &malloc_vtable,
-};
-
-struct reftable_block_source malloc_block_source(void)
-{
- return malloc_block_source_instance;
-}
-
struct file_block_source {
uint64_t size;
unsigned char *data;
diff --git a/reftable/blocksource.h b/reftable/blocksource.h
index 072e2727ad..659a27b406 100644
--- a/reftable/blocksource.h
+++ b/reftable/blocksource.h
@@ -17,6 +17,4 @@ struct reftable_block_source;
void block_source_from_strbuf(struct reftable_block_source *bs,
struct strbuf *buf);
-struct reftable_block_source malloc_block_source(void);
-
#endif
diff --git a/reftable/dump.c b/reftable/dump.c
deleted file mode 100644
index dd65d9e8bb..0000000000
--- a/reftable/dump.c
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
-Copyright 2020 Google LLC
-
-Use of this source code is governed by a BSD-style
-license that can be found in the LICENSE file or at
-https://developers.google.com/open-source/licenses/bsd
-*/
-
-#include "git-compat-util.h"
-#include "hash.h"
-
-#include "reftable-blocksource.h"
-#include "reftable-error.h"
-#include "reftable-record.h"
-#include "reftable-tests.h"
-#include "reftable-writer.h"
-#include "reftable-iterator.h"
-#include "reftable-reader.h"
-#include "reftable-stack.h"
-
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-
-static int compact_stack(const char *stackdir)
-{
- struct reftable_stack *stack = NULL;
- struct reftable_write_options opts = { 0 };
-
- int err = reftable_new_stack(&stack, stackdir, &opts);
- if (err < 0)
- goto done;
-
- err = reftable_stack_compact_all(stack, NULL);
- if (err < 0)
- goto done;
-done:
- if (stack) {
- reftable_stack_destroy(stack);
- }
- return err;
-}
-
-static void print_help(void)
-{
- printf("usage: dump [-cst] arg\n\n"
- "options: \n"
- " -c compact\n"
- " -b dump blocks\n"
- " -t dump table\n"
- " -s dump stack\n"
- " -6 sha256 hash format\n"
- " -h this help\n"
- "\n");
-}
-
-int reftable_dump_main(int argc, char *const *argv)
-{
- int err = 0;
- int opt_dump_blocks = 0;
- int opt_dump_table = 0;
- int opt_dump_stack = 0;
- int opt_compact = 0;
- uint32_t opt_hash_id = GIT_SHA1_FORMAT_ID;
- const char *arg = NULL, *argv0 = argv[0];
-
- for (; argc > 1; argv++, argc--)
- if (*argv[1] != '-')
- break;
- else if (!strcmp("-b", argv[1]))
- opt_dump_blocks = 1;
- else if (!strcmp("-t", argv[1]))
- opt_dump_table = 1;
- else if (!strcmp("-6", argv[1]))
- opt_hash_id = GIT_SHA256_FORMAT_ID;
- else if (!strcmp("-s", argv[1]))
- opt_dump_stack = 1;
- else if (!strcmp("-c", argv[1]))
- opt_compact = 1;
- else if (!strcmp("-?", argv[1]) || !strcmp("-h", argv[1])) {
- print_help();
- return 2;
- }
-
- if (argc != 2) {
- fprintf(stderr, "need argument\n");
- print_help();
- return 2;
- }
-
- arg = argv[1];
-
- if (opt_dump_blocks) {
- err = reftable_reader_print_blocks(arg);
- } else if (opt_dump_table) {
- err = reftable_reader_print_file(arg);
- } else if (opt_dump_stack) {
- err = reftable_stack_print_directory(arg, opt_hash_id);
- } else if (opt_compact) {
- err = compact_stack(arg);
- }
-
- if (err < 0) {
- fprintf(stderr, "%s: %s: %s\n", argv0, arg,
- reftable_error_str(err));
- return 1;
- }
- return 0;
-}
diff --git a/reftable/generic.c b/reftable/generic.c
deleted file mode 100644
index a00725d9c4..0000000000
--- a/reftable/generic.c
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
-Copyright 2020 Google LLC
-
-Use of this source code is governed by a BSD-style
-license that can be found in the LICENSE file or at
-https://developers.google.com/open-source/licenses/bsd
-*/
-
-#include "constants.h"
-#include "record.h"
-#include "generic.h"
-#include "reftable-iterator.h"
-#include "reftable-generic.h"
-
-void table_init_iter(struct reftable_table *tab,
- struct reftable_iterator *it,
- uint8_t typ)
-{
-
- tab->ops->init_iter(tab->table_arg, it, typ);
-}
-
-void reftable_table_init_ref_iter(struct reftable_table *tab,
- struct reftable_iterator *it)
-{
- table_init_iter(tab, it, BLOCK_TYPE_REF);
-}
-
-void reftable_table_init_log_iter(struct reftable_table *tab,
- struct reftable_iterator *it)
-{
- table_init_iter(tab, it, BLOCK_TYPE_LOG);
-}
-
-int reftable_iterator_seek_ref(struct reftable_iterator *it,
- const char *name)
-{
- struct reftable_record want = {
- .type = BLOCK_TYPE_REF,
- .u.ref = {
- .refname = (char *)name,
- },
- };
- return it->ops->seek(it->iter_arg, &want);
-}
-
-int reftable_iterator_seek_log_at(struct reftable_iterator *it,
- const char *name, uint64_t update_index)
-{
- struct reftable_record want = {
- .type = BLOCK_TYPE_LOG,
- .u.log = {
- .refname = (char *)name,
- .update_index = update_index,
- },
- };
- return it->ops->seek(it->iter_arg, &want);
-}
-
-int reftable_iterator_seek_log(struct reftable_iterator *it,
- const char *name)
-{
- return reftable_iterator_seek_log_at(it, name, ~((uint64_t) 0));
-}
-
-int reftable_table_read_ref(struct reftable_table *tab, const char *name,
- struct reftable_ref_record *ref)
-{
- struct reftable_iterator it = { NULL };
- int err;
-
- reftable_table_init_ref_iter(tab, &it);
-
- err = reftable_iterator_seek_ref(&it, name);
- if (err)
- goto done;
-
- err = reftable_iterator_next_ref(&it, ref);
- if (err)
- goto done;
-
- if (strcmp(ref->refname, name) ||
- reftable_ref_record_is_deletion(ref)) {
- reftable_ref_record_release(ref);
- err = 1;
- goto done;
- }
-
-done:
- reftable_iterator_destroy(&it);
- return err;
-}
-
-int reftable_table_print(struct reftable_table *tab) {
- struct reftable_iterator it = { NULL };
- struct reftable_ref_record ref = { NULL };
- struct reftable_log_record log = { NULL };
- uint32_t hash_id = reftable_table_hash_id(tab);
- int err;
-
- reftable_table_init_ref_iter(tab, &it);
-
- err = reftable_iterator_seek_ref(&it, "");
- if (err < 0)
- return err;
-
- while (1) {
- err = reftable_iterator_next_ref(&it, &ref);
- if (err > 0) {
- break;
- }
- if (err < 0) {
- return err;
- }
- reftable_ref_record_print(&ref, hash_id);
- }
- reftable_iterator_destroy(&it);
- reftable_ref_record_release(&ref);
-
- reftable_table_init_log_iter(tab, &it);
-
- err = reftable_iterator_seek_log(&it, "");
- if (err < 0)
- return err;
-
- while (1) {
- err = reftable_iterator_next_log(&it, &log);
- if (err > 0) {
- break;
- }
- if (err < 0) {
- return err;
- }
- reftable_log_record_print(&log, hash_id);
- }
- reftable_iterator_destroy(&it);
- reftable_log_record_release(&log);
- return 0;
-}
-
-uint64_t reftable_table_max_update_index(struct reftable_table *tab)
-{
- return tab->ops->max_update_index(tab->table_arg);
-}
-
-uint64_t reftable_table_min_update_index(struct reftable_table *tab)
-{
- return tab->ops->min_update_index(tab->table_arg);
-}
-
-uint32_t reftable_table_hash_id(struct reftable_table *tab)
-{
- return tab->ops->hash_id(tab->table_arg);
-}
-
-void reftable_iterator_destroy(struct reftable_iterator *it)
-{
- if (!it->ops) {
- return;
- }
- it->ops->close(it->iter_arg);
- it->ops = NULL;
- FREE_AND_NULL(it->iter_arg);
-}
-
-int reftable_iterator_next_ref(struct reftable_iterator *it,
- struct reftable_ref_record *ref)
-{
- struct reftable_record rec = {
- .type = BLOCK_TYPE_REF,
- .u = {
- .ref = *ref
- },
- };
- int err = iterator_next(it, &rec);
- *ref = rec.u.ref;
- return err;
-}
-
-int reftable_iterator_next_log(struct reftable_iterator *it,
- struct reftable_log_record *log)
-{
- struct reftable_record rec = {
- .type = BLOCK_TYPE_LOG,
- .u = {
- .log = *log,
- },
- };
- int err = iterator_next(it, &rec);
- *log = rec.u.log;
- return err;
-}
-
-int iterator_seek(struct reftable_iterator *it, struct reftable_record *want)
-{
- return it->ops->seek(it->iter_arg, want);
-}
-
-int iterator_next(struct reftable_iterator *it, struct reftable_record *rec)
-{
- return it->ops->next(it->iter_arg, rec);
-}
-
-static int empty_iterator_seek(void *arg UNUSED,
- struct reftable_record *want UNUSED)
-{
- return 0;
-}
-
-static int empty_iterator_next(void *arg UNUSED,
- struct reftable_record *rec UNUSED)
-{
- return 1;
-}
-
-static void empty_iterator_close(void *arg UNUSED)
-{
-}
-
-static struct reftable_iterator_vtable empty_vtable = {
- .seek = &empty_iterator_seek,
- .next = &empty_iterator_next,
- .close = &empty_iterator_close,
-};
-
-void iterator_set_empty(struct reftable_iterator *it)
-{
- assert(!it->ops);
- it->iter_arg = NULL;
- it->ops = &empty_vtable;
-}
diff --git a/reftable/generic.h b/reftable/generic.h
deleted file mode 100644
index 8341fa570e..0000000000
--- a/reftable/generic.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
-Copyright 2020 Google LLC
-
-Use of this source code is governed by a BSD-style
-license that can be found in the LICENSE file or at
-https://developers.google.com/open-source/licenses/bsd
-*/
-
-#ifndef GENERIC_H
-#define GENERIC_H
-
-#include "record.h"
-#include "reftable-generic.h"
-
-/* generic interface to reftables */
-struct reftable_table_vtable {
- void (*init_iter)(void *tab, struct reftable_iterator *it, uint8_t typ);
- uint32_t (*hash_id)(void *tab);
- uint64_t (*min_update_index)(void *tab);
- uint64_t (*max_update_index)(void *tab);
-};
-
-void table_init_iter(struct reftable_table *tab,
- struct reftable_iterator *it,
- uint8_t typ);
-
-struct reftable_iterator_vtable {
- int (*seek)(void *iter_arg, struct reftable_record *want);
- int (*next)(void *iter_arg, struct reftable_record *rec);
- void (*close)(void *iter_arg);
-};
-
-void iterator_set_empty(struct reftable_iterator *it);
-int iterator_seek(struct reftable_iterator *it, struct reftable_record *want);
-int iterator_next(struct reftable_iterator *it, struct reftable_record *rec);
-
-#endif
diff --git a/reftable/iter.c b/reftable/iter.c
index 9e8b2952fd..416a9f6996 100644
--- a/reftable/iter.c
+++ b/reftable/iter.c
@@ -11,11 +11,47 @@ https://developers.google.com/open-source/licenses/bsd
#include "system.h"
#include "block.h"
-#include "generic.h"
#include "constants.h"
#include "reader.h"
#include "reftable-error.h"
+int iterator_seek(struct reftable_iterator *it, struct reftable_record *want)
+{
+ return it->ops->seek(it->iter_arg, want);
+}
+
+int iterator_next(struct reftable_iterator *it, struct reftable_record *rec)
+{
+ return it->ops->next(it->iter_arg, rec);
+}
+
+static int empty_iterator_seek(void *arg UNUSED, struct reftable_record *want UNUSED)
+{
+ return 0;
+}
+
+static int empty_iterator_next(void *arg UNUSED, struct reftable_record *rec UNUSED)
+{
+ return 1;
+}
+
+static void empty_iterator_close(void *arg UNUSED)
+{
+}
+
+static struct reftable_iterator_vtable empty_vtable = {
+ .seek = &empty_iterator_seek,
+ .next = &empty_iterator_next,
+ .close = &empty_iterator_close,
+};
+
+void iterator_set_empty(struct reftable_iterator *it)
+{
+ assert(!it->ops);
+ it->iter_arg = NULL;
+ it->ops = &empty_vtable;
+}
+
static void filtering_ref_iterator_close(void *iter_arg)
{
struct filtering_ref_iterator *fri = iter_arg;
@@ -42,26 +78,6 @@ static int filtering_ref_iterator_next(void *iter_arg,
break;
}
- if (fri->double_check) {
- struct reftable_iterator it = { NULL };
-
- reftable_table_init_ref_iter(&fri->tab, &it);
-
- err = reftable_iterator_seek_ref(&it, ref->refname);
- if (err == 0)
- err = reftable_iterator_next_ref(&it, ref);
-
- reftable_iterator_destroy(&it);
-
- if (err < 0) {
- break;
- }
-
- if (err > 0) {
- continue;
- }
- }
-
if (ref->value_type == REFTABLE_REF_VAL2 &&
(!memcmp(fri->oid.buf, ref->value.val2.target_value,
fri->oid.len) ||
@@ -202,3 +218,71 @@ void iterator_from_indexed_table_ref_iter(struct reftable_iterator *it,
it->iter_arg = itr;
it->ops = &indexed_table_ref_iter_vtable;
}
+
+void reftable_iterator_destroy(struct reftable_iterator *it)
+{
+ if (!it->ops)
+ return;
+ it->ops->close(it->iter_arg);
+ it->ops = NULL;
+ FREE_AND_NULL(it->iter_arg);
+}
+
+int reftable_iterator_seek_ref(struct reftable_iterator *it,
+ const char *name)
+{
+ struct reftable_record want = {
+ .type = BLOCK_TYPE_REF,
+ .u.ref = {
+ .refname = (char *)name,
+ },
+ };
+ return it->ops->seek(it->iter_arg, &want);
+}
+
+int reftable_iterator_next_ref(struct reftable_iterator *it,
+ struct reftable_ref_record *ref)
+{
+ struct reftable_record rec = {
+ .type = BLOCK_TYPE_REF,
+ .u = {
+ .ref = *ref
+ },
+ };
+ int err = iterator_next(it, &rec);
+ *ref = rec.u.ref;
+ return err;
+}
+
+int reftable_iterator_seek_log_at(struct reftable_iterator *it,
+ const char *name, uint64_t update_index)
+{
+ struct reftable_record want = {
+ .type = BLOCK_TYPE_LOG,
+ .u.log = {
+ .refname = (char *)name,
+ .update_index = update_index,
+ },
+ };
+ return it->ops->seek(it->iter_arg, &want);
+}
+
+int reftable_iterator_seek_log(struct reftable_iterator *it,
+ const char *name)
+{
+ return reftable_iterator_seek_log_at(it, name, ~((uint64_t) 0));
+}
+
+int reftable_iterator_next_log(struct reftable_iterator *it,
+ struct reftable_log_record *log)
+{
+ struct reftable_record rec = {
+ .type = BLOCK_TYPE_LOG,
+ .u = {
+ .log = *log,
+ },
+ };
+ int err = iterator_next(it, &rec);
+ *log = rec.u.log;
+ return err;
+}
diff --git a/reftable/iter.h b/reftable/iter.h
index 537431baba..befc4597df 100644
--- a/reftable/iter.h
+++ b/reftable/iter.h
@@ -14,12 +14,36 @@ https://developers.google.com/open-source/licenses/bsd
#include "record.h"
#include "reftable-iterator.h"
-#include "reftable-generic.h"
+
+/*
+ * The virtual function table for implementing generic reftable iterators.
+ */
+struct reftable_iterator_vtable {
+ int (*seek)(void *iter_arg, struct reftable_record *want);
+ int (*next)(void *iter_arg, struct reftable_record *rec);
+ void (*close)(void *iter_arg);
+};
+
+/*
+ * Position the iterator at the wanted record such that a call to
+ * `iterator_next()` would return that record, if it exists.
+ */
+int iterator_seek(struct reftable_iterator *it, struct reftable_record *want);
+
+/*
+ * Yield the next record and advance the iterator. Returns <0 on error, 0 when
+ * a record was yielded, and >0 when the iterator hit an error.
+ */
+int iterator_next(struct reftable_iterator *it, struct reftable_record *rec);
+
+/*
+ * Set up the iterator such that it behaves the same as an iterator with no
+ * entries.
+ */
+void iterator_set_empty(struct reftable_iterator *it);
/* iterator that produces only ref records that point to `oid` */
struct filtering_ref_iterator {
- int double_check;
- struct reftable_table tab;
struct strbuf oid;
struct reftable_iterator it;
};
diff --git a/reftable/merged.c b/reftable/merged.c
index 6adce44f4b..128a810c55 100644
--- a/reftable/merged.c
+++ b/reftable/merged.c
@@ -11,8 +11,8 @@ https://developers.google.com/open-source/licenses/bsd
#include "constants.h"
#include "iter.h"
#include "pq.h"
+#include "reader.h"
#include "record.h"
-#include "generic.h"
#include "reftable-merged.h"
#include "reftable-error.h"
#include "system.h"
@@ -25,7 +25,7 @@ struct merged_subiter {
struct merged_iter {
struct merged_subiter *subiters;
struct merged_iter_pqueue pq;
- size_t stack_len;
+ size_t subiters_len;
int suppress_deletions;
ssize_t advance_index;
};
@@ -38,12 +38,12 @@ static void merged_iter_init(struct merged_iter *mi,
mi->advance_index = -1;
mi->suppress_deletions = mt->suppress_deletions;
- REFTABLE_CALLOC_ARRAY(mi->subiters, mt->stack_len);
- for (size_t i = 0; i < mt->stack_len; i++) {
+ REFTABLE_CALLOC_ARRAY(mi->subiters, mt->readers_len);
+ for (size_t i = 0; i < mt->readers_len; i++) {
reftable_record_init(&mi->subiters[i].rec, typ);
- table_init_iter(&mt->stack[i], &mi->subiters[i].iter, typ);
+ reader_init_iter(mt->readers[i], &mi->subiters[i].iter, typ);
}
- mi->stack_len = mt->stack_len;
+ mi->subiters_len = mt->readers_len;
}
static void merged_iter_close(void *p)
@@ -51,7 +51,7 @@ static void merged_iter_close(void *p)
struct merged_iter *mi = p;
merged_iter_pqueue_release(&mi->pq);
- for (size_t i = 0; i < mi->stack_len; i++) {
+ for (size_t i = 0; i < mi->subiters_len; i++) {
reftable_iterator_destroy(&mi->subiters[i].iter);
reftable_record_release(&mi->subiters[i].rec);
}
@@ -80,7 +80,7 @@ static int merged_iter_seek(struct merged_iter *mi, struct reftable_record *want
mi->advance_index = -1;
- for (size_t i = 0; i < mi->stack_len; i++) {
+ for (size_t i = 0; i < mi->subiters_len; i++) {
err = iterator_seek(&mi->subiters[i].iter, want);
if (err < 0)
return err;
@@ -192,8 +192,8 @@ static void iterator_from_merged_iter(struct reftable_iterator *it,
it->ops = &merged_iter_vtable;
}
-int reftable_new_merged_table(struct reftable_merged_table **dest,
- struct reftable_table *stack, size_t n,
+int reftable_merged_table_new(struct reftable_merged_table **dest,
+ struct reftable_reader **readers, size_t n,
uint32_t hash_id)
{
struct reftable_merged_table *m = NULL;
@@ -201,10 +201,10 @@ int reftable_new_merged_table(struct reftable_merged_table **dest,
uint64_t first_min = 0;
for (size_t i = 0; i < n; i++) {
- uint64_t min = reftable_table_min_update_index(&stack[i]);
- uint64_t max = reftable_table_max_update_index(&stack[i]);
+ uint64_t min = reftable_reader_min_update_index(readers[i]);
+ uint64_t max = reftable_reader_max_update_index(readers[i]);
- if (reftable_table_hash_id(&stack[i]) != hash_id) {
+ if (reftable_reader_hash_id(readers[i]) != hash_id) {
return REFTABLE_FORMAT_ERROR;
}
if (i == 0 || min < first_min) {
@@ -216,8 +216,8 @@ int reftable_new_merged_table(struct reftable_merged_table **dest,
}
REFTABLE_CALLOC_ARRAY(m, 1);
- m->stack = stack;
- m->stack_len = n;
+ m->readers = readers;
+ m->readers_len = n;
m->min = first_min;
m->max = last_max;
m->hash_id = hash_id;
@@ -229,7 +229,6 @@ void reftable_merged_table_free(struct reftable_merged_table *mt)
{
if (!mt)
return;
- FREE_AND_NULL(mt->stack);
reftable_free(mt);
}
@@ -254,44 +253,19 @@ void merged_table_init_iter(struct reftable_merged_table *mt,
iterator_from_merged_iter(it, mi);
}
-uint32_t reftable_merged_table_hash_id(struct reftable_merged_table *mt)
-{
- return mt->hash_id;
-}
-
-static void reftable_merged_table_init_iter_void(void *tab,
- struct reftable_iterator *it,
- uint8_t typ)
-{
- merged_table_init_iter(tab, it, typ);
-}
-
-static uint32_t reftable_merged_table_hash_id_void(void *tab)
+void reftable_merged_table_init_ref_iterator(struct reftable_merged_table *mt,
+ struct reftable_iterator *it)
{
- return reftable_merged_table_hash_id(tab);
+ merged_table_init_iter(mt, it, BLOCK_TYPE_REF);
}
-static uint64_t reftable_merged_table_min_update_index_void(void *tab)
+void reftable_merged_table_init_log_iterator(struct reftable_merged_table *mt,
+ struct reftable_iterator *it)
{
- return reftable_merged_table_min_update_index(tab);
+ merged_table_init_iter(mt, it, BLOCK_TYPE_LOG);
}
-static uint64_t reftable_merged_table_max_update_index_void(void *tab)
-{
- return reftable_merged_table_max_update_index(tab);
-}
-
-static struct reftable_table_vtable merged_table_vtable = {
- .init_iter = reftable_merged_table_init_iter_void,
- .hash_id = reftable_merged_table_hash_id_void,
- .min_update_index = reftable_merged_table_min_update_index_void,
- .max_update_index = reftable_merged_table_max_update_index_void,
-};
-
-void reftable_table_from_merged_table(struct reftable_table *tab,
- struct reftable_merged_table *merged)
+uint32_t reftable_merged_table_hash_id(struct reftable_merged_table *mt)
{
- assert(!tab->ops);
- tab->ops = &merged_table_vtable;
- tab->table_arg = merged;
+ return mt->hash_id;
}
diff --git a/reftable/merged.h b/reftable/merged.h
index 2efe571da6..de5fd33f01 100644
--- a/reftable/merged.h
+++ b/reftable/merged.h
@@ -12,8 +12,8 @@ https://developers.google.com/open-source/licenses/bsd
#include "system.h"
struct reftable_merged_table {
- struct reftable_table *stack;
- size_t stack_len;
+ struct reftable_reader **readers;
+ size_t readers_len;
uint32_t hash_id;
/* If unset, produce deletions. This is useful for compaction. For the
diff --git a/reftable/reader.c b/reftable/reader.c
index 29c99e2269..f877099087 100644
--- a/reftable/reader.c
+++ b/reftable/reader.c
@@ -11,11 +11,9 @@ https://developers.google.com/open-source/licenses/bsd
#include "system.h"
#include "block.h"
#include "constants.h"
-#include "generic.h"
#include "iter.h"
#include "record.h"
#include "reftable-error.h"
-#include "reftable-generic.h"
uint64_t block_source_size(struct reftable_block_source *source)
{
@@ -164,58 +162,6 @@ done:
return err;
}
-int init_reader(struct reftable_reader *r, struct reftable_block_source *source,
- const char *name)
-{
- struct reftable_block footer = { NULL };
- struct reftable_block header = { NULL };
- int err = 0;
- uint64_t file_size = block_source_size(source);
-
- /* Need +1 to read type of first block. */
- uint32_t read_size = header_size(2) + 1; /* read v2 because it's larger. */
- memset(r, 0, sizeof(struct reftable_reader));
-
- if (read_size > file_size) {
- err = REFTABLE_FORMAT_ERROR;
- goto done;
- }
-
- err = block_source_read_block(source, &header, 0, read_size);
- if (err != read_size) {
- err = REFTABLE_IO_ERROR;
- goto done;
- }
-
- if (memcmp(header.data, "REFT", 4)) {
- err = REFTABLE_FORMAT_ERROR;
- goto done;
- }
- r->version = header.data[4];
- if (r->version != 1 && r->version != 2) {
- err = REFTABLE_FORMAT_ERROR;
- goto done;
- }
-
- r->size = file_size - footer_size(r->version);
- r->source = *source;
- r->name = xstrdup(name);
- r->hash_id = 0;
-
- err = block_source_read_block(source, &footer, r->size,
- footer_size(r->version));
- if (err != footer_size(r->version)) {
- err = REFTABLE_IO_ERROR;
- goto done;
- }
-
- err = parse_footer(r, footer.data, header.data);
-done:
- reftable_block_done(&footer);
- reftable_block_done(&header);
- return err;
-}
-
struct table_iter {
struct reftable_reader *r;
uint8_t typ;
@@ -229,6 +175,7 @@ static int table_iter_init(struct table_iter *ti, struct reftable_reader *r)
{
struct block_iter bi = BLOCK_ITER_INIT;
memset(ti, 0, sizeof(*ti));
+ reftable_reader_incref(r);
ti->r = r;
ti->bi = bi;
return 0;
@@ -316,6 +263,7 @@ static void table_iter_close(struct table_iter *ti)
{
table_iter_block_done(ti);
block_iter_close(&ti->bi);
+ reftable_reader_decref(ti->r);
}
static int table_iter_next_block(struct table_iter *ti)
@@ -605,9 +553,9 @@ static void iterator_from_table_iter(struct reftable_iterator *it,
it->ops = &table_iter_vtable;
}
-static void reader_init_iter(struct reftable_reader *r,
- struct reftable_iterator *it,
- uint8_t typ)
+void reader_init_iter(struct reftable_reader *r,
+ struct reftable_iterator *it,
+ uint8_t typ)
{
struct reftable_reader_offsets *offs = reader_offsets_for(r, typ);
@@ -633,31 +581,90 @@ void reftable_reader_init_log_iterator(struct reftable_reader *r,
reader_init_iter(r, it, BLOCK_TYPE_LOG);
}
-void reader_close(struct reftable_reader *r)
+int reftable_reader_new(struct reftable_reader **out,
+ struct reftable_block_source *source, char const *name)
{
- block_source_close(&r->source);
- FREE_AND_NULL(r->name);
-}
+ struct reftable_block footer = { 0 };
+ struct reftable_block header = { 0 };
+ struct reftable_reader *r;
+ uint64_t file_size = block_source_size(source);
+ uint32_t read_size;
+ int err;
-int reftable_new_reader(struct reftable_reader **p,
- struct reftable_block_source *src, char const *name)
-{
- struct reftable_reader *rd = reftable_calloc(1, sizeof(*rd));
- int err = init_reader(rd, src, name);
- if (err == 0) {
- *p = rd;
- } else {
- block_source_close(src);
- reftable_free(rd);
+ REFTABLE_CALLOC_ARRAY(r, 1);
+
+ /*
+ * We need one extra byte to read the type of first block. We also
+ * pretend to always be reading v2 of the format because it is larger.
+ */
+ read_size = header_size(2) + 1;
+ if (read_size > file_size) {
+ err = REFTABLE_FORMAT_ERROR;
+ goto done;
+ }
+
+ err = block_source_read_block(source, &header, 0, read_size);
+ if (err != read_size) {
+ err = REFTABLE_IO_ERROR;
+ goto done;
+ }
+
+ if (memcmp(header.data, "REFT", 4)) {
+ err = REFTABLE_FORMAT_ERROR;
+ goto done;
+ }
+ r->version = header.data[4];
+ if (r->version != 1 && r->version != 2) {
+ err = REFTABLE_FORMAT_ERROR;
+ goto done;
+ }
+
+ r->size = file_size - footer_size(r->version);
+ r->source = *source;
+ r->name = xstrdup(name);
+ r->hash_id = 0;
+ r->refcount = 1;
+
+ err = block_source_read_block(source, &footer, r->size,
+ footer_size(r->version));
+ if (err != footer_size(r->version)) {
+ err = REFTABLE_IO_ERROR;
+ goto done;
+ }
+
+ err = parse_footer(r, footer.data, header.data);
+ if (err)
+ goto done;
+
+ *out = r;
+
+done:
+ reftable_block_done(&footer);
+ reftable_block_done(&header);
+ if (err) {
+ reftable_free(r);
+ block_source_close(source);
}
return err;
}
-void reftable_reader_free(struct reftable_reader *r)
+void reftable_reader_incref(struct reftable_reader *r)
+{
+ if (!r->refcount)
+ BUG("cannot increment ref counter of dead reader");
+ r->refcount++;
+}
+
+void reftable_reader_decref(struct reftable_reader *r)
{
if (!r)
return;
- reader_close(r);
+ if (!r->refcount)
+ BUG("cannot decrement ref counter of dead reader");
+ if (--r->refcount)
+ return;
+ block_source_close(&r->source);
+ FREE_AND_NULL(r->name);
reftable_free(r);
}
@@ -735,8 +742,6 @@ static int reftable_reader_refs_for_unindexed(struct reftable_reader *r,
*filter = empty;
strbuf_add(&filter->oid, oid, oid_len);
- reftable_table_from_reader(&filter->tab, r);
- filter->double_check = 0;
iterator_from_table_iter(&filter->it, ti);
iterator_from_filtering_ref_iterator(it, filter);
@@ -761,66 +766,6 @@ uint64_t reftable_reader_min_update_index(struct reftable_reader *r)
return r->min_update_index;
}
-/* generic table interface. */
-
-static void reftable_reader_init_iter_void(void *tab,
- struct reftable_iterator *it,
- uint8_t typ)
-{
- reader_init_iter(tab, it, typ);
-}
-
-static uint32_t reftable_reader_hash_id_void(void *tab)
-{
- return reftable_reader_hash_id(tab);
-}
-
-static uint64_t reftable_reader_min_update_index_void(void *tab)
-{
- return reftable_reader_min_update_index(tab);
-}
-
-static uint64_t reftable_reader_max_update_index_void(void *tab)
-{
- return reftable_reader_max_update_index(tab);
-}
-
-static struct reftable_table_vtable reader_vtable = {
- .init_iter = reftable_reader_init_iter_void,
- .hash_id = reftable_reader_hash_id_void,
- .min_update_index = reftable_reader_min_update_index_void,
- .max_update_index = reftable_reader_max_update_index_void,
-};
-
-void reftable_table_from_reader(struct reftable_table *tab,
- struct reftable_reader *reader)
-{
- assert(!tab->ops);
- tab->ops = &reader_vtable;
- tab->table_arg = reader;
-}
-
-
-int reftable_reader_print_file(const char *tablename)
-{
- struct reftable_block_source src = { NULL };
- int err = reftable_block_source_from_file(&src, tablename);
- struct reftable_reader *r = NULL;
- struct reftable_table tab = { NULL };
- if (err < 0)
- goto done;
-
- err = reftable_new_reader(&r, &src, tablename);
- if (err < 0)
- goto done;
-
- reftable_table_from_reader(&tab, r);
- err = reftable_table_print(&tab);
-done:
- reftable_reader_free(r);
- return err;
-}
-
int reftable_reader_print_blocks(const char *tablename)
{
struct {
@@ -850,7 +795,7 @@ int reftable_reader_print_blocks(const char *tablename)
if (err < 0)
goto done;
- err = reftable_new_reader(&r, &src, tablename);
+ err = reftable_reader_new(&r, &src, tablename);
if (err < 0)
goto done;
@@ -881,7 +826,7 @@ int reftable_reader_print_blocks(const char *tablename)
}
done:
- reftable_reader_free(r);
+ reftable_reader_decref(r);
table_iter_close(&ti);
return err;
}
diff --git a/reftable/reader.h b/reftable/reader.h
index e869165f23..3710ee09b4 100644
--- a/reftable/reader.h
+++ b/reftable/reader.h
@@ -50,13 +50,16 @@ struct reftable_reader {
struct reftable_reader_offsets ref_offsets;
struct reftable_reader_offsets obj_offsets;
struct reftable_reader_offsets log_offsets;
+
+ uint64_t refcount;
};
-int init_reader(struct reftable_reader *r, struct reftable_block_source *source,
- const char *name);
-void reader_close(struct reftable_reader *r);
const char *reader_name(struct reftable_reader *r);
+void reader_init_iter(struct reftable_reader *r,
+ struct reftable_iterator *it,
+ uint8_t typ);
+
/* initialize a block reader to read from `r` */
int reader_init_block_reader(struct reftable_reader *r, struct block_reader *br,
uint64_t next_off, uint8_t want_typ);
diff --git a/reftable/record.c b/reftable/record.c
index 2ec0c6d346..6b5a075b92 100644
--- a/reftable/record.c
+++ b/reftable/record.c
@@ -259,58 +259,6 @@ static void reftable_ref_record_copy_from(void *rec, const void *src_rec,
}
}
-static char hexdigit(int c)
-{
- if (c <= 9)
- return '0' + c;
- return 'a' + (c - 10);
-}
-
-static void hex_format(char *dest, const unsigned char *src, int hash_size)
-{
- assert(hash_size > 0);
- if (src) {
- int i = 0;
- for (i = 0; i < hash_size; i++) {
- dest[2 * i] = hexdigit(src[i] >> 4);
- dest[2 * i + 1] = hexdigit(src[i] & 0xf);
- }
- dest[2 * hash_size] = 0;
- }
-}
-
-static void reftable_ref_record_print_sz(const struct reftable_ref_record *ref,
- int hash_size)
-{
- char hex[GIT_MAX_HEXSZ + 1] = { 0 }; /* BUG */
- printf("ref{%s(%" PRIu64 ") ", ref->refname, ref->update_index);
- switch (ref->value_type) {
- case REFTABLE_REF_SYMREF:
- printf("=> %s", ref->value.symref);
- break;
- case REFTABLE_REF_VAL2:
- hex_format(hex, ref->value.val2.value, hash_size);
- printf("val 2 %s", hex);
- hex_format(hex, ref->value.val2.target_value,
- hash_size);
- printf("(T %s)", hex);
- break;
- case REFTABLE_REF_VAL1:
- hex_format(hex, ref->value.val1, hash_size);
- printf("val 1 %s", hex);
- break;
- case REFTABLE_REF_DELETION:
- printf("delete");
- break;
- }
- printf("}\n");
-}
-
-void reftable_ref_record_print(const struct reftable_ref_record *ref,
- uint32_t hash_id) {
- reftable_ref_record_print_sz(ref, hash_size(hash_id));
-}
-
static void reftable_ref_record_release_void(void *rec)
{
reftable_ref_record_release(rec);
@@ -480,12 +428,6 @@ static int reftable_ref_record_cmp_void(const void *_a, const void *_b)
return strcmp(a->refname, b->refname);
}
-static void reftable_ref_record_print_void(const void *rec,
- int hash_size)
-{
- reftable_ref_record_print_sz((struct reftable_ref_record *) rec, hash_size);
-}
-
static struct reftable_record_vtable reftable_ref_record_vtable = {
.key = &reftable_ref_record_key,
.type = BLOCK_TYPE_REF,
@@ -497,7 +439,6 @@ static struct reftable_record_vtable reftable_ref_record_vtable = {
.is_deletion = &reftable_ref_record_is_deletion_void,
.equal = &reftable_ref_record_equal_void,
.cmp = &reftable_ref_record_cmp_void,
- .print = &reftable_ref_record_print_void,
};
static void reftable_obj_record_key(const void *r, struct strbuf *dest)
@@ -516,21 +457,6 @@ static void reftable_obj_record_release(void *rec)
memset(obj, 0, sizeof(struct reftable_obj_record));
}
-static void reftable_obj_record_print(const void *rec, int hash_size UNUSED)
-{
- const struct reftable_obj_record *obj = rec;
- char hex[GIT_MAX_HEXSZ + 1] = { 0 };
- struct strbuf offset_str = STRBUF_INIT;
- int i;
-
- for (i = 0; i < obj->offset_len; i++)
- strbuf_addf(&offset_str, "%" PRIu64 " ", obj->offsets[i]);
- hex_format(hex, obj->hash_prefix, obj->hash_prefix_len);
- printf("prefix %s (len %d), offsets [%s]\n",
- hex, obj->hash_prefix_len, offset_str.buf);
- strbuf_release(&offset_str);
-}
-
static void reftable_obj_record_copy_from(void *rec, const void *src_rec,
int hash_size UNUSED)
{
@@ -703,41 +629,8 @@ static struct reftable_record_vtable reftable_obj_record_vtable = {
.is_deletion = &not_a_deletion,
.equal = &reftable_obj_record_equal_void,
.cmp = &reftable_obj_record_cmp_void,
- .print = &reftable_obj_record_print,
};
-static void reftable_log_record_print_sz(struct reftable_log_record *log,
- int hash_size)
-{
- char hex[GIT_MAX_HEXSZ + 1] = { 0 };
-
- switch (log->value_type) {
- case REFTABLE_LOG_DELETION:
- printf("log{%s(%" PRIu64 ") delete\n", log->refname,
- log->update_index);
- break;
- case REFTABLE_LOG_UPDATE:
- printf("log{%s(%" PRIu64 ") %s <%s> %" PRIu64 " %04d\n",
- log->refname, log->update_index,
- log->value.update.name ? log->value.update.name : "",
- log->value.update.email ? log->value.update.email : "",
- log->value.update.time,
- log->value.update.tz_offset);
- hex_format(hex, log->value.update.old_hash, hash_size);
- printf("%s => ", hex);
- hex_format(hex, log->value.update.new_hash, hash_size);
- printf("%s\n\n%s\n}\n", hex,
- log->value.update.message ? log->value.update.message : "");
- break;
- }
-}
-
-void reftable_log_record_print(struct reftable_log_record *log,
- uint32_t hash_id)
-{
- reftable_log_record_print_sz(log, hash_size(hash_id));
-}
-
static void reftable_log_record_key(const void *r, struct strbuf *dest)
{
const struct reftable_log_record *rec =
@@ -1041,11 +934,6 @@ static int reftable_log_record_is_deletion_void(const void *p)
(const struct reftable_log_record *)p);
}
-static void reftable_log_record_print_void(const void *rec, int hash_size)
-{
- reftable_log_record_print_sz((struct reftable_log_record*)rec, hash_size);
-}
-
static struct reftable_record_vtable reftable_log_record_vtable = {
.key = &reftable_log_record_key,
.type = BLOCK_TYPE_LOG,
@@ -1057,7 +945,6 @@ static struct reftable_record_vtable reftable_log_record_vtable = {
.is_deletion = &reftable_log_record_is_deletion_void,
.equal = &reftable_log_record_equal_void,
.cmp = &reftable_log_record_cmp_void,
- .print = &reftable_log_record_print_void,
};
static void reftable_index_record_key(const void *r, struct strbuf *dest)
@@ -1142,13 +1029,6 @@ static int reftable_index_record_cmp(const void *_a, const void *_b)
return strbuf_cmp(&a->last_key, &b->last_key);
}
-static void reftable_index_record_print(const void *rec, int hash_size UNUSED)
-{
- const struct reftable_index_record *idx = rec;
- /* TODO: escape null chars? */
- printf("\"%s\" %" PRIu64 "\n", idx->last_key.buf, idx->offset);
-}
-
static struct reftable_record_vtable reftable_index_record_vtable = {
.key = &reftable_index_record_key,
.type = BLOCK_TYPE_INDEX,
@@ -1160,7 +1040,6 @@ static struct reftable_record_vtable reftable_index_record_vtable = {
.is_deletion = &not_a_deletion,
.equal = &reftable_index_record_equal,
.cmp = &reftable_index_record_cmp,
- .print = &reftable_index_record_print,
};
void reftable_record_key(struct reftable_record *rec, struct strbuf *dest)
@@ -1339,9 +1218,3 @@ void reftable_record_init(struct reftable_record *rec, uint8_t typ)
BUG("unhandled record type");
}
}
-
-void reftable_record_print(struct reftable_record *rec, int hash_size)
-{
- printf("'%c': ", rec->type);
- reftable_record_vtable(rec)->print(reftable_record_data(rec), hash_size);
-}
diff --git a/reftable/record.h b/reftable/record.h
index d778133e6e..5003bacdb0 100644
--- a/reftable/record.h
+++ b/reftable/record.h
@@ -136,7 +136,6 @@ void reftable_record_init(struct reftable_record *rec, uint8_t typ);
/* see struct record_vtable */
int reftable_record_cmp(struct reftable_record *a, struct reftable_record *b);
int reftable_record_equal(struct reftable_record *a, struct reftable_record *b, int hash_size);
-void reftable_record_print(struct reftable_record *rec, int hash_size);
void reftable_record_key(struct reftable_record *rec, struct strbuf *dest);
void reftable_record_copy_from(struct reftable_record *rec,
struct reftable_record *src, int hash_size);
diff --git a/reftable/reftable-generic.h b/reftable/reftable-generic.h
deleted file mode 100644
index 65670ea093..0000000000
--- a/reftable/reftable-generic.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
-Copyright 2020 Google LLC
-
-Use of this source code is governed by a BSD-style
-license that can be found in the LICENSE file or at
-https://developers.google.com/open-source/licenses/bsd
-*/
-
-#ifndef REFTABLE_GENERIC_H
-#define REFTABLE_GENERIC_H
-
-#include "reftable-iterator.h"
-
-struct reftable_table_vtable;
-
-/*
- * Provides a unified API for reading tables, either merged tables, or single
- * readers. */
-struct reftable_table {
- struct reftable_table_vtable *ops;
- void *table_arg;
-};
-
-void reftable_table_init_ref_iter(struct reftable_table *tab,
- struct reftable_iterator *it);
-
-void reftable_table_init_log_iter(struct reftable_table *tab,
- struct reftable_iterator *it);
-
-/* returns the hash ID from a generic reftable_table */
-uint32_t reftable_table_hash_id(struct reftable_table *tab);
-
-/* returns the max update_index covered by this table. */
-uint64_t reftable_table_max_update_index(struct reftable_table *tab);
-
-/* returns the min update_index covered by this table. */
-uint64_t reftable_table_min_update_index(struct reftable_table *tab);
-
-/* convenience function to read a single ref. Returns < 0 for error, 0
- for success, and 1 if ref not found. */
-int reftable_table_read_ref(struct reftable_table *tab, const char *name,
- struct reftable_ref_record *ref);
-
-/* dump table contents onto stdout for debugging */
-int reftable_table_print(struct reftable_table *tab);
-
-#endif
diff --git a/reftable/reftable-merged.h b/reftable/reftable-merged.h
index 14d5fc9f05..16d19f8df2 100644
--- a/reftable/reftable-merged.h
+++ b/reftable/reftable-merged.h
@@ -26,16 +26,24 @@ https://developers.google.com/open-source/licenses/bsd
/* A merged table is implements seeking/iterating over a stack of tables. */
struct reftable_merged_table;
-/* A generic reftable; see below. */
-struct reftable_table;
+struct reftable_reader;
-/* reftable_new_merged_table creates a new merged table. It takes ownership of
- the stack array.
-*/
-int reftable_new_merged_table(struct reftable_merged_table **dest,
- struct reftable_table *stack, size_t n,
+/*
+ * reftable_merged_table_new creates a new merged table. The readers must be
+ * kept alive as long as the merged table is still in use.
+ */
+int reftable_merged_table_new(struct reftable_merged_table **dest,
+ struct reftable_reader **readers, size_t n,
uint32_t hash_id);
+/* Initialize a merged table iterator for reading refs. */
+void reftable_merged_table_init_ref_iterator(struct reftable_merged_table *mt,
+ struct reftable_iterator *it);
+
+/* Initialize a merged table iterator for reading logs. */
+void reftable_merged_table_init_log_iterator(struct reftable_merged_table *mt,
+ struct reftable_iterator *it);
+
/* returns the max update_index covered by this merged table. */
uint64_t
reftable_merged_table_max_update_index(struct reftable_merged_table *mt);
@@ -50,8 +58,4 @@ void reftable_merged_table_free(struct reftable_merged_table *m);
/* return the hash ID of the merged table. */
uint32_t reftable_merged_table_hash_id(struct reftable_merged_table *m);
-/* create a generic table from reftable_merged_table */
-void reftable_table_from_merged_table(struct reftable_table *tab,
- struct reftable_merged_table *table);
-
#endif
diff --git a/reftable/reftable-reader.h b/reftable/reftable-reader.h
index a32f31d648..a600452b56 100644
--- a/reftable/reftable-reader.h
+++ b/reftable/reftable-reader.h
@@ -23,19 +23,28 @@
/* The reader struct is a handle to an open reftable file. */
struct reftable_reader;
-/* Generic table. */
-struct reftable_table;
-
-/* reftable_new_reader opens a reftable for reading. If successful,
+/* reftable_reader_new opens a reftable for reading. If successful,
* returns 0 code and sets pp. The name is used for creating a
* stack. Typically, it is the basename of the file. The block source
* `src` is owned by the reader, and is closed on calling
* reftable_reader_destroy(). On error, the block source `src` is
* closed as well.
*/
-int reftable_new_reader(struct reftable_reader **pp,
+int reftable_reader_new(struct reftable_reader **pp,
struct reftable_block_source *src, const char *name);
+/*
+ * Manage the reference count of the reftable reader. A newly initialized
+ * reader starts with a refcount of 1 and will be deleted once the refcount has
+ * reached 0.
+ *
+ * This is required because readers may have longer lifetimes than the stack
+ * they belong to. The stack may for example be reloaded while the old tables
+ * are still being accessed by an iterator.
+ */
+void reftable_reader_incref(struct reftable_reader *reader);
+void reftable_reader_decref(struct reftable_reader *reader);
+
/* Initialize a reftable iterator for reading refs. */
void reftable_reader_init_ref_iterator(struct reftable_reader *r,
struct reftable_iterator *it);
@@ -47,9 +56,6 @@ void reftable_reader_init_log_iterator(struct reftable_reader *r,
/* returns the hash ID used in this table. */
uint32_t reftable_reader_hash_id(struct reftable_reader *r);
-/* closes and deallocates a reader. */
-void reftable_reader_free(struct reftable_reader *);
-
/* return an iterator for the refs pointing to `oid`. */
int reftable_reader_refs_for(struct reftable_reader *r,
struct reftable_iterator *it, uint8_t *oid);
@@ -60,12 +66,6 @@ uint64_t reftable_reader_max_update_index(struct reftable_reader *r);
/* return the min_update_index for a table */
uint64_t reftable_reader_min_update_index(struct reftable_reader *r);
-/* creates a generic table from a file reader. */
-void reftable_table_from_reader(struct reftable_table *tab,
- struct reftable_reader *reader);
-
-/* print table onto stdout for debugging. */
-int reftable_reader_print_file(const char *tablename);
/* print blocks onto stdout for debugging. */
int reftable_reader_print_blocks(const char *tablename);
diff --git a/reftable/reftable-record.h b/reftable/reftable-record.h
index ff486eb1f7..2d42463c58 100644
--- a/reftable/reftable-record.h
+++ b/reftable/reftable-record.h
@@ -60,10 +60,6 @@ const unsigned char *reftable_ref_record_val2(const struct reftable_ref_record *
/* returns whether 'ref' represents a deletion */
int reftable_ref_record_is_deletion(const struct reftable_ref_record *ref);
-/* prints a reftable_ref_record onto stdout. Useful for debugging. */
-void reftable_ref_record_print(const struct reftable_ref_record *ref,
- uint32_t hash_id);
-
/* frees and nulls all pointer values inside `ref`. */
void reftable_ref_record_release(struct reftable_ref_record *ref);
@@ -111,8 +107,4 @@ void reftable_log_record_release(struct reftable_log_record *log);
int reftable_log_record_equal(const struct reftable_log_record *a,
const struct reftable_log_record *b, int hash_size);
-/* dumps a reftable_log_record on stdout, for debugging/testing. */
-void reftable_log_record_print(struct reftable_log_record *log,
- uint32_t hash_id);
-
#endif
diff --git a/reftable/reftable-stack.h b/reftable/reftable-stack.h
index 09e97c9991..f4f8cabc7f 100644
--- a/reftable/reftable-stack.h
+++ b/reftable/reftable-stack.h
@@ -140,7 +140,4 @@ struct reftable_compaction_stats {
struct reftable_compaction_stats *
reftable_stack_compaction_stats(struct reftable_stack *st);
-/* print the entire stack represented by the directory */
-int reftable_stack_print_directory(const char *stackdir, uint32_t hash_id);
-
#endif
diff --git a/reftable/reftable-tests.h b/reftable/reftable-tests.h
index afe0103ad4..5d725c69c7 100644
--- a/reftable/reftable-tests.h
+++ b/reftable/reftable-tests.h
@@ -9,8 +9,6 @@ https://developers.google.com/open-source/licenses/bsd
#ifndef REFTABLE_TESTS_H
#define REFTABLE_TESTS_H
-int block_test_main(int argc, const char **argv);
int stack_test_main(int argc, const char **argv);
-int reftable_dump_main(int argc, char *const *argv);
#endif
diff --git a/reftable/stack.c b/reftable/stack.c
index 2071e428a8..ce0a35216b 100644
--- a/reftable/stack.c
+++ b/reftable/stack.c
@@ -14,7 +14,6 @@ https://developers.google.com/open-source/licenses/bsd
#include "merged.h"
#include "reader.h"
#include "reftable-error.h"
-#include "reftable-generic.h"
#include "reftable-record.h"
#include "reftable-merged.h"
#include "writer.h"
@@ -187,7 +186,7 @@ void reftable_stack_destroy(struct reftable_stack *st)
if (names && !has_name(names, name)) {
stack_filename(&filename, st, name);
}
- reftable_reader_free(st->readers[i]);
+ reftable_reader_decref(st->readers[i]);
if (filename.len) {
/* On Windows, can only unlink after closing. */
@@ -225,13 +224,13 @@ static int reftable_stack_reload_once(struct reftable_stack *st,
const char **names,
int reuse_open)
{
- size_t cur_len = !st->merged ? 0 : st->merged->stack_len;
+ size_t cur_len = !st->merged ? 0 : st->merged->readers_len;
struct reftable_reader **cur = stack_copy_readers(st, cur_len);
+ struct reftable_reader **reused = NULL;
+ size_t reused_len = 0, reused_alloc = 0;
size_t names_len = names_length(names);
struct reftable_reader **new_readers =
reftable_calloc(names_len, sizeof(*new_readers));
- struct reftable_table *new_tables =
- reftable_calloc(names_len, sizeof(*new_tables));
size_t new_readers_len = 0;
struct reftable_merged_table *new_merged = NULL;
struct strbuf table_path = STRBUF_INIT;
@@ -248,6 +247,18 @@ static int reftable_stack_reload_once(struct reftable_stack *st,
if (cur[i] && 0 == strcmp(cur[i]->name, name)) {
rd = cur[i];
cur[i] = NULL;
+
+ /*
+ * When reloading the stack fails, we end up
+ * releasing all new readers. This also
+ * includes the reused readers, even though
+ * they are still in used by the old stack. We
+ * thus need to keep them alive here, which we
+ * do by bumping their refcount.
+ */
+ REFTABLE_ALLOC_GROW(reused, reused_len + 1, reused_alloc);
+ reused[reused_len++] = rd;
+ reftable_reader_incref(rd);
break;
}
}
@@ -261,55 +272,62 @@ static int reftable_stack_reload_once(struct reftable_stack *st,
if (err < 0)
goto done;
- err = reftable_new_reader(&rd, &src, name);
+ err = reftable_reader_new(&rd, &src, name);
if (err < 0)
goto done;
}
new_readers[new_readers_len] = rd;
- reftable_table_from_reader(&new_tables[new_readers_len], rd);
new_readers_len++;
}
/* success! */
- err = reftable_new_merged_table(&new_merged, new_tables,
+ err = reftable_merged_table_new(&new_merged, new_readers,
new_readers_len, st->opts.hash_id);
if (err < 0)
goto done;
- new_tables = NULL;
- st->readers_len = new_readers_len;
- if (st->merged)
- reftable_merged_table_free(st->merged);
- if (st->readers) {
- reftable_free(st->readers);
- }
- st->readers = new_readers;
- new_readers = NULL;
- new_readers_len = 0;
-
- new_merged->suppress_deletions = 1;
- st->merged = new_merged;
+ /*
+ * Close the old, non-reused readers and proactively try to unlink
+ * them. This is done for systems like Windows, where the underlying
+ * file of such an open reader wouldn't have been possible to be
+ * unlinked by the compacting process.
+ */
for (i = 0; i < cur_len; i++) {
if (cur[i]) {
const char *name = reader_name(cur[i]);
stack_filename(&table_path, st, name);
-
- reader_close(cur[i]);
- reftable_reader_free(cur[i]);
-
- /* On Windows, can only unlink after closing. */
+ reftable_reader_decref(cur[i]);
unlink(table_path.buf);
}
}
+ /* Update the stack to point to the new tables. */
+ if (st->merged)
+ reftable_merged_table_free(st->merged);
+ new_merged->suppress_deletions = 1;
+ st->merged = new_merged;
+
+ if (st->readers)
+ reftable_free(st->readers);
+ st->readers = new_readers;
+ st->readers_len = new_readers_len;
+ new_readers = NULL;
+ new_readers_len = 0;
+
+ /*
+ * Decrement the refcount of reused readers again. This only needs to
+ * happen on the successful case, because on the unsuccessful one we
+ * decrement their refcount via `new_readers`.
+ */
+ for (i = 0; i < reused_len; i++)
+ reftable_reader_decref(reused[i]);
+
done:
- for (i = 0; i < new_readers_len; i++) {
- reader_close(new_readers[i]);
- reftable_reader_free(new_readers[i]);
- }
+ for (i = 0; i < new_readers_len; i++)
+ reftable_reader_decref(new_readers[i]);
reftable_free(new_readers);
- reftable_free(new_tables);
+ reftable_free(reused);
reftable_free(cur);
strbuf_release(&table_path);
return err;
@@ -520,7 +538,7 @@ static int stack_uptodate(struct reftable_stack *st)
}
}
- if (names[st->merged->stack_len]) {
+ if (names[st->merged->readers_len]) {
err = 1;
goto done;
}
@@ -659,7 +677,7 @@ int reftable_addition_commit(struct reftable_addition *add)
if (add->new_tables_len == 0)
goto done;
- for (i = 0; i < add->stack->merged->stack_len; i++) {
+ for (i = 0; i < add->stack->merged->readers_len; i++) {
strbuf_addstr(&table_list, add->stack->readers[i]->name);
strbuf_addstr(&table_list, "\n");
}
@@ -839,7 +857,7 @@ done:
uint64_t reftable_stack_next_update_index(struct reftable_stack *st)
{
- int sz = st->merged->stack_len;
+ int sz = st->merged->readers_len;
if (sz > 0)
return reftable_reader_max_update_index(st->readers[sz - 1]) +
1;
@@ -906,30 +924,23 @@ static int stack_write_compact(struct reftable_stack *st,
size_t first, size_t last,
struct reftable_log_expiry_config *config)
{
- size_t subtabs_len = last - first + 1;
- struct reftable_table *subtabs = reftable_calloc(
- last - first + 1, sizeof(*subtabs));
struct reftable_merged_table *mt = NULL;
struct reftable_iterator it = { NULL };
struct reftable_ref_record ref = { NULL };
struct reftable_log_record log = { NULL };
+ size_t subtabs_len = last - first + 1;
uint64_t entries = 0;
int err = 0;
- for (size_t i = first, j = 0; i <= last; i++) {
- struct reftable_reader *t = st->readers[i];
- reftable_table_from_reader(&subtabs[j++], t);
- st->stats.bytes += t->size;
- }
+ for (size_t i = first; i <= last; i++)
+ st->stats.bytes += st->readers[i]->size;
reftable_writer_set_limits(wr, st->readers[first]->min_update_index,
st->readers[last]->max_update_index);
- err = reftable_new_merged_table(&mt, subtabs, subtabs_len,
+ err = reftable_merged_table_new(&mt, st->readers + first, subtabs_len,
st->opts.hash_id);
- if (err < 0) {
- reftable_free(subtabs);
+ if (err < 0)
goto done;
- }
merged_table_init_iter(mt, &it, BLOCK_TYPE_REF);
err = reftable_iterator_seek_ref(&it, "");
@@ -1207,7 +1218,7 @@ static int stack_compact_range(struct reftable_stack *st,
* have compacted them.
*/
for (size_t j = 1; j < last - first + 1; j++) {
- const char *old = first + j < st->merged->stack_len ?
+ const char *old = first + j < st->merged->readers_len ?
st->readers[first + j]->name : NULL;
const char *new = names[i + j];
@@ -1248,10 +1259,10 @@ static int stack_compact_range(struct reftable_stack *st,
* `fd_read_lines()` uses a `NULL` sentinel to indicate that
* the array is at its end. As we use `free_names()` to free
* the array, we need to include this sentinel value here and
- * thus have to allocate `stack_len + 1` many entries.
+ * thus have to allocate `readers_len + 1` many entries.
*/
- REFTABLE_CALLOC_ARRAY(names, st->merged->stack_len + 1);
- for (size_t i = 0; i < st->merged->stack_len; i++)
+ REFTABLE_CALLOC_ARRAY(names, st->merged->readers_len + 1);
+ for (size_t i = 0; i < st->merged->readers_len; i++)
names[i] = xstrdup(st->readers[i]->name);
first_to_replace = first;
last_to_replace = last;
@@ -1341,25 +1352,17 @@ done:
strbuf_release(&table_name);
free_names(names);
- return err;
-}
-
-static int stack_compact_range_stats(struct reftable_stack *st,
- size_t first, size_t last,
- struct reftable_log_expiry_config *config,
- unsigned int flags)
-{
- int err = stack_compact_range(st, first, last, config, flags);
if (err == REFTABLE_LOCK_ERROR)
st->stats.failures++;
+
return err;
}
int reftable_stack_compact_all(struct reftable_stack *st,
struct reftable_log_expiry_config *config)
{
- size_t last = st->merged->stack_len ? st->merged->stack_len - 1 : 0;
- return stack_compact_range_stats(st, 0, last, config, 0);
+ size_t last = st->merged->readers_len ? st->merged->readers_len - 1 : 0;
+ return stack_compact_range(st, 0, last, config, 0);
}
static int segment_size(struct segment *s)
@@ -1449,9 +1452,9 @@ static uint64_t *stack_table_sizes_for_compaction(struct reftable_stack *st)
int overhead = header_size(version) - 1;
uint64_t *sizes;
- REFTABLE_CALLOC_ARRAY(sizes, st->merged->stack_len);
+ REFTABLE_CALLOC_ARRAY(sizes, st->merged->readers_len);
- for (size_t i = 0; i < st->merged->stack_len; i++)
+ for (size_t i = 0; i < st->merged->readers_len; i++)
sizes[i] = st->readers[i]->size - overhead;
return sizes;
@@ -1461,12 +1464,12 @@ int reftable_stack_auto_compact(struct reftable_stack *st)
{
uint64_t *sizes = stack_table_sizes_for_compaction(st);
struct segment seg =
- suggest_compaction_segment(sizes, st->merged->stack_len,
+ suggest_compaction_segment(sizes, st->merged->readers_len,
st->opts.auto_compaction_factor);
reftable_free(sizes);
if (segment_size(&seg) > 0)
- return stack_compact_range_stats(st, seg.start, seg.end - 1,
- NULL, STACK_COMPACT_RANGE_BEST_EFFORT);
+ return stack_compact_range(st, seg.start, seg.end - 1,
+ NULL, STACK_COMPACT_RANGE_BEST_EFFORT);
return 0;
}
@@ -1480,9 +1483,28 @@ reftable_stack_compaction_stats(struct reftable_stack *st)
int reftable_stack_read_ref(struct reftable_stack *st, const char *refname,
struct reftable_ref_record *ref)
{
- struct reftable_table tab = { NULL };
- reftable_table_from_merged_table(&tab, reftable_stack_merged_table(st));
- return reftable_table_read_ref(&tab, refname, ref);
+ struct reftable_iterator it = { 0 };
+ int ret;
+
+ reftable_merged_table_init_ref_iterator(st->merged, &it);
+ ret = reftable_iterator_seek_ref(&it, refname);
+ if (ret)
+ goto out;
+
+ ret = reftable_iterator_next_ref(&it, ref);
+ if (ret)
+ goto out;
+
+ if (strcmp(ref->refname, refname) ||
+ reftable_ref_record_is_deletion(ref)) {
+ reftable_ref_record_release(ref);
+ ret = 1;
+ goto out;
+ }
+
+out:
+ reftable_iterator_destroy(&it);
+ return ret;
}
int reftable_stack_read_log(struct reftable_stack *st, const char *refname,
@@ -1534,12 +1556,12 @@ static void remove_maybe_stale_table(struct reftable_stack *st, uint64_t max,
if (err < 0)
goto done;
- err = reftable_new_reader(&rd, &src, name);
+ err = reftable_reader_new(&rd, &src, name);
if (err < 0)
goto done;
update_idx = reftable_reader_max_update_index(rd);
- reftable_reader_free(rd);
+ reftable_reader_decref(rd);
if (update_idx <= max) {
unlink(table_path.buf);
@@ -1596,23 +1618,3 @@ done:
reftable_addition_destroy(add);
return err;
}
-
-int reftable_stack_print_directory(const char *stackdir, uint32_t hash_id)
-{
- struct reftable_stack *stack = NULL;
- struct reftable_write_options opts = { .hash_id = hash_id };
- struct reftable_merged_table *merged = NULL;
- struct reftable_table table = { NULL };
-
- int err = reftable_new_stack(&stack, stackdir, &opts);
- if (err < 0)
- goto done;
-
- merged = reftable_stack_merged_table(stack);
- reftable_table_from_merged_table(&table, merged);
- err = reftable_table_print(&table);
-done:
- if (stack)
- reftable_stack_destroy(stack);
- return err;
-}
diff --git a/reftable/stack_test.c b/reftable/stack_test.c
index 1a638cd2e0..89cb2be19f 100644
--- a/reftable/stack_test.c
+++ b/reftable/stack_test.c
@@ -10,6 +10,7 @@ https://developers.google.com/open-source/licenses/bsd
#include "system.h"
+#include "copy.h"
#include "reftable-reader.h"
#include "merged.h"
#include "basics.h"
@@ -125,6 +126,7 @@ static void write_n_ref_tables(struct reftable_stack *st,
.value_type = REFTABLE_REF_VAL1,
};
+ strbuf_reset(&buf);
strbuf_addf(&buf, "refs/heads/branch-%04u", (unsigned) i);
ref.refname = buf.buf;
set_test_hash(ref.value.val1, i);
@@ -179,13 +181,6 @@ static void test_reftable_stack_add_one(void)
EXPECT(0 == strcmp("master", dest.value.symref));
EXPECT(st->readers_len > 0);
- printf("testing print functionality:\n");
- err = reftable_stack_print_directory(dir, GIT_SHA1_FORMAT_ID);
- EXPECT_ERR(err);
-
- err = reftable_stack_print_directory(dir, GIT_SHA256_FORMAT_ID);
- EXPECT(err == REFTABLE_FORMAT_ERROR);
-
#ifndef GIT_WINDOWS_NATIVE
strbuf_addstr(&scratch, dir);
strbuf_addstr(&scratch, "/tables.list");
@@ -347,9 +342,9 @@ static void test_reftable_stack_transaction_api_performs_auto_compaction(void)
* all tables in the stack.
*/
if (i != n)
- EXPECT(st->merged->stack_len == i + 1);
+ EXPECT(st->merged->readers_len == i + 1);
else
- EXPECT(st->merged->stack_len == 1);
+ EXPECT(st->merged->readers_len == 1);
}
reftable_stack_destroy(st);
@@ -375,7 +370,7 @@ static void test_reftable_stack_auto_compaction_fails_gracefully(void)
err = reftable_stack_add(st, write_test_ref, &ref);
EXPECT_ERR(err);
- EXPECT(st->merged->stack_len == 1);
+ EXPECT(st->merged->readers_len == 1);
EXPECT(st->stats.attempts == 0);
EXPECT(st->stats.failures == 0);
@@ -390,7 +385,7 @@ static void test_reftable_stack_auto_compaction_fails_gracefully(void)
ref.update_index = 2;
err = reftable_stack_add(st, write_test_ref, &ref);
EXPECT_ERR(err);
- EXPECT(st->merged->stack_len == 2);
+ EXPECT(st->merged->readers_len == 2);
EXPECT(st->stats.attempts == 1);
EXPECT(st->stats.failures == 1);
@@ -881,7 +876,7 @@ static void test_reftable_stack_auto_compaction(void)
err = reftable_stack_auto_compact(st);
EXPECT_ERR(err);
- EXPECT(i < 3 || st->merged->stack_len < 2 * fastlog2(i));
+ EXPECT(i < 3 || st->merged->readers_len < 2 * fastlog2(i));
}
EXPECT(reftable_stack_compaction_stats(st)->entries_written <
@@ -905,7 +900,7 @@ static void test_reftable_stack_auto_compaction_with_locked_tables(void)
EXPECT_ERR(err);
write_n_ref_tables(st, 5);
- EXPECT(st->merged->stack_len == 5);
+ EXPECT(st->merged->readers_len == 5);
/*
* Given that all tables we have written should be roughly the same
@@ -925,7 +920,7 @@ static void test_reftable_stack_auto_compaction_with_locked_tables(void)
err = reftable_stack_auto_compact(st);
EXPECT_ERR(err);
EXPECT(st->stats.failures == 0);
- EXPECT(st->merged->stack_len == 4);
+ EXPECT(st->merged->readers_len == 4);
reftable_stack_destroy(st);
strbuf_release(&buf);
@@ -970,9 +965,9 @@ static void test_reftable_stack_add_performs_auto_compaction(void)
* all tables in the stack.
*/
if (i != n)
- EXPECT(st->merged->stack_len == i + 1);
+ EXPECT(st->merged->readers_len == i + 1);
else
- EXPECT(st->merged->stack_len == 1);
+ EXPECT(st->merged->readers_len == 1);
}
reftable_stack_destroy(st);
@@ -994,7 +989,7 @@ static void test_reftable_stack_compaction_with_locked_tables(void)
EXPECT_ERR(err);
write_n_ref_tables(st, 3);
- EXPECT(st->merged->stack_len == 3);
+ EXPECT(st->merged->readers_len == 3);
/* Lock one of the tables that we're about to compact. */
strbuf_reset(&buf);
@@ -1008,7 +1003,7 @@ static void test_reftable_stack_compaction_with_locked_tables(void)
err = reftable_stack_compact_all(st, NULL);
EXPECT(err == REFTABLE_LOCK_ERROR);
EXPECT(st->stats.failures == 1);
- EXPECT(st->merged->stack_len == 3);
+ EXPECT(st->merged->readers_len == 3);
reftable_stack_destroy(st);
strbuf_release(&buf);
@@ -1042,10 +1037,8 @@ static void test_reftable_stack_compaction_concurrent(void)
static void unclean_stack_close(struct reftable_stack *st)
{
/* break abstraction boundary to simulate unclean shutdown. */
- int i = 0;
- for (; i < st->readers_len; i++) {
- reftable_reader_free(st->readers[i]);
- }
+ for (size_t i = 0; i < st->readers_len; i++)
+ reftable_reader_decref(st->readers[i]);
st->readers_len = 0;
FREE_AND_NULL(st->readers);
}
@@ -1084,6 +1077,112 @@ static void test_reftable_stack_compaction_concurrent_clean(void)
clear_dir(dir);
}
+static void test_reftable_stack_read_across_reload(void)
+{
+ struct reftable_write_options opts = { 0 };
+ struct reftable_stack *st1 = NULL, *st2 = NULL;
+ struct reftable_ref_record rec = { 0 };
+ struct reftable_iterator it = { 0 };
+ char *dir = get_tmp_dir(__LINE__);
+ int err;
+
+ /* Create a first stack and set up an iterator for it. */
+ err = reftable_new_stack(&st1, dir, &opts);
+ EXPECT_ERR(err);
+ write_n_ref_tables(st1, 2);
+ EXPECT(st1->merged->readers_len == 2);
+ reftable_stack_init_ref_iterator(st1, &it);
+ err = reftable_iterator_seek_ref(&it, "");
+ EXPECT_ERR(err);
+
+ /* Set up a second stack for the same directory and compact it. */
+ err = reftable_new_stack(&st2, dir, &opts);
+ EXPECT_ERR(err);
+ EXPECT(st2->merged->readers_len == 2);
+ err = reftable_stack_compact_all(st2, NULL);
+ EXPECT_ERR(err);
+ EXPECT(st2->merged->readers_len == 1);
+
+ /*
+ * Verify that we can continue to use the old iterator even after we
+ * have reloaded its stack.
+ */
+ err = reftable_stack_reload(st1);
+ EXPECT_ERR(err);
+ EXPECT(st1->merged->readers_len == 1);
+ err = reftable_iterator_next_ref(&it, &rec);
+ EXPECT_ERR(err);
+ EXPECT(!strcmp(rec.refname, "refs/heads/branch-0000"));
+ err = reftable_iterator_next_ref(&it, &rec);
+ EXPECT_ERR(err);
+ EXPECT(!strcmp(rec.refname, "refs/heads/branch-0001"));
+ err = reftable_iterator_next_ref(&it, &rec);
+ EXPECT(err > 0);
+
+ reftable_ref_record_release(&rec);
+ reftable_iterator_destroy(&it);
+ reftable_stack_destroy(st1);
+ reftable_stack_destroy(st2);
+ clear_dir(dir);
+}
+
+static void test_reftable_stack_reload_with_missing_table(void)
+{
+ struct reftable_write_options opts = { 0 };
+ struct reftable_stack *st = NULL;
+ struct reftable_ref_record rec = { 0 };
+ struct reftable_iterator it = { 0 };
+ struct strbuf table_path = STRBUF_INIT, content = STRBUF_INIT;
+ char *dir = get_tmp_dir(__LINE__);
+ int err;
+
+ /* Create a first stack and set up an iterator for it. */
+ err = reftable_new_stack(&st, dir, &opts);
+ EXPECT_ERR(err);
+ write_n_ref_tables(st, 2);
+ EXPECT(st->merged->readers_len == 2);
+ reftable_stack_init_ref_iterator(st, &it);
+ err = reftable_iterator_seek_ref(&it, "");
+ EXPECT_ERR(err);
+
+ /*
+ * Update the tables.list file with some garbage data, while reusing
+ * our old readers. This should trigger a partial reload of the stack,
+ * where we try to reuse our old readers.
+ */
+ strbuf_addf(&content, "%s\n", st->readers[0]->name);
+ strbuf_addf(&content, "%s\n", st->readers[1]->name);
+ strbuf_addstr(&content, "garbage\n");
+ strbuf_addf(&table_path, "%s.lock", st->list_file);
+ write_file_buf(table_path.buf, content.buf, content.len);
+ err = rename(table_path.buf, st->list_file);
+ EXPECT_ERR(err);
+
+ err = reftable_stack_reload(st);
+ EXPECT(err == -4);
+ EXPECT(st->merged->readers_len == 2);
+
+ /*
+ * Even though the reload has failed, we should be able to continue
+ * using the iterator.
+ */
+ err = reftable_iterator_next_ref(&it, &rec);
+ EXPECT_ERR(err);
+ EXPECT(!strcmp(rec.refname, "refs/heads/branch-0000"));
+ err = reftable_iterator_next_ref(&it, &rec);
+ EXPECT_ERR(err);
+ EXPECT(!strcmp(rec.refname, "refs/heads/branch-0001"));
+ err = reftable_iterator_next_ref(&it, &rec);
+ EXPECT(err > 0);
+
+ reftable_ref_record_release(&rec);
+ reftable_iterator_destroy(&it);
+ reftable_stack_destroy(st);
+ strbuf_release(&table_path);
+ strbuf_release(&content);
+ clear_dir(dir);
+}
+
int stack_test_main(int argc UNUSED, const char *argv[] UNUSED)
{
RUN_TEST(test_empty_add);
@@ -1106,6 +1205,8 @@ int stack_test_main(int argc UNUSED, const char *argv[] UNUSED)
RUN_TEST(test_reftable_stack_auto_compaction_fails_gracefully);
RUN_TEST(test_reftable_stack_update_index_check);
RUN_TEST(test_reftable_stack_uptodate);
+ RUN_TEST(test_reftable_stack_read_across_reload);
+ RUN_TEST(test_reftable_stack_reload_with_missing_table);
RUN_TEST(test_suggest_compaction_segment);
RUN_TEST(test_suggest_compaction_segment_nothing);
return 0;
diff --git a/remote.c b/remote.c
index 7d5b8f750d..8f3dee1318 100644
--- a/remote.c
+++ b/remote.c
@@ -243,6 +243,17 @@ static struct branch *make_branch(struct remote_state *remote_state,
return ret;
}
+static void branch_release(struct branch *branch)
+{
+ free((char *)branch->name);
+ free((char *)branch->refname);
+ free(branch->remote_name);
+ free(branch->pushremote_name);
+ for (int i = 0; i < branch->merge_nr; i++)
+ refspec_item_clear(branch->merge[i]);
+ free(branch->merge);
+}
+
static struct rewrite *make_rewrite(struct rewrites *r,
const char *base, size_t len)
{
@@ -263,6 +274,14 @@ static struct rewrite *make_rewrite(struct rewrites *r,
return ret;
}
+static void rewrites_release(struct rewrites *r)
+{
+ for (int i = 0; i < r->rewrite_nr; i++)
+ free((char *)r->rewrite[i]->base);
+ free(r->rewrite);
+ memset(r, 0, sizeof(*r));
+}
+
static void add_instead_of(struct rewrite *rewrite, const char *instead_of)
{
ALLOC_GROW(rewrite->instead_of, rewrite->instead_of_nr + 1, rewrite->instead_of_alloc);
@@ -373,8 +392,10 @@ static int handle_config(const char *key, const char *value,
return -1;
branch = make_branch(remote_state, name, namelen);
if (!strcmp(subkey, "remote")) {
+ FREE_AND_NULL(branch->remote_name);
return git_config_string(&branch->remote_name, key, value);
} else if (!strcmp(subkey, "pushremote")) {
+ FREE_AND_NULL(branch->pushremote_name);
return git_config_string(&branch->pushremote_name, key, value);
} else if (!strcmp(subkey, "merge")) {
if (!value)
@@ -406,9 +427,11 @@ static int handle_config(const char *key, const char *value,
return 0;
/* Handle remote.* variables */
- if (!name && !strcmp(subkey, "pushdefault"))
+ if (!name && !strcmp(subkey, "pushdefault")) {
+ FREE_AND_NULL(remote_state->pushremote_name);
return git_config_string(&remote_state->pushremote_name, key,
value);
+ }
if (!name)
return 0;
@@ -475,12 +498,15 @@ static int handle_config(const char *key, const char *value,
else if (!strcmp(value, "--tags"))
remote->fetch_tags = 2;
} else if (!strcmp(subkey, "proxy")) {
+ FREE_AND_NULL(remote->http_proxy);
return git_config_string(&remote->http_proxy,
key, value);
} else if (!strcmp(subkey, "proxyauthmethod")) {
+ FREE_AND_NULL(remote->http_proxy_authmethod);
return git_config_string(&remote->http_proxy_authmethod,
key, value);
} else if (!strcmp(subkey, "vcs")) {
+ FREE_AND_NULL(remote->foreign_vcs);
return git_config_string(&remote->foreign_vcs, key, value);
}
return 0;
@@ -1318,18 +1344,21 @@ static int match_explicit(struct ref *src, struct ref *dst,
struct ref ***dst_tail,
struct refspec_item *rs)
{
- struct ref *matched_src, *matched_dst;
- int allocated_src;
+ struct ref *matched_src = NULL, *matched_dst = NULL;
+ int allocated_src = 0, ret;
const char *dst_value = rs->dst;
char *dst_guess;
- if (rs->pattern || rs->matching || rs->negative)
- return 0;
+ if (rs->pattern || rs->matching || rs->negative) {
+ ret = 0;
+ goto out;
+ }
- matched_src = matched_dst = NULL;
- if (match_explicit_lhs(src, rs, &matched_src, &allocated_src) < 0)
- return -1;
+ if (match_explicit_lhs(src, rs, &matched_src, &allocated_src) < 0) {
+ ret = -1;
+ goto out;
+ }
if (!dst_value) {
int flag;
@@ -1368,18 +1397,30 @@ static int match_explicit(struct ref *src, struct ref *dst,
dst_value);
break;
}
- if (!matched_dst)
- return -1;
- if (matched_dst->peer_ref)
- return error(_("dst ref %s receives from more than one src"),
- matched_dst->name);
- else {
+
+ if (!matched_dst) {
+ ret = -1;
+ goto out;
+ }
+
+ if (matched_dst->peer_ref) {
+ ret = error(_("dst ref %s receives from more than one src"),
+ matched_dst->name);
+ goto out;
+ } else {
matched_dst->peer_ref = allocated_src ?
matched_src :
copy_ref(matched_src);
matched_dst->force = rs->force;
+ matched_src = NULL;
}
- return 0;
+
+ ret = 0;
+
+out:
+ if (allocated_src)
+ free_one_ref(matched_src);
+ return ret;
}
static int match_explicit_refs(struct ref *src, struct ref *dst,
@@ -2040,6 +2081,8 @@ static struct ref *get_expanded_map(const struct ref *remote_refs,
!ignore_symref_update(expn_name, &scratch)) {
struct ref *cpy = copy_ref(ref);
+ if (cpy->peer_ref)
+ free_one_ref(cpy->peer_ref);
cpy->peer_ref = alloc_ref(expn_name);
if (refspec->force)
cpy->peer_ref->force = 1;
@@ -2797,16 +2840,26 @@ struct remote_state *remote_state_new(void)
void remote_state_clear(struct remote_state *remote_state)
{
+ struct hashmap_iter iter;
+ struct branch *b;
int i;
for (i = 0; i < remote_state->remotes_nr; i++)
remote_clear(remote_state->remotes[i]);
FREE_AND_NULL(remote_state->remotes);
+ FREE_AND_NULL(remote_state->pushremote_name);
remote_state->remotes_alloc = 0;
remote_state->remotes_nr = 0;
+ rewrites_release(&remote_state->rewrites);
+ rewrites_release(&remote_state->rewrites_push);
+
hashmap_clear_and_free(&remote_state->remotes_hash, struct remote, ent);
- hashmap_clear_and_free(&remote_state->branches_hash, struct remote, ent);
+ hashmap_for_each_entry(&remote_state->branches_hash, &iter, b, ent) {
+ branch_release(b);
+ free(b);
+ }
+ hashmap_clear(&remote_state->branches_hash);
}
/*
diff --git a/revision.c b/revision.c
index ac94f8d429..2d7ad2bddf 100644
--- a/revision.c
+++ b/revision.c
@@ -4407,6 +4407,7 @@ static struct commit *get_revision_internal(struct rev_info *revs)
c = get_revision_1(revs);
if (!c)
break;
+ free_commit_buffer(revs->repo->parsed_objects, c);
}
}
diff --git a/send-pack.c b/send-pack.c
index fa2f5eec17..9666b2c995 100644
--- a/send-pack.c
+++ b/send-pack.c
@@ -75,6 +75,7 @@ static int pack_objects(int fd, struct ref *refs, struct oid_array *advertised,
int i;
int rc;
+ trace2_region_enter("send_pack", "pack_objects", the_repository);
strvec_push(&po.args, "pack-objects");
strvec_push(&po.args, "--all-progress-implied");
strvec_push(&po.args, "--revs");
@@ -146,8 +147,10 @@ static int pack_objects(int fd, struct ref *refs, struct oid_array *advertised,
*/
if (rc > 128 && rc != 141)
error("pack-objects died of signal %d", rc - 128);
+ trace2_region_leave("send_pack", "pack_objects", the_repository);
return -1;
}
+ trace2_region_leave("send_pack", "pack_objects", the_repository);
return 0;
}
@@ -170,6 +173,7 @@ static int receive_status(struct packet_reader *reader, struct ref *refs)
int new_report = 0;
int once = 0;
+ trace2_region_enter("send_pack", "receive_status", the_repository);
hint = NULL;
ret = receive_unpack_status(reader);
while (1) {
@@ -268,6 +272,7 @@ static int receive_status(struct packet_reader *reader, struct ref *refs)
new_report = 1;
}
}
+ trace2_region_leave("send_pack", "receive_status", the_repository);
return ret;
}
@@ -512,8 +517,11 @@ int send_pack(struct send_pack_args *args,
}
git_config_get_bool("push.negotiate", &push_negotiate);
- if (push_negotiate)
+ if (push_negotiate) {
+ trace2_region_enter("send_pack", "push_negotiate", the_repository);
get_commons_through_negotiation(args->url, remote_refs, &commons);
+ trace2_region_leave("send_pack", "push_negotiate", the_repository);
+ }
if (!git_config_get_bool("push.usebitmaps", &use_bitmaps))
args->disable_bitmaps = !use_bitmaps;
@@ -641,10 +649,11 @@ int send_pack(struct send_pack_args *args,
/*
* Finally, tell the other end!
*/
- if (!args->dry_run && push_cert_nonce)
+ if (!args->dry_run && push_cert_nonce) {
cmds_sent = generate_push_cert(&req_buf, remote_refs, args,
cap_buf.buf, push_cert_nonce);
- else if (!args->dry_run)
+ trace2_printf("Generated push certificate");
+ } else if (!args->dry_run) {
for (ref = remote_refs; ref; ref = ref->next) {
char *old_hex, *new_hex;
@@ -664,6 +673,7 @@ int send_pack(struct send_pack_args *args,
old_hex, new_hex, ref->name);
}
}
+ }
if (use_push_options) {
struct string_list_item *item;
diff --git a/sequencer.c b/sequencer.c
index e592df0f51..8d01cd50ac 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -3794,12 +3794,13 @@ static int error_failed_squash(struct repository *r,
return error_with_patch(r, commit, subject, subject_len, opts, 1, 0);
}
-static int do_exec(struct repository *r, const char *command_line)
+static int do_exec(struct repository *r, const char *command_line, int quiet)
{
struct child_process cmd = CHILD_PROCESS_INIT;
int dirty, status;
- fprintf(stderr, _("Executing: %s\n"), command_line);
+ if (!quiet)
+ fprintf(stderr, _("Executing: %s\n"), command_line);
cmd.use_shell = 1;
strvec_push(&cmd.args, command_line);
strvec_push(&cmd.env, "GIT_CHERRY_PICK_HELP");
@@ -5014,7 +5015,7 @@ static int pick_commits(struct repository *r,
if (!opts->verbose)
term_clear_line();
*end_of_arg = '\0';
- res = do_exec(r, arg);
+ res = do_exec(r, arg, opts->quiet);
*end_of_arg = saved;
if (res) {
diff --git a/sideband.c b/sideband.c
index 5b6b872a1c..4e816be4e9 100644
--- a/sideband.c
+++ b/sideband.c
@@ -32,28 +32,27 @@ static int use_sideband_colors(void)
const char *key = "color.remote";
struct strbuf sb = STRBUF_INIT;
- char *value;
+ const char *value;
int i;
if (use_sideband_colors_cached >= 0)
return use_sideband_colors_cached;
- if (!git_config_get_string(key, &value)) {
+ if (!git_config_get_string_tmp(key, &value))
use_sideband_colors_cached = git_config_colorbool(key, value);
- } else if (!git_config_get_string("color.ui", &value)) {
+ else if (!git_config_get_string_tmp("color.ui", &value))
use_sideband_colors_cached = git_config_colorbool("color.ui", value);
- } else {
+ else
use_sideband_colors_cached = GIT_COLOR_AUTO;
- }
for (i = 0; i < ARRAY_SIZE(keywords); i++) {
strbuf_reset(&sb);
strbuf_addf(&sb, "%s.%s", key, keywords[i].keyword);
- if (git_config_get_string(sb.buf, &value))
- continue;
- if (color_parse(value, keywords[i].color))
+ if (git_config_get_string_tmp(sb.buf, &value))
continue;
+ color_parse(value, keywords[i].color);
}
+
strbuf_release(&sb);
return use_sideband_colors_cached;
}
diff --git a/t/helper/test-oid-array.c b/t/helper/test-oid-array.c
deleted file mode 100644
index 076b849cbf..0000000000
--- a/t/helper/test-oid-array.c
+++ /dev/null
@@ -1,49 +0,0 @@
-#define USE_THE_REPOSITORY_VARIABLE
-
-#include "test-tool.h"
-#include "hex.h"
-#include "oid-array.h"
-#include "setup.h"
-#include "strbuf.h"
-
-static int print_oid(const struct object_id *oid, void *data UNUSED)
-{
- puts(oid_to_hex(oid));
- return 0;
-}
-
-int cmd__oid_array(int argc UNUSED, const char **argv UNUSED)
-{
- struct oid_array array = OID_ARRAY_INIT;
- struct strbuf line = STRBUF_INIT;
- int nongit_ok;
-
- setup_git_directory_gently(&nongit_ok);
- if (nongit_ok)
- repo_set_hash_algo(the_repository, GIT_HASH_SHA1);
-
- while (strbuf_getline(&line, stdin) != EOF) {
- const char *arg;
- struct object_id oid;
-
- if (skip_prefix(line.buf, "append ", &arg)) {
- if (get_oid_hex(arg, &oid))
- die("not a hexadecimal oid: %s", arg);
- oid_array_append(&array, &oid);
- } else if (skip_prefix(line.buf, "lookup ", &arg)) {
- if (get_oid_hex(arg, &oid))
- die("not a hexadecimal oid: %s", arg);
- printf("%d\n", oid_array_lookup(&array, &oid));
- } else if (!strcmp(line.buf, "clear"))
- oid_array_clear(&array);
- else if (!strcmp(line.buf, "for_each_unique"))
- oid_array_for_each_unique(&array, print_oid, NULL);
- else
- die("unknown command: %s", line.buf);
- }
-
- strbuf_release(&line);
- oid_array_clear(&array);
-
- return 0;
-}
diff --git a/t/helper/test-read-midx.c b/t/helper/test-read-midx.c
index 69757e94fc..438fb9fc61 100644
--- a/t/helper/test-read-midx.c
+++ b/t/helper/test-read-midx.c
@@ -86,6 +86,8 @@ static int read_midx_checksum(const char *object_dir)
if (!m)
return 1;
printf("%s\n", hash_to_hex(get_midx_checksum(m)));
+
+ close_midx(m);
return 0;
}
@@ -102,10 +104,12 @@ static int read_midx_preferred_pack(const char *object_dir)
if (midx_preferred_pack(midx, &preferred_pack) < 0) {
warning(_("could not determine MIDX preferred pack"));
+ close_midx(midx);
return 1;
}
printf("%s\n", midx->pack_names[preferred_pack]);
+ close_midx(midx);
return 0;
}
@@ -122,8 +126,10 @@ static int read_midx_bitmapped_packs(const char *object_dir)
return 1;
for (i = 0; i < midx->num_packs + midx->num_packs_in_base; i++) {
- if (nth_bitmapped_pack(the_repository, midx, &pack, i) < 0)
+ if (nth_bitmapped_pack(the_repository, midx, &pack, i) < 0) {
+ close_midx(midx);
return 1;
+ }
printf("%s\n", pack_basename(pack.p));
printf(" bitmap_pos: %"PRIuMAX"\n", (uintmax_t)pack.bitmap_pos);
diff --git a/t/helper/test-reftable.c b/t/helper/test-reftable.c
index ded28ee5fb..ce5a94fbd3 100644
--- a/t/helper/test-reftable.c
+++ b/t/helper/test-reftable.c
@@ -1,16 +1,202 @@
+#include "git-compat-util.h"
+#include "hash.h"
+#include "hex.h"
#include "reftable/system.h"
+#include "reftable/reftable-error.h"
+#include "reftable/reftable-merged.h"
+#include "reftable/reftable-reader.h"
+#include "reftable/reftable-stack.h"
#include "reftable/reftable-tests.h"
#include "test-tool.h"
int cmd__reftable(int argc, const char **argv)
{
/* test from simple to complex. */
- block_test_main(argc, argv);
stack_test_main(argc, argv);
return 0;
}
+static void print_help(void)
+{
+ printf("usage: dump [-st] arg\n\n"
+ "options: \n"
+ " -b dump blocks\n"
+ " -t dump table\n"
+ " -s dump stack\n"
+ " -6 sha256 hash format\n"
+ " -h this help\n"
+ "\n");
+}
+
+static int dump_table(struct reftable_merged_table *mt)
+{
+ struct reftable_iterator it = { NULL };
+ struct reftable_ref_record ref = { NULL };
+ struct reftable_log_record log = { NULL };
+ const struct git_hash_algo *algop;
+ int err;
+
+ reftable_merged_table_init_ref_iterator(mt, &it);
+ err = reftable_iterator_seek_ref(&it, "");
+ if (err < 0)
+ return err;
+
+ algop = &hash_algos[hash_algo_by_id(reftable_merged_table_hash_id(mt))];
+
+ while (1) {
+ err = reftable_iterator_next_ref(&it, &ref);
+ if (err > 0)
+ break;
+ if (err < 0)
+ return err;
+
+ printf("ref{%s(%" PRIu64 ") ", ref.refname, ref.update_index);
+ switch (ref.value_type) {
+ case REFTABLE_REF_SYMREF:
+ printf("=> %s", ref.value.symref);
+ break;
+ case REFTABLE_REF_VAL2:
+ printf("val 2 %s", hash_to_hex_algop(ref.value.val2.value, algop));
+ printf("(T %s)", hash_to_hex_algop(ref.value.val2.target_value, algop));
+ break;
+ case REFTABLE_REF_VAL1:
+ printf("val 1 %s", hash_to_hex_algop(ref.value.val1, algop));
+ break;
+ case REFTABLE_REF_DELETION:
+ printf("delete");
+ break;
+ }
+ printf("}\n");
+ }
+ reftable_iterator_destroy(&it);
+ reftable_ref_record_release(&ref);
+
+ reftable_merged_table_init_log_iterator(mt, &it);
+ err = reftable_iterator_seek_log(&it, "");
+ if (err < 0)
+ return err;
+
+ while (1) {
+ err = reftable_iterator_next_log(&it, &log);
+ if (err > 0)
+ break;
+ if (err < 0)
+ return err;
+
+ switch (log.value_type) {
+ case REFTABLE_LOG_DELETION:
+ printf("log{%s(%" PRIu64 ") delete\n", log.refname,
+ log.update_index);
+ break;
+ case REFTABLE_LOG_UPDATE:
+ printf("log{%s(%" PRIu64 ") %s <%s> %" PRIu64 " %04d\n",
+ log.refname, log.update_index,
+ log.value.update.name ? log.value.update.name : "",
+ log.value.update.email ? log.value.update.email : "",
+ log.value.update.time,
+ log.value.update.tz_offset);
+ printf("%s => ", hash_to_hex_algop(log.value.update.old_hash, algop));
+ printf("%s\n\n%s\n}\n", hash_to_hex_algop(log.value.update.new_hash, algop),
+ log.value.update.message ? log.value.update.message : "");
+ break;
+ }
+ }
+ reftable_iterator_destroy(&it);
+ reftable_log_record_release(&log);
+ return 0;
+}
+
+static int dump_stack(const char *stackdir, uint32_t hash_id)
+{
+ struct reftable_stack *stack = NULL;
+ struct reftable_write_options opts = { .hash_id = hash_id };
+ struct reftable_merged_table *merged = NULL;
+
+ int err = reftable_new_stack(&stack, stackdir, &opts);
+ if (err < 0)
+ goto done;
+
+ merged = reftable_stack_merged_table(stack);
+ err = dump_table(merged);
+done:
+ if (stack)
+ reftable_stack_destroy(stack);
+ return err;
+}
+
+static int dump_reftable(const char *tablename)
+{
+ struct reftable_block_source src = { 0 };
+ struct reftable_merged_table *mt = NULL;
+ struct reftable_reader *r = NULL;
+ int err;
+
+ err = reftable_block_source_from_file(&src, tablename);
+ if (err < 0)
+ goto done;
+
+ err = reftable_reader_new(&r, &src, tablename);
+ if (err < 0)
+ goto done;
+
+ err = reftable_merged_table_new(&mt, &r, 1,
+ reftable_reader_hash_id(r));
+ if (err < 0)
+ goto done;
+
+ err = dump_table(mt);
+
+done:
+ reftable_merged_table_free(mt);
+ reftable_reader_decref(r);
+ return err;
+}
+
int cmd__dump_reftable(int argc, const char **argv)
{
- return reftable_dump_main(argc, (char *const *)argv);
+ int err = 0;
+ int opt_dump_blocks = 0;
+ int opt_dump_table = 0;
+ int opt_dump_stack = 0;
+ uint32_t opt_hash_id = GIT_SHA1_FORMAT_ID;
+ const char *arg = NULL, *argv0 = argv[0];
+
+ for (; argc > 1; argv++, argc--)
+ if (*argv[1] != '-')
+ break;
+ else if (!strcmp("-b", argv[1]))
+ opt_dump_blocks = 1;
+ else if (!strcmp("-t", argv[1]))
+ opt_dump_table = 1;
+ else if (!strcmp("-6", argv[1]))
+ opt_hash_id = GIT_SHA256_FORMAT_ID;
+ else if (!strcmp("-s", argv[1]))
+ opt_dump_stack = 1;
+ else if (!strcmp("-?", argv[1]) || !strcmp("-h", argv[1])) {
+ print_help();
+ return 2;
+ }
+
+ if (argc != 2) {
+ fprintf(stderr, "need argument\n");
+ print_help();
+ return 2;
+ }
+
+ arg = argv[1];
+
+ if (opt_dump_blocks) {
+ err = reftable_reader_print_blocks(arg);
+ } else if (opt_dump_table) {
+ err = dump_reftable(arg);
+ } else if (opt_dump_stack) {
+ err = dump_stack(arg, opt_hash_id);
+ }
+
+ if (err < 0) {
+ fprintf(stderr, "%s: %s: %s\n", argv0, arg,
+ reftable_error_str(err));
+ return 1;
+ }
+ return 0;
}
diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c
index da3e69128a..7005b7d0bf 100644
--- a/t/helper/test-tool.c
+++ b/t/helper/test-tool.c
@@ -43,7 +43,6 @@ static struct test_cmd cmds[] = {
{ "match-trees", cmd__match_trees },
{ "mergesort", cmd__mergesort },
{ "mktemp", cmd__mktemp },
- { "oid-array", cmd__oid_array },
{ "online-cpus", cmd__online_cpus },
{ "pack-mtimes", cmd__pack_mtimes },
{ "parse-options", cmd__parse_options },
@@ -83,7 +82,6 @@ static struct test_cmd cmds[] = {
{ "trace2", cmd__trace2 },
{ "truncate", cmd__truncate },
{ "userdiff", cmd__userdiff },
- { "urlmatch-normalization", cmd__urlmatch_normalization },
{ "xml-encode", cmd__xml_encode },
{ "wildmatch", cmd__wildmatch },
#ifdef GIT_WINDOWS_NATIVE
diff --git a/t/helper/test-tool.h b/t/helper/test-tool.h
index 642a34578c..b51f79e774 100644
--- a/t/helper/test-tool.h
+++ b/t/helper/test-tool.h
@@ -64,7 +64,6 @@ int cmd__scrap_cache_tree(int argc, const char **argv);
int cmd__serve_v2(int argc, const char **argv);
int cmd__sha1(int argc, const char **argv);
int cmd__sha1_is_sha1dc(int argc, const char **argv);
-int cmd__oid_array(int argc, const char **argv);
int cmd__sha256(int argc, const char **argv);
int cmd__sigchain(int argc, const char **argv);
int cmd__simple_ipc(int argc, const char **argv);
@@ -76,7 +75,6 @@ int cmd__subprocess(int argc, const char **argv);
int cmd__trace2(int argc, const char **argv);
int cmd__truncate(int argc, const char **argv);
int cmd__userdiff(int argc, const char **argv);
-int cmd__urlmatch_normalization(int argc, const char **argv);
int cmd__xml_encode(int argc, const char **argv);
int cmd__wildmatch(int argc, const char **argv);
#ifdef GIT_WINDOWS_NATIVE
diff --git a/t/helper/test-urlmatch-normalization.c b/t/helper/test-urlmatch-normalization.c
deleted file mode 100644
index 86edd454f5..0000000000
--- a/t/helper/test-urlmatch-normalization.c
+++ /dev/null
@@ -1,56 +0,0 @@
-#include "test-tool.h"
-#include "git-compat-util.h"
-#include "urlmatch.h"
-
-int cmd__urlmatch_normalization(int argc, const char **argv)
-{
- const char usage[] = "test-tool urlmatch-normalization [-p | -l] <url1> | <url1> <url2>";
- char *url1 = NULL, *url2 = NULL;
- int opt_p = 0, opt_l = 0;
- int ret = 0;
-
- /*
- * For one url, succeed if url_normalize succeeds on it, fail otherwise.
- * For two urls, succeed only if url_normalize succeeds on both and
- * the results compare equal with strcmp. If -p is given (one url only)
- * and url_normalize succeeds, print the result followed by "\n". If
- * -l is given (one url only) and url_normalize succeeds, print the
- * returned length in decimal followed by "\n".
- */
-
- if (argc > 1 && !strcmp(argv[1], "-p")) {
- opt_p = 1;
- argc--;
- argv++;
- } else if (argc > 1 && !strcmp(argv[1], "-l")) {
- opt_l = 1;
- argc--;
- argv++;
- }
-
- if (argc < 2 || argc > 3)
- die("%s", usage);
-
- if (argc == 2) {
- struct url_info info;
- url1 = url_normalize(argv[1], &info);
- if (!url1)
- return 1;
- if (opt_p)
- printf("%s\n", url1);
- if (opt_l)
- printf("%u\n", (unsigned)info.url_len);
- goto cleanup;
- }
-
- if (opt_p || opt_l)
- die("%s", usage);
-
- url1 = url_normalize(argv[1], NULL);
- url2 = url_normalize(argv[2], NULL);
- ret = (url1 && url2 && !strcmp(url1, url2)) ? 0 : 1;
-cleanup:
- free(url1);
- free(url2);
- return ret;
-}
diff --git a/t/t0064-oid-array.sh b/t/t0064-oid-array.sh
deleted file mode 100755
index de74b692d0..0000000000
--- a/t/t0064-oid-array.sh
+++ /dev/null
@@ -1,122 +0,0 @@
-#!/bin/sh
-
-test_description='basic tests for the oid array implementation'
-
-TEST_PASSES_SANITIZE_LEAK=true
-. ./test-lib.sh
-
-echoid () {
- prefix="${1:+$1 }"
- shift
- while test $# -gt 0
- do
- echo "$prefix$ZERO_OID" | sed -e "s/00/$1/g"
- shift
- done
-}
-
-test_expect_success 'without repository' '
- cat >expect <<-EOF &&
- 4444444444444444444444444444444444444444
- 5555555555555555555555555555555555555555
- 8888888888888888888888888888888888888888
- aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
- EOF
- cat >input <<-EOF &&
- append 4444444444444444444444444444444444444444
- append 5555555555555555555555555555555555555555
- append 8888888888888888888888888888888888888888
- append aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
- for_each_unique
- EOF
- nongit test-tool oid-array <input >actual &&
- test_cmp expect actual
-'
-
-test_expect_success 'ordered enumeration' '
- echoid "" 44 55 88 aa >expect &&
- {
- echoid append 88 44 aa 55 &&
- echo for_each_unique
- } | test-tool oid-array >actual &&
- test_cmp expect actual
-'
-
-test_expect_success 'ordered enumeration with duplicate suppression' '
- echoid "" 44 55 88 aa >expect &&
- {
- echoid append 88 44 aa 55 &&
- echoid append 88 44 aa 55 &&
- echoid append 88 44 aa 55 &&
- echo for_each_unique
- } | test-tool oid-array >actual &&
- test_cmp expect actual
-'
-
-test_expect_success 'lookup' '
- {
- echoid append 88 44 aa 55 &&
- echoid lookup 55
- } | test-tool oid-array >actual &&
- n=$(cat actual) &&
- test "$n" -eq 1
-'
-
-test_expect_success 'lookup non-existing entry' '
- {
- echoid append 88 44 aa 55 &&
- echoid lookup 33
- } | test-tool oid-array >actual &&
- n=$(cat actual) &&
- test "$n" -lt 0
-'
-
-test_expect_success 'lookup with duplicates' '
- {
- echoid append 88 44 aa 55 &&
- echoid append 88 44 aa 55 &&
- echoid append 88 44 aa 55 &&
- echoid lookup 55
- } | test-tool oid-array >actual &&
- n=$(cat actual) &&
- test "$n" -ge 3 &&
- test "$n" -le 5
-'
-
-test_expect_success 'lookup non-existing entry with duplicates' '
- {
- echoid append 88 44 aa 55 &&
- echoid append 88 44 aa 55 &&
- echoid append 88 44 aa 55 &&
- echoid lookup 66
- } | test-tool oid-array >actual &&
- n=$(cat actual) &&
- test "$n" -lt 0
-'
-
-test_expect_success 'lookup with almost duplicate values' '
- # n-1 5s
- root=$(echoid "" 55) &&
- root=${root%5} &&
- {
- id1="${root}5" &&
- id2="${root}f" &&
- echo "append $id1" &&
- echo "append $id2" &&
- echoid lookup 55
- } | test-tool oid-array >actual &&
- n=$(cat actual) &&
- test "$n" -eq 0
-'
-
-test_expect_success 'lookup with single duplicate value' '
- {
- echoid append 55 55 &&
- echoid lookup 55
- } | test-tool oid-array >actual &&
- n=$(cat actual) &&
- test "$n" -ge 0 &&
- test "$n" -le 1
-'
-
-test_done
diff --git a/t/t0110-urlmatch-normalization.sh b/t/t0110-urlmatch-normalization.sh
deleted file mode 100755
index 12d817fbd3..0000000000
--- a/t/t0110-urlmatch-normalization.sh
+++ /dev/null
@@ -1,182 +0,0 @@
-#!/bin/sh
-
-test_description='urlmatch URL normalization'
-
-TEST_PASSES_SANITIZE_LEAK=true
-. ./test-lib.sh
-
-# The base name of the test url files
-tu="$TEST_DIRECTORY/t0110/url"
-
-# Note that only file: URLs should be allowed without a host
-
-test_expect_success 'url scheme' '
- ! test-tool urlmatch-normalization "" &&
- ! test-tool urlmatch-normalization "_" &&
- ! test-tool urlmatch-normalization "scheme" &&
- ! test-tool urlmatch-normalization "scheme:" &&
- ! test-tool urlmatch-normalization "scheme:/" &&
- ! test-tool urlmatch-normalization "scheme://" &&
- ! test-tool urlmatch-normalization "file" &&
- ! test-tool urlmatch-normalization "file:" &&
- ! test-tool urlmatch-normalization "file:/" &&
- test-tool urlmatch-normalization "file://" &&
- ! test-tool urlmatch-normalization "://acme.co" &&
- ! test-tool urlmatch-normalization "x_test://acme.co" &&
- ! test-tool urlmatch-normalization "-test://acme.co" &&
- ! test-tool urlmatch-normalization "0test://acme.co" &&
- ! test-tool urlmatch-normalization "+test://acme.co" &&
- ! test-tool urlmatch-normalization ".test://acme.co" &&
- ! test-tool urlmatch-normalization "schem%6e://" &&
- test-tool urlmatch-normalization "x-Test+v1.0://acme.co" &&
- test "$(test-tool urlmatch-normalization -p "AbCdeF://x.Y")" = "abcdef://x.y/"
-'
-
-test_expect_success 'url authority' '
- ! test-tool urlmatch-normalization "scheme://user:pass@" &&
- ! test-tool urlmatch-normalization "scheme://?" &&
- ! test-tool urlmatch-normalization "scheme://#" &&
- ! test-tool urlmatch-normalization "scheme:///" &&
- ! test-tool urlmatch-normalization "scheme://:" &&
- ! test-tool urlmatch-normalization "scheme://:555" &&
- test-tool urlmatch-normalization "file://user:pass@" &&
- test-tool urlmatch-normalization "file://?" &&
- test-tool urlmatch-normalization "file://#" &&
- test-tool urlmatch-normalization "file:///" &&
- test-tool urlmatch-normalization "file://:" &&
- ! test-tool urlmatch-normalization "file://:555" &&
- test-tool urlmatch-normalization "scheme://user:pass@host" &&
- test-tool urlmatch-normalization "scheme://@host" &&
- test-tool urlmatch-normalization "scheme://%00@host" &&
- ! test-tool urlmatch-normalization "scheme://%%@host" &&
- test-tool urlmatch-normalization "scheme://host_" &&
- test-tool urlmatch-normalization "scheme://user:pass@host/" &&
- test-tool urlmatch-normalization "scheme://@host/" &&
- test-tool urlmatch-normalization "scheme://host/" &&
- test-tool urlmatch-normalization "scheme://host?x" &&
- test-tool urlmatch-normalization "scheme://host#x" &&
- test-tool urlmatch-normalization "scheme://host/@" &&
- test-tool urlmatch-normalization "scheme://host?@x" &&
- test-tool urlmatch-normalization "scheme://host#@x" &&
- test-tool urlmatch-normalization "scheme://[::1]" &&
- test-tool urlmatch-normalization "scheme://[::1]/" &&
- ! test-tool urlmatch-normalization "scheme://hos%41/" &&
- test-tool urlmatch-normalization "scheme://[invalid....:/" &&
- test-tool urlmatch-normalization "scheme://invalid....:]/" &&
- ! test-tool urlmatch-normalization "scheme://invalid....:[/" &&
- ! test-tool urlmatch-normalization "scheme://invalid....:["
-'
-
-test_expect_success 'url port checks' '
- test-tool urlmatch-normalization "xyz://q@some.host:" &&
- test-tool urlmatch-normalization "xyz://q@some.host:456/" &&
- ! test-tool urlmatch-normalization "xyz://q@some.host:0" &&
- ! test-tool urlmatch-normalization "xyz://q@some.host:0000000" &&
- test-tool urlmatch-normalization "xyz://q@some.host:0000001?" &&
- test-tool urlmatch-normalization "xyz://q@some.host:065535#" &&
- test-tool urlmatch-normalization "xyz://q@some.host:65535" &&
- ! test-tool urlmatch-normalization "xyz://q@some.host:65536" &&
- ! test-tool urlmatch-normalization "xyz://q@some.host:99999" &&
- ! test-tool urlmatch-normalization "xyz://q@some.host:100000" &&
- ! test-tool urlmatch-normalization "xyz://q@some.host:100001" &&
- test-tool urlmatch-normalization "http://q@some.host:80" &&
- test-tool urlmatch-normalization "https://q@some.host:443" &&
- test-tool urlmatch-normalization "http://q@some.host:80/" &&
- test-tool urlmatch-normalization "https://q@some.host:443?" &&
- ! test-tool urlmatch-normalization "http://q@:8008" &&
- ! test-tool urlmatch-normalization "http://:8080" &&
- ! test-tool urlmatch-normalization "http://:" &&
- test-tool urlmatch-normalization "xyz://q@some.host:456/" &&
- test-tool urlmatch-normalization "xyz://[::1]:456/" &&
- test-tool urlmatch-normalization "xyz://[::1]:/" &&
- ! test-tool urlmatch-normalization "xyz://[::1]:000/" &&
- ! test-tool urlmatch-normalization "xyz://[::1]:0%300/" &&
- ! test-tool urlmatch-normalization "xyz://[::1]:0x80/" &&
- ! test-tool urlmatch-normalization "xyz://[::1]:4294967297/" &&
- ! test-tool urlmatch-normalization "xyz://[::1]:030f/"
-'
-
-test_expect_success 'url port normalization' '
- test "$(test-tool urlmatch-normalization -p "http://x:800")" = "http://x:800/" &&
- test "$(test-tool urlmatch-normalization -p "http://x:0800")" = "http://x:800/" &&
- test "$(test-tool urlmatch-normalization -p "http://x:00000800")" = "http://x:800/" &&
- test "$(test-tool urlmatch-normalization -p "http://x:065535")" = "http://x:65535/" &&
- test "$(test-tool urlmatch-normalization -p "http://x:1")" = "http://x:1/" &&
- test "$(test-tool urlmatch-normalization -p "http://x:80")" = "http://x/" &&
- test "$(test-tool urlmatch-normalization -p "http://x:080")" = "http://x/" &&
- test "$(test-tool urlmatch-normalization -p "http://x:000000080")" = "http://x/" &&
- test "$(test-tool urlmatch-normalization -p "https://x:443")" = "https://x/" &&
- test "$(test-tool urlmatch-normalization -p "https://x:0443")" = "https://x/" &&
- test "$(test-tool urlmatch-normalization -p "https://x:000000443")" = "https://x/"
-'
-
-test_expect_success 'url general escapes' '
- ! test-tool urlmatch-normalization "http://x.y?%fg" &&
- test "$(test-tool urlmatch-normalization -p "X://W/%7e%41^%3a")" = "x://w/~A%5E%3A" &&
- test "$(test-tool urlmatch-normalization -p "X://W/:/?#[]@")" = "x://w/:/?#[]@" &&
- test "$(test-tool urlmatch-normalization -p "X://W/$&()*+,;=")" = "x://w/$&()*+,;=" &&
- test "$(test-tool urlmatch-normalization -p "X://W/'\''")" = "x://w/'\''" &&
- test "$(test-tool urlmatch-normalization -p "X://W?'\!'")" = "x://w/?'\!'"
-'
-
-test_expect_success !MINGW 'url high-bit escapes' '
- test "$(test-tool urlmatch-normalization -p "$(cat "$tu-1")")" = "x://q/%01%02%03%04%05%06%07%08%0E%0F%10%11%12" &&
- test "$(test-tool urlmatch-normalization -p "$(cat "$tu-2")")" = "x://q/%13%14%15%16%17%18%19%1B%1C%1D%1E%1F%7F" &&
- test "$(test-tool urlmatch-normalization -p "$(cat "$tu-3")")" = "x://q/%80%81%82%83%84%85%86%87%88%89%8A%8B%8C%8D%8E%8F" &&
- test "$(test-tool urlmatch-normalization -p "$(cat "$tu-4")")" = "x://q/%90%91%92%93%94%95%96%97%98%99%9A%9B%9C%9D%9E%9F" &&
- test "$(test-tool urlmatch-normalization -p "$(cat "$tu-5")")" = "x://q/%A0%A1%A2%A3%A4%A5%A6%A7%A8%A9%AA%AB%AC%AD%AE%AF" &&
- test "$(test-tool urlmatch-normalization -p "$(cat "$tu-6")")" = "x://q/%B0%B1%B2%B3%B4%B5%B6%B7%B8%B9%BA%BB%BC%BD%BE%BF" &&
- test "$(test-tool urlmatch-normalization -p "$(cat "$tu-7")")" = "x://q/%C0%C1%C2%C3%C4%C5%C6%C7%C8%C9%CA%CB%CC%CD%CE%CF" &&
- test "$(test-tool urlmatch-normalization -p "$(cat "$tu-8")")" = "x://q/%D0%D1%D2%D3%D4%D5%D6%D7%D8%D9%DA%DB%DC%DD%DE%DF" &&
- test "$(test-tool urlmatch-normalization -p "$(cat "$tu-9")")" = "x://q/%E0%E1%E2%E3%E4%E5%E6%E7%E8%E9%EA%EB%EC%ED%EE%EF" &&
- test "$(test-tool urlmatch-normalization -p "$(cat "$tu-10")")" = "x://q/%F0%F1%F2%F3%F4%F5%F6%F7%F8%F9%FA%FB%FC%FD%FE%FF"
-'
-
-test_expect_success 'url utf-8 escapes' '
- test "$(test-tool urlmatch-normalization -p "$(cat "$tu-11")")" = "x://q/%C2%80%DF%BF%E0%A0%80%EF%BF%BD%F0%90%80%80%F0%AF%BF%BD"
-'
-
-test_expect_success 'url username/password escapes' '
- test "$(test-tool urlmatch-normalization -p "x://%41%62(^):%70+d@foo")" = "x://Ab(%5E):p+d@foo/"
-'
-
-test_expect_success 'url normalized lengths' '
- test "$(test-tool urlmatch-normalization -l "Http://%4d%65:%4d^%70@The.Host")" = 25 &&
- test "$(test-tool urlmatch-normalization -l "http://%41:%42@x.y/%61/")" = 17 &&
- test "$(test-tool urlmatch-normalization -l "http://@x.y/^")" = 15
-'
-
-test_expect_success 'url . and .. segments' '
- test "$(test-tool urlmatch-normalization -p "x://y/.")" = "x://y/" &&
- test "$(test-tool urlmatch-normalization -p "x://y/./")" = "x://y/" &&
- test "$(test-tool urlmatch-normalization -p "x://y/a/.")" = "x://y/a" &&
- test "$(test-tool urlmatch-normalization -p "x://y/a/./")" = "x://y/a/" &&
- test "$(test-tool urlmatch-normalization -p "x://y/.?")" = "x://y/?" &&
- test "$(test-tool urlmatch-normalization -p "x://y/./?")" = "x://y/?" &&
- test "$(test-tool urlmatch-normalization -p "x://y/a/.?")" = "x://y/a?" &&
- test "$(test-tool urlmatch-normalization -p "x://y/a/./?")" = "x://y/a/?" &&
- test "$(test-tool urlmatch-normalization -p "x://y/a/./b/.././../c")" = "x://y/c" &&
- test "$(test-tool urlmatch-normalization -p "x://y/a/./b/../.././c/")" = "x://y/c/" &&
- test "$(test-tool urlmatch-normalization -p "x://y/a/./b/.././../c/././.././.")" = "x://y/" &&
- ! test-tool urlmatch-normalization "x://y/a/./b/.././../c/././.././.." &&
- test "$(test-tool urlmatch-normalization -p "x://y/a/./?/././..")" = "x://y/a/?/././.." &&
- test "$(test-tool urlmatch-normalization -p "x://y/%2e/")" = "x://y/" &&
- test "$(test-tool urlmatch-normalization -p "x://y/%2E/")" = "x://y/" &&
- test "$(test-tool urlmatch-normalization -p "x://y/a/%2e./")" = "x://y/" &&
- test "$(test-tool urlmatch-normalization -p "x://y/b/.%2E/")" = "x://y/" &&
- test "$(test-tool urlmatch-normalization -p "x://y/c/%2e%2E/")" = "x://y/"
-'
-
-# http://@foo specifies an empty user name but does not specify a password
-# http://foo specifies neither a user name nor a password
-# So they should not be equivalent
-test_expect_success 'url equivalents' '
- test-tool urlmatch-normalization "httP://x" "Http://X/" &&
- test-tool urlmatch-normalization "Http://%4d%65:%4d^%70@The.Host" "hTTP://Me:%4D^p@the.HOST:80/" &&
- ! test-tool urlmatch-normalization "https://@x.y/^" "httpS://x.y:443/^" &&
- test-tool urlmatch-normalization "https://@x.y/^" "httpS://@x.y:0443/^" &&
- test-tool urlmatch-normalization "https://@x.y/^/../abc" "httpS://@x.y:0443/abc" &&
- test-tool urlmatch-normalization "https://@x.y/^/.." "httpS://@x.y:0443/"
-'
-
-test_done
diff --git a/t/t0110/README b/t/t0110/README
deleted file mode 100644
index ad4a50ecd8..0000000000
--- a/t/t0110/README
+++ /dev/null
@@ -1,9 +0,0 @@
-The url data files in this directory contain URLs with characters
-in the range 0x01-0x1f and 0x7f-0xff to test the proper normalization
-of unprintable characters.
-
-A select few characters in the 0x01-0x1f range are skipped to help
-avoid problems running the test itself.
-
-The urls are in test files in this directory rather than being
-embedded in the test script for portability.
diff --git a/t/t0110/url-1 b/t/t0110/url-1
deleted file mode 100644
index 519019c5ce..0000000000
--- a/t/t0110/url-1
+++ /dev/null
@@ -1 +0,0 @@
-x://q/
diff --git a/t/t0110/url-10 b/t/t0110/url-10
deleted file mode 100644
index b9965de6a5..0000000000
--- a/t/t0110/url-10
+++ /dev/null
@@ -1 +0,0 @@
-x://q/ðñòóôõö÷øùúûüýþÿ
diff --git a/t/t0110/url-11 b/t/t0110/url-11
deleted file mode 100644
index f0a50f1009..0000000000
--- a/t/t0110/url-11
+++ /dev/null
@@ -1 +0,0 @@
-x://q/€߿ࠀ�ð€€ð¯¿½
diff --git a/t/t0110/url-2 b/t/t0110/url-2
deleted file mode 100644
index 43334b05b2..0000000000
--- a/t/t0110/url-2
+++ /dev/null
@@ -1 +0,0 @@
-x://q/
diff --git a/t/t0110/url-3 b/t/t0110/url-3
deleted file mode 100644
index 7378c7bec2..0000000000
--- a/t/t0110/url-3
+++ /dev/null
@@ -1 +0,0 @@
-x://q/€‚ƒ„…†‡ˆ‰Š‹ŒŽ
diff --git a/t/t0110/url-4 b/t/t0110/url-4
deleted file mode 100644
index 220b198c97..0000000000
--- a/t/t0110/url-4
+++ /dev/null
@@ -1 +0,0 @@
-x://q/‘’“”•–—˜™š›œžŸ
diff --git a/t/t0110/url-5 b/t/t0110/url-5
deleted file mode 100644
index 1ccd927779..0000000000
--- a/t/t0110/url-5
+++ /dev/null
@@ -1 +0,0 @@
-x://q/ ¡¢£¤¥¦§¨©ª«¬­®¯
diff --git a/t/t0110/url-6 b/t/t0110/url-6
deleted file mode 100644
index e8283aac6d..0000000000
--- a/t/t0110/url-6
+++ /dev/null
@@ -1 +0,0 @@
-x://q/°±²³´µ¶·¸¹º»¼½¾¿
diff --git a/t/t0110/url-7 b/t/t0110/url-7
deleted file mode 100644
index fa7c10b615..0000000000
--- a/t/t0110/url-7
+++ /dev/null
@@ -1 +0,0 @@
-x://q/ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ
diff --git a/t/t0110/url-8 b/t/t0110/url-8
deleted file mode 100644
index 79a0ba836f..0000000000
--- a/t/t0110/url-8
+++ /dev/null
@@ -1 +0,0 @@
-x://q/ÐÑÒÓÔÕÖרÙÚÛÜÝÞß
diff --git a/t/t0110/url-9 b/t/t0110/url-9
deleted file mode 100644
index 8b44bec48b..0000000000
--- a/t/t0110/url-9
+++ /dev/null
@@ -1 +0,0 @@
-x://q/àáâãäåæçèéêëìíîï
diff --git a/t/t1092-sparse-checkout-compatibility.sh b/t/t1092-sparse-checkout-compatibility.sh
index a2c0e1b4dc..6fa7f5e958 100755
--- a/t/t1092-sparse-checkout-compatibility.sh
+++ b/t/t1092-sparse-checkout-compatibility.sh
@@ -803,6 +803,8 @@ test_expect_success 'update-index --remove outside sparse definition' '
test_sparse_match git diff --cached --name-status &&
test_cmp expect sparse-checkout-out &&
+ test_sparse_match git diff-index --cached HEAD &&
+
# Reset the state
test_all_match git reset --hard &&
@@ -812,6 +814,8 @@ test_expect_success 'update-index --remove outside sparse definition' '
test_sparse_match git diff --cached --name-status &&
test_must_be_empty sparse-checkout-out &&
+ test_sparse_match git diff-index --cached HEAD &&
+
# Reset the state
test_all_match git reset --hard &&
@@ -823,7 +827,9 @@ test_expect_success 'update-index --remove outside sparse definition' '
D folder1/a
EOF
test_sparse_match git diff --cached --name-status &&
- test_cmp expect sparse-checkout-out
+ test_cmp expect sparse-checkout-out &&
+
+ test_sparse_match git diff-index --cached HEAD
'
test_expect_success 'update-index with directories' '
@@ -1551,7 +1557,7 @@ test_expect_success 'sparse-index is not expanded: describe' '
ensure_not_expanded describe
'
-test_expect_success 'sparse index is not expanded: diff' '
+test_expect_success 'sparse index is not expanded: diff and diff-index' '
init_repos &&
write_script edit-contents <<-\EOF &&
@@ -1568,6 +1574,7 @@ test_expect_success 'sparse index is not expanded: diff' '
test_all_match git diff --cached &&
ensure_not_expanded diff &&
ensure_not_expanded diff --cached &&
+ ensure_not_expanded diff-index --cached HEAD &&
# Add file outside cone
test_all_match git reset --hard &&
@@ -1582,6 +1589,7 @@ test_expect_success 'sparse index is not expanded: diff' '
test_all_match git diff --cached &&
ensure_not_expanded diff &&
ensure_not_expanded diff --cached &&
+ ensure_not_expanded diff-index --cached HEAD &&
# Merge conflict outside cone
# The sparse checkout will report a warning that is not in the
@@ -1594,7 +1602,8 @@ test_expect_success 'sparse index is not expanded: diff' '
test_all_match git diff &&
test_all_match git diff --cached &&
ensure_not_expanded diff &&
- ensure_not_expanded diff --cached
+ ensure_not_expanded diff --cached &&
+ ensure_not_expanded diff-index --cached HEAD
'
test_expect_success 'sparse index is not expanded: show and rev-parse' '
diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh
index ae34bfad60..bd8bcc381a 100755
--- a/t/t3400-rebase.sh
+++ b/t/t3400-rebase.sh
@@ -235,6 +235,12 @@ test_expect_success 'rebase --merge -q is quiet' '
test_must_be_empty output.out
'
+test_expect_success 'rebase --exec -q is quiet' '
+ git checkout -B quiet topic &&
+ git rebase --exec true -q main >output.out 2>&1 &&
+ test_must_be_empty output.out
+'
+
test_expect_success 'Rebase a commit that sprinkles CRs in' '
(
echo "One" &&
diff --git a/t/t4150-am.sh b/t/t4150-am.sh
index 5e2b6c80ea..232e1394e8 100755
--- a/t/t4150-am.sh
+++ b/t/t4150-am.sh
@@ -5,6 +5,7 @@ test_description='git am running'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup: messages' '
diff --git a/t/t4203-mailmap.sh b/t/t4203-mailmap.sh
index 79e5f42760..2265ff8872 100755
--- a/t/t4203-mailmap.sh
+++ b/t/t4203-mailmap.sh
@@ -72,12 +72,46 @@ test_expect_success 'check-mailmap --stdin arguments: mapping' '
test_cmp expect actual
'
-test_expect_success 'check-mailmap bogus contact' '
- test_must_fail git check-mailmap bogus
+test_expect_success 'check-mailmap simple address: mapping' '
+ test_when_finished "rm .mailmap" &&
+ cat >.mailmap <<-EOF &&
+ New Name <$GIT_AUTHOR_EMAIL>
+ EOF
+ cat .mailmap >expect &&
+ git check-mailmap "$GIT_AUTHOR_EMAIL" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'check-mailmap --stdin simple address: mapping' '
+ test_when_finished "rm .mailmap" &&
+ cat >.mailmap <<-EOF &&
+ New Name <$GIT_AUTHOR_EMAIL>
+ EOF
+ cat >stdin <<-EOF &&
+ $GIT_AUTHOR_EMAIL
+ EOF
+ cat .mailmap >expect &&
+ git check-mailmap --stdin <stdin >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'check-mailmap simple address: no mapping' '
+ cat >expect <<-EOF &&
+ <bugs@company.xx>
+ EOF
+ git check-mailmap "bugs@company.xx" >actual &&
+ test_cmp expect actual
'
-test_expect_success 'check-mailmap bogus contact --stdin' '
- test_must_fail git check-mailmap --stdin bogus </dev/null
+test_expect_success 'check-mailmap --stdin simple address: no mapping' '
+ cat >expect <<-EOF &&
+ <bugs@company.xx>
+ EOF
+ cat >stdin <<-EOF &&
+ bugs@company.xx
+ EOF
+ git check-mailmap --stdin <stdin >actual &&
+ test_cmp expect actual
'
test_expect_success 'No mailmap' '
diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh
index 158b49d4b6..eb63ce011f 100755
--- a/t/t4205-log-pretty-formats.sh
+++ b/t/t4205-log-pretty-formats.sh
@@ -5,6 +5,8 @@
#
test_description='Test pretty formats'
+
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# Tested non-UTF-8 encoding
diff --git a/t/t4301-merge-tree-write-tree.sh b/t/t4301-merge-tree-write-tree.sh
index eea19907b5..37f1cd7364 100755
--- a/t/t4301-merge-tree-write-tree.sh
+++ b/t/t4301-merge-tree-write-tree.sh
@@ -2,6 +2,7 @@
test_description='git merge-tree --write-tree'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# This test is ort-specific
diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh
index 72b8d0ff02..7abba8a4b2 100755
--- a/t/t5000-tar-tree.sh
+++ b/t/t5000-tar-tree.sh
@@ -25,6 +25,7 @@ commit id embedding:
'
TEST_CREATE_REPO_NO_TEMPLATE=1
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
SUBSTFORMAT=%H%n
diff --git a/t/t5003-archive-zip.sh b/t/t5003-archive-zip.sh
index 961c6aac25..01f591c99b 100755
--- a/t/t5003-archive-zip.sh
+++ b/t/t5003-archive-zip.sh
@@ -3,6 +3,7 @@
test_description='git archive --format=zip test'
TEST_CREATE_REPO_NO_TEMPLATE=1
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
SUBSTFORMAT=%H%n
diff --git a/t/t5100-mailinfo.sh b/t/t5100-mailinfo.sh
index c8d0655454..065156c1f3 100755
--- a/t/t5100-mailinfo.sh
+++ b/t/t5100-mailinfo.sh
@@ -5,6 +5,7 @@
test_description='git mailinfo and git mailsplit test'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
DATA="$TEST_DIRECTORY/t5100"
diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh
index 4ad023c846..3b9dae331a 100755
--- a/t/t5300-pack-object.sh
+++ b/t/t5300-pack-object.sh
@@ -635,4 +635,43 @@ test_expect_success 'negative window clamps to 0' '
check_deltas stderr = 0
'
+for hash in sha1 sha256
+do
+ test_expect_success "verify-pack with $hash packfile" '
+ test_when_finished "rm -rf repo" &&
+ git init --object-format=$hash repo &&
+ test_commit -C repo initial &&
+ git -C repo repack -ad &&
+ git -C repo verify-pack "$(pwd)"/repo/.git/objects/pack/*.idx &&
+ if test $hash = sha1
+ then
+ nongit git verify-pack "$(pwd)"/repo/.git/objects/pack/*.idx
+ else
+ # We have no way to identify the hash used by packfiles
+ # or indices, so we always fall back to SHA1.
+ nongit test_must_fail git verify-pack "$(pwd)"/repo/.git/objects/pack/*.idx &&
+ # But with an explicit object format we should succeed.
+ nongit git verify-pack --object-format=$hash "$(pwd)"/repo/.git/objects/pack/*.idx
+ fi
+ '
+
+ test_expect_success "index-pack outside of a $hash repository" '
+ test_when_finished "rm -rf repo" &&
+ git init --object-format=$hash repo &&
+ test_commit -C repo initial &&
+ git -C repo repack -ad &&
+ git -C repo index-pack --verify "$(pwd)"/repo/.git/objects/pack/*.pack &&
+ if test $hash = sha1
+ then
+ nongit git index-pack --verify "$(pwd)"/repo/.git/objects/pack/*.pack
+ else
+ # We have no way to identify the hash used by packfiles
+ # or indices, so we always fall back to SHA1.
+ nongit test_must_fail git index-pack --verify "$(pwd)"/repo/.git/objects/pack/*.pack 2>err &&
+ # But with an explicit object format we should succeed.
+ nongit git index-pack --object-format=$hash --verify "$(pwd)"/repo/.git/objects/pack/*.pack
+ fi
+ '
+done
+
test_done
diff --git a/t/t5319-multi-pack-index.sh b/t/t5319-multi-pack-index.sh
index ce1b58c732..fbbc218d04 100755
--- a/t/t5319-multi-pack-index.sh
+++ b/t/t5319-multi-pack-index.sh
@@ -1,6 +1,8 @@
#!/bin/sh
test_description='multi-pack-indexes'
+
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-chunk.sh
. "$TEST_DIRECTORY"/lib-midx.sh
diff --git a/t/t5400-send-pack.sh b/t/t5400-send-pack.sh
index 3f81f16e13..248c74d8ef 100755
--- a/t/t5400-send-pack.sh
+++ b/t/t5400-send-pack.sh
@@ -9,6 +9,7 @@ test_description='See why rewinding head breaks send-pack
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
cnt=64
diff --git a/t/t5401-update-hooks.sh b/t/t5401-update-hooks.sh
index d8cadeec73..3c1ea6086e 100755
--- a/t/t5401-update-hooks.sh
+++ b/t/t5401-update-hooks.sh
@@ -4,6 +4,8 @@
#
test_description='Test the update hook infrastructure.'
+
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t5408-send-pack-stdin.sh b/t/t5408-send-pack-stdin.sh
index e8737df6f9..c3695a4d4e 100755
--- a/t/t5408-send-pack-stdin.sh
+++ b/t/t5408-send-pack-stdin.sh
@@ -1,6 +1,8 @@
#!/bin/sh
test_description='send-pack --stdin tests'
+
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
create_ref () {
diff --git a/t/t5409-colorize-remote-messages.sh b/t/t5409-colorize-remote-messages.sh
index fa5de4500a..516b22fd96 100755
--- a/t/t5409-colorize-remote-messages.sh
+++ b/t/t5409-colorize-remote-messages.sh
@@ -2,6 +2,7 @@
test_description='remote messages are colorized on the client'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t5501-fetch-push-alternates.sh b/t/t5501-fetch-push-alternates.sh
index 66f19a4ef2..0c8668a1b8 100755
--- a/t/t5501-fetch-push-alternates.sh
+++ b/t/t5501-fetch-push-alternates.sh
@@ -4,6 +4,7 @@ test_description='fetch/push involving alternates'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
count_objects () {
diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index 08424e878e..532035933f 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -2,6 +2,7 @@
test_description='git remote porcelain-ish'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
setup_repository () {
diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh
index 3b3991ab86..0890b9f61c 100755
--- a/t/t5510-fetch.sh
+++ b/t/t5510-fetch.sh
@@ -5,6 +5,7 @@ test_description='Per branch config variables affects "git fetch".
'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-bundle.sh
diff --git a/t/t5519-push-alternates.sh b/t/t5519-push-alternates.sh
index 20ba604dfd..72e97b15fa 100755
--- a/t/t5519-push-alternates.sh
+++ b/t/t5519-push-alternates.sh
@@ -5,6 +5,7 @@ test_description='push to a repository that borrows from elsewhere'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t5536-fetch-conflicts.sh b/t/t5536-fetch-conflicts.sh
index 23bf696170..2dcbe79052 100755
--- a/t/t5536-fetch-conflicts.sh
+++ b/t/t5536-fetch-conflicts.sh
@@ -2,6 +2,7 @@
test_description='fetch handles conflicting refspecs correctly'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
D=$(pwd)
diff --git a/t/t5548-push-porcelain.sh b/t/t5548-push-porcelain.sh
index 6282728eaf..ecb3877aa4 100755
--- a/t/t5548-push-porcelain.sh
+++ b/t/t5548-push-porcelain.sh
@@ -4,6 +4,7 @@
#
test_description='Test git push porcelain output'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# Create commits in <repo> and assign each commit's oid to shell variables
diff --git a/t/t5553-set-upstream.sh b/t/t5553-set-upstream.sh
index 70e3376d31..33e919a17e 100755
--- a/t/t5553-set-upstream.sh
+++ b/t/t5553-set-upstream.sh
@@ -4,6 +4,7 @@ test_description='"git fetch/pull --set-upstream" basic tests.'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
check_config () {
diff --git a/t/t5574-fetch-output.sh b/t/t5574-fetch-output.sh
index 5883839a04..f7707326ea 100755
--- a/t/t5574-fetch-output.sh
+++ b/t/t5574-fetch-output.sh
@@ -5,6 +5,7 @@ test_description='git fetch output format'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'fetch with invalid output format configuration' '
diff --git a/t/t5703-upload-pack-ref-in-want.sh b/t/t5703-upload-pack-ref-in-want.sh
index 191097171b..f75fae52c8 100755
--- a/t/t5703-upload-pack-ref-in-want.sh
+++ b/t/t5703-upload-pack-ref-in-want.sh
@@ -2,6 +2,7 @@
test_description='upload-pack ref-in-want'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
get_actual_refs () {
diff --git a/t/t5812-proto-disable-http.sh b/t/t5812-proto-disable-http.sh
index 769c717e88..f69959c64c 100755
--- a/t/t5812-proto-disable-http.sh
+++ b/t/t5812-proto-disable-http.sh
@@ -1,6 +1,8 @@
#!/bin/sh
test_description='test disabling of git-over-http in clone/fetch'
+
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY/lib-proto-disable.sh"
. "$TEST_DIRECTORY/lib-httpd.sh"
diff --git a/t/t6050-replace.sh b/t/t6050-replace.sh
index c6e9b33e44..d7702fc756 100755
--- a/t/t6050-replace.sh
+++ b/t/t6050-replace.sh
@@ -7,6 +7,7 @@ test_description='Tests replace refs functionality'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY/lib-gpg.sh"
diff --git a/t/t7704-repack-cruft.sh b/t/t7704-repack-cruft.sh
index 959e6e2648..5db9f4e10f 100755
--- a/t/t7704-repack-cruft.sh
+++ b/t/t7704-repack-cruft.sh
@@ -2,6 +2,7 @@
test_description='git repack works correctly'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
objdir=.git/objects
diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh
index c5e862694e..df5336bb7e 100755
--- a/t/t9001-send-email.sh
+++ b/t/t9001-send-email.sh
@@ -2485,6 +2485,128 @@ test_expect_success $PREREQ 'leading and trailing whitespaces are removed' '
test_cmp expected-list actual-list
'
+test_expect_success $PREREQ 'mailmap support with --to' '
+ clean_fake_sendmail &&
+ test_config mailmap.file "mailmap.test" &&
+ cat >mailmap.test <<-EOF &&
+ Some Body <someone@example.com> <someone@example.org>
+ EOF
+ git format-patch --stdout -1 >a.patch &&
+ git send-email \
+ --from="Example <nobody@example.com>" \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ --to=someone@example.org \
+ --mailmap \
+ a.patch \
+ 2>errors >out &&
+ grep "^!someone@example\.com!$" commandline1
+'
+
+test_expect_success $PREREQ 'sendemail.mailmap configuration' '
+ clean_fake_sendmail &&
+ test_config mailmap.file "mailmap.test" &&
+ test_config sendemail.mailmap "true" &&
+ cat >mailmap.test <<-EOF &&
+ Some Body <someone@example.com> <someone@example.org>
+ EOF
+ git format-patch --stdout -1 >a.patch &&
+ git send-email \
+ --from="Example <nobody@example.com>" \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ --to=someone@example.org \
+ a.patch \
+ 2>errors >out &&
+ grep "^!someone@example\.com!$" commandline1
+'
+
+test_expect_success $PREREQ 'sendemail.mailmap.file configuration' '
+ clean_fake_sendmail &&
+ test_config sendemail.mailmap.file "mailmap.test" &&
+ test_config sendemail.mailmap "true" &&
+ cat >mailmap.test <<-EOF &&
+ Some Body <someone@example.com> <someone@example.org>
+ EOF
+ git format-patch --stdout -1 >a.patch &&
+ git send-email \
+ --from="Example <nobody@example.com>" \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ --to=someone@example.org \
+ a.patch \
+ 2>errors >out &&
+ grep "^!someone@example\.com!$" commandline1
+'
+
+test_expect_success $PREREQ 'sendemail.mailmap identity overrides configuration' '
+ clean_fake_sendmail &&
+ test_config sendemail.cloud.mailmap.file "mailmap.test" &&
+ test_config sendemail.mailmap "false" &&
+ test_config sendemail.cloud.mailmap "true" &&
+ cat >mailmap.test <<-EOF &&
+ Some Body <someone@example.com> <someone@example.org>
+ EOF
+ git format-patch --stdout -1 >a.patch &&
+ git send-email \
+ --from="Example <nobody@example.com>" \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ --identity=cloud \
+ --to=someone@example.org \
+ a.patch \
+ 2>errors >out &&
+ grep "^!someone@example\.com!$" commandline1
+'
+
+test_expect_success $PREREQ '--no-mailmap overrides configuration' '
+ clean_fake_sendmail &&
+ test_config sendemail.cloud.mailmap.file "mailmap.test" &&
+ test_config sendemail.mailmap "false" &&
+ test_config sendemail.cloud.mailmap "true" &&
+ cat >mailmap.test <<-EOF &&
+ Some Body <someone@example.com> <someone@example.org>
+ EOF
+ git format-patch --stdout -1 >a.patch &&
+ git send-email \
+ --from="Example <nobody@example.com>" \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ --identity=cloud \
+ --to=someone@example.org \
+ --no-mailmap \
+ a.patch \
+ 2>errors >out &&
+ grep "^!someone@example\.org!$" commandline1
+'
+
+test_expect_success $PREREQ 'mailmap support in To header' '
+ clean_fake_sendmail &&
+ test_config mailmap.file "mailmap.test" &&
+ cat >mailmap.test <<-EOF &&
+ <someone@example.com> <someone@example.org>
+ EOF
+ git format-patch --stdout -1 --to=someone@example.org >a.patch &&
+ git send-email \
+ --from="Example <nobody@example.com>" \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ --mailmap \
+ a.patch \
+ 2>errors >out &&
+ grep "^!someone@example\.com!$" commandline1
+'
+
+test_expect_success $PREREQ 'mailmap support in Cc header' '
+ clean_fake_sendmail &&
+ test_config mailmap.file "mailmap.test" &&
+ cat >mailmap.test <<-EOF &&
+ <someone@example.com> <someone@example.org>
+ EOF
+ git format-patch --stdout -1 --cc=someone@example.org >a.patch &&
+ git send-email \
+ --from="Example <nobody@example.com>" \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ --mailmap \
+ a.patch \
+ 2>errors >out &&
+ grep "^!someone@example\.com!$" commandline1
+'
+
test_expect_success $PREREQ 'test using command name with --sendmail-cmd' '
clean_fake_sendmail &&
PATH="$PWD:$PATH" \
diff --git a/t/unit-tests/lib-oid.c b/t/unit-tests/lib-oid.c
index 37105f0a8f..8f0ccac532 100644
--- a/t/unit-tests/lib-oid.c
+++ b/t/unit-tests/lib-oid.c
@@ -3,7 +3,7 @@
#include "strbuf.h"
#include "hex.h"
-static int init_hash_algo(void)
+int init_hash_algo(void)
{
static int algo = -1;
diff --git a/t/unit-tests/lib-oid.h b/t/unit-tests/lib-oid.h
index 8d2acca768..4e77c04bd2 100644
--- a/t/unit-tests/lib-oid.h
+++ b/t/unit-tests/lib-oid.h
@@ -13,5 +13,13 @@
* environment variable.
*/
int get_oid_arbitrary_hex(const char *s, struct object_id *oid);
+/*
+ * Returns one of GIT_HASH_{SHA1, SHA256, UNKNOWN} based on the value of
+ * GIT_TEST_DEFAULT_HASH environment variable. The fallback value in the
+ * absence of GIT_TEST_DEFAULT_HASH is GIT_HASH_SHA1. It also uses
+ * check(algo != GIT_HASH_UNKNOWN) before returning to verify if the
+ * GIT_TEST_DEFAULT_HASH's value is valid or not.
+ */
+int init_hash_algo(void);
#endif /* LIB_OID_H */
diff --git a/t/unit-tests/t-oid-array.c b/t/unit-tests/t-oid-array.c
new file mode 100644
index 0000000000..45b59a2a51
--- /dev/null
+++ b/t/unit-tests/t-oid-array.c
@@ -0,0 +1,126 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "test-lib.h"
+#include "lib-oid.h"
+#include "oid-array.h"
+#include "hex.h"
+
+static int fill_array(struct oid_array *array, const char *hexes[], size_t n)
+{
+ for (size_t i = 0; i < n; i++) {
+ struct object_id oid;
+
+ if (!check_int(get_oid_arbitrary_hex(hexes[i], &oid), ==, 0))
+ return -1;
+ oid_array_append(array, &oid);
+ }
+ if (!check_uint(array->nr, ==, n))
+ return -1;
+ return 0;
+}
+
+static int add_to_oid_array(const struct object_id *oid, void *data)
+{
+ struct oid_array *array = data;
+
+ oid_array_append(array, oid);
+ return 0;
+}
+
+static void t_enumeration(const char **input_args, size_t input_sz,
+ const char **expect_args, size_t expect_sz)
+{
+ struct oid_array input = OID_ARRAY_INIT, expect = OID_ARRAY_INIT,
+ actual = OID_ARRAY_INIT;
+ size_t i;
+
+ if (fill_array(&input, input_args, input_sz))
+ return;
+ if (fill_array(&expect, expect_args, expect_sz))
+ return;
+
+ oid_array_for_each_unique(&input, add_to_oid_array, &actual);
+ if (!check_uint(actual.nr, ==, expect.nr))
+ return;
+
+ for (i = 0; i < actual.nr; i++) {
+ if (!check(oideq(&actual.oid[i], &expect.oid[i])))
+ test_msg("expected: %s\n got: %s\n index: %" PRIuMAX,
+ oid_to_hex(&expect.oid[i]), oid_to_hex(&actual.oid[i]),
+ (uintmax_t)i);
+ }
+
+ oid_array_clear(&actual);
+ oid_array_clear(&input);
+ oid_array_clear(&expect);
+}
+
+#define TEST_ENUMERATION(input, expect, desc) \
+ TEST(t_enumeration(input, ARRAY_SIZE(input), expect, ARRAY_SIZE(expect)), \
+ desc " works")
+
+static void t_lookup(const char **input_hexes, size_t n, const char *query_hex,
+ int lower_bound, int upper_bound)
+{
+ struct oid_array array = OID_ARRAY_INIT;
+ struct object_id oid_query;
+ int ret;
+
+ if (!check_int(get_oid_arbitrary_hex(query_hex, &oid_query), ==, 0))
+ return;
+ if (fill_array(&array, input_hexes, n))
+ return;
+ ret = oid_array_lookup(&array, &oid_query);
+
+ if (!check_int(ret, <=, upper_bound) ||
+ !check_int(ret, >=, lower_bound))
+ test_msg("oid query for lookup: %s", oid_to_hex(&oid_query));
+
+ oid_array_clear(&array);
+}
+
+#define TEST_LOOKUP(input_hexes, query, lower_bound, upper_bound, desc) \
+ TEST(t_lookup(input_hexes, ARRAY_SIZE(input_hexes), query, \
+ lower_bound, upper_bound), \
+ desc " works")
+
+static void setup(void)
+{
+ /* The hash algo is used by oid_array_lookup() internally */
+ int algo = init_hash_algo();
+ if (check_int(algo, !=, GIT_HASH_UNKNOWN))
+ repo_set_hash_algo(the_repository, algo);
+}
+
+int cmd_main(int argc UNUSED, const char **argv UNUSED)
+{
+ const char *arr_input[] = { "88", "44", "aa", "55" };
+ const char *arr_input_dup[] = { "88", "44", "aa", "55",
+ "88", "44", "aa", "55",
+ "88", "44", "aa", "55" };
+ const char *res_sorted[] = { "44", "55", "88", "aa" };
+ const char *nearly_55;
+
+ if (!TEST(setup(), "setup"))
+ test_skip_all("hash algo initialization failed");
+
+ TEST_ENUMERATION(arr_input, res_sorted, "ordered enumeration");
+ TEST_ENUMERATION(arr_input_dup, res_sorted,
+ "ordered enumeration with duplicate suppression");
+
+ TEST_LOOKUP(arr_input, "55", 1, 1, "lookup");
+ TEST_LOOKUP(arr_input, "33", INT_MIN, -1, "lookup non-existent entry");
+ TEST_LOOKUP(arr_input_dup, "55", 3, 5, "lookup with duplicates");
+ TEST_LOOKUP(arr_input_dup, "66", INT_MIN, -1,
+ "lookup non-existent entry with duplicates");
+
+ nearly_55 = init_hash_algo() == GIT_HASH_SHA1 ?
+ "5500000000000000000000000000000000000001" :
+ "5500000000000000000000000000000000000000000000000000000000000001";
+ TEST_LOOKUP(((const char *[]){ "55", nearly_55 }), "55", 0, 0,
+ "lookup with almost duplicate values");
+ TEST_LOOKUP(((const char *[]){ "55", "55" }), "55", 0, 1,
+ "lookup with single duplicate value");
+
+ return test_done();
+}
diff --git a/t/unit-tests/t-reftable-block.c b/t/unit-tests/t-reftable-block.c
new file mode 100644
index 0000000000..f1a49485e2
--- /dev/null
+++ b/t/unit-tests/t-reftable-block.c
@@ -0,0 +1,371 @@
+/*
+Copyright 2020 Google LLC
+
+Use of this source code is governed by a BSD-style
+license that can be found in the LICENSE file or at
+https://developers.google.com/open-source/licenses/bsd
+*/
+
+#include "test-lib.h"
+#include "reftable/block.h"
+#include "reftable/blocksource.h"
+#include "reftable/constants.h"
+#include "reftable/reftable-error.h"
+
+static void t_ref_block_read_write(void)
+{
+ const int header_off = 21; /* random */
+ struct reftable_record recs[30];
+ const size_t N = ARRAY_SIZE(recs);
+ const size_t block_size = 1024;
+ struct reftable_block block = { 0 };
+ struct block_writer bw = {
+ .last_key = STRBUF_INIT,
+ };
+ struct reftable_record rec = {
+ .type = BLOCK_TYPE_REF,
+ };
+ size_t i = 0;
+ int ret;
+ struct block_reader br = { 0 };
+ struct block_iter it = BLOCK_ITER_INIT;
+ struct strbuf want = STRBUF_INIT, buf = STRBUF_INIT;
+
+ REFTABLE_CALLOC_ARRAY(block.data, block_size);
+ block.len = block_size;
+ block_source_from_strbuf(&block.source ,&buf);
+ block_writer_init(&bw, BLOCK_TYPE_REF, block.data, block_size,
+ header_off, hash_size(GIT_SHA1_FORMAT_ID));
+
+ rec.u.ref.refname = (char *) "";
+ rec.u.ref.value_type = REFTABLE_REF_DELETION;
+ ret = block_writer_add(&bw, &rec);
+ check_int(ret, ==, REFTABLE_API_ERROR);
+
+ for (i = 0; i < N; i++) {
+ rec.u.ref.refname = xstrfmt("branch%02"PRIuMAX, (uintmax_t)i);
+ rec.u.ref.value_type = REFTABLE_REF_VAL1;
+ memset(rec.u.ref.value.val1, i, GIT_SHA1_RAWSZ);
+
+ recs[i] = rec;
+ ret = block_writer_add(&bw, &rec);
+ rec.u.ref.refname = NULL;
+ rec.u.ref.value_type = REFTABLE_REF_DELETION;
+ check_int(ret, ==, 0);
+ }
+
+ ret = block_writer_finish(&bw);
+ check_int(ret, >, 0);
+
+ block_writer_release(&bw);
+
+ block_reader_init(&br, &block, header_off, block_size, GIT_SHA1_RAWSZ);
+
+ block_iter_seek_start(&it, &br);
+
+ for (i = 0; ; i++) {
+ ret = block_iter_next(&it, &rec);
+ check_int(ret, >=, 0);
+ if (ret > 0) {
+ check_int(i, ==, N);
+ break;
+ }
+ check(reftable_record_equal(&recs[i], &rec, GIT_SHA1_RAWSZ));
+ }
+
+ for (i = 0; i < N; i++) {
+ block_iter_reset(&it);
+ reftable_record_key(&recs[i], &want);
+
+ ret = block_iter_seek_key(&it, &br, &want);
+ check_int(ret, ==, 0);
+
+ ret = block_iter_next(&it, &rec);
+ check_int(ret, ==, 0);
+
+ check(reftable_record_equal(&recs[i], &rec, GIT_SHA1_RAWSZ));
+
+ want.len--;
+ ret = block_iter_seek_key(&it, &br, &want);
+ check_int(ret, ==, 0);
+
+ ret = block_iter_next(&it, &rec);
+ check_int(ret, ==, 0);
+ check(reftable_record_equal(&recs[10 * (i / 10)], &rec, GIT_SHA1_RAWSZ));
+ }
+
+ block_reader_release(&br);
+ block_iter_close(&it);
+ reftable_record_release(&rec);
+ reftable_block_done(&br.block);
+ strbuf_release(&want);
+ strbuf_release(&buf);
+ for (i = 0; i < N; i++)
+ reftable_record_release(&recs[i]);
+}
+
+static void t_log_block_read_write(void)
+{
+ const int header_off = 21;
+ struct reftable_record recs[30];
+ const size_t N = ARRAY_SIZE(recs);
+ const size_t block_size = 2048;
+ struct reftable_block block = { 0 };
+ struct block_writer bw = {
+ .last_key = STRBUF_INIT,
+ };
+ struct reftable_record rec = {
+ .type = BLOCK_TYPE_LOG,
+ };
+ size_t i = 0;
+ int ret;
+ struct block_reader br = { 0 };
+ struct block_iter it = BLOCK_ITER_INIT;
+ struct strbuf want = STRBUF_INIT, buf = STRBUF_INIT;
+
+ REFTABLE_CALLOC_ARRAY(block.data, block_size);
+ block.len = block_size;
+ block_source_from_strbuf(&block.source ,&buf);
+ block_writer_init(&bw, BLOCK_TYPE_LOG, block.data, block_size,
+ header_off, hash_size(GIT_SHA1_FORMAT_ID));
+
+ for (i = 0; i < N; i++) {
+ rec.u.log.refname = xstrfmt("branch%02"PRIuMAX , (uintmax_t)i);
+ rec.u.log.update_index = i;
+ rec.u.log.value_type = REFTABLE_LOG_UPDATE;
+
+ recs[i] = rec;
+ ret = block_writer_add(&bw, &rec);
+ rec.u.log.refname = NULL;
+ rec.u.log.value_type = REFTABLE_LOG_DELETION;
+ check_int(ret, ==, 0);
+ }
+
+ ret = block_writer_finish(&bw);
+ check_int(ret, >, 0);
+
+ block_writer_release(&bw);
+
+ block_reader_init(&br, &block, header_off, block_size, GIT_SHA1_RAWSZ);
+
+ block_iter_seek_start(&it, &br);
+
+ for (i = 0; ; i++) {
+ ret = block_iter_next(&it, &rec);
+ check_int(ret, >=, 0);
+ if (ret > 0) {
+ check_int(i, ==, N);
+ break;
+ }
+ check(reftable_record_equal(&recs[i], &rec, GIT_SHA1_RAWSZ));
+ }
+
+ for (i = 0; i < N; i++) {
+ block_iter_reset(&it);
+ strbuf_reset(&want);
+ strbuf_addstr(&want, recs[i].u.log.refname);
+
+ ret = block_iter_seek_key(&it, &br, &want);
+ check_int(ret, ==, 0);
+
+ ret = block_iter_next(&it, &rec);
+ check_int(ret, ==, 0);
+
+ check(reftable_record_equal(&recs[i], &rec, GIT_SHA1_RAWSZ));
+
+ want.len--;
+ ret = block_iter_seek_key(&it, &br, &want);
+ check_int(ret, ==, 0);
+
+ ret = block_iter_next(&it, &rec);
+ check_int(ret, ==, 0);
+ check(reftable_record_equal(&recs[10 * (i / 10)], &rec, GIT_SHA1_RAWSZ));
+ }
+
+ block_reader_release(&br);
+ block_iter_close(&it);
+ reftable_record_release(&rec);
+ reftable_block_done(&br.block);
+ strbuf_release(&want);
+ strbuf_release(&buf);
+ for (i = 0; i < N; i++)
+ reftable_record_release(&recs[i]);
+}
+
+static void t_obj_block_read_write(void)
+{
+ const int header_off = 21;
+ struct reftable_record recs[30];
+ const size_t N = ARRAY_SIZE(recs);
+ const size_t block_size = 1024;
+ struct reftable_block block = { 0 };
+ struct block_writer bw = {
+ .last_key = STRBUF_INIT,
+ };
+ struct reftable_record rec = {
+ .type = BLOCK_TYPE_OBJ,
+ };
+ size_t i = 0;
+ int ret;
+ struct block_reader br = { 0 };
+ struct block_iter it = BLOCK_ITER_INIT;
+ struct strbuf want = STRBUF_INIT, buf = STRBUF_INIT;
+
+ REFTABLE_CALLOC_ARRAY(block.data, block_size);
+ block.len = block_size;
+ block_source_from_strbuf(&block.source, &buf);
+ block_writer_init(&bw, BLOCK_TYPE_OBJ, block.data, block_size,
+ header_off, hash_size(GIT_SHA1_FORMAT_ID));
+
+ for (i = 0; i < N; i++) {
+ uint8_t bytes[] = { i, i + 1, i + 2, i + 3, i + 5 }, *allocated;
+ DUP_ARRAY(allocated, bytes, ARRAY_SIZE(bytes));
+
+ rec.u.obj.hash_prefix = allocated;
+ rec.u.obj.hash_prefix_len = 5;
+
+ recs[i] = rec;
+ ret = block_writer_add(&bw, &rec);
+ rec.u.obj.hash_prefix = NULL;
+ rec.u.obj.hash_prefix_len = 0;
+ check_int(ret, ==, 0);
+ }
+
+ ret = block_writer_finish(&bw);
+ check_int(ret, >, 0);
+
+ block_writer_release(&bw);
+
+ block_reader_init(&br, &block, header_off, block_size, GIT_SHA1_RAWSZ);
+
+ block_iter_seek_start(&it, &br);
+
+ for (i = 0; ; i++) {
+ ret = block_iter_next(&it, &rec);
+ check_int(ret, >=, 0);
+ if (ret > 0) {
+ check_int(i, ==, N);
+ break;
+ }
+ check(reftable_record_equal(&recs[i], &rec, GIT_SHA1_RAWSZ));
+ }
+
+ for (i = 0; i < N; i++) {
+ block_iter_reset(&it);
+ reftable_record_key(&recs[i], &want);
+
+ ret = block_iter_seek_key(&it, &br, &want);
+ check_int(ret, ==, 0);
+
+ ret = block_iter_next(&it, &rec);
+ check_int(ret, ==, 0);
+
+ check(reftable_record_equal(&recs[i], &rec, GIT_SHA1_RAWSZ));
+ }
+
+ block_reader_release(&br);
+ block_iter_close(&it);
+ reftable_record_release(&rec);
+ reftable_block_done(&br.block);
+ strbuf_release(&want);
+ strbuf_release(&buf);
+ for (i = 0; i < N; i++)
+ reftable_record_release(&recs[i]);
+}
+
+static void t_index_block_read_write(void)
+{
+ const int header_off = 21;
+ struct reftable_record recs[30];
+ const size_t N = ARRAY_SIZE(recs);
+ const size_t block_size = 1024;
+ struct reftable_block block = { 0 };
+ struct block_writer bw = {
+ .last_key = STRBUF_INIT,
+ };
+ struct reftable_record rec = {
+ .type = BLOCK_TYPE_INDEX,
+ .u.idx.last_key = STRBUF_INIT,
+ };
+ size_t i = 0;
+ int ret;
+ struct block_reader br = { 0 };
+ struct block_iter it = BLOCK_ITER_INIT;
+ struct strbuf want = STRBUF_INIT, buf = STRBUF_INIT;
+
+ REFTABLE_CALLOC_ARRAY(block.data, block_size);
+ block.len = block_size;
+ block_source_from_strbuf(&block.source, &buf);
+ block_writer_init(&bw, BLOCK_TYPE_INDEX, block.data, block_size,
+ header_off, hash_size(GIT_SHA1_FORMAT_ID));
+
+ for (i = 0; i < N; i++) {
+ strbuf_init(&recs[i].u.idx.last_key, 9);
+
+ recs[i].type = BLOCK_TYPE_INDEX;
+ strbuf_addf(&recs[i].u.idx.last_key, "branch%02"PRIuMAX, (uintmax_t)i);
+ recs[i].u.idx.offset = i;
+
+ ret = block_writer_add(&bw, &recs[i]);
+ check_int(ret, ==, 0);
+ }
+
+ ret = block_writer_finish(&bw);
+ check_int(ret, >, 0);
+
+ block_writer_release(&bw);
+
+ block_reader_init(&br, &block, header_off, block_size, GIT_SHA1_RAWSZ);
+
+ block_iter_seek_start(&it, &br);
+
+ for (i = 0; ; i++) {
+ ret = block_iter_next(&it, &rec);
+ check_int(ret, >=, 0);
+ if (ret > 0) {
+ check_int(i, ==, N);
+ break;
+ }
+ check(reftable_record_equal(&recs[i], &rec, GIT_SHA1_RAWSZ));
+ }
+
+ for (i = 0; i < N; i++) {
+ block_iter_reset(&it);
+ reftable_record_key(&recs[i], &want);
+
+ ret = block_iter_seek_key(&it, &br, &want);
+ check_int(ret, ==, 0);
+
+ ret = block_iter_next(&it, &rec);
+ check_int(ret, ==, 0);
+
+ check(reftable_record_equal(&recs[i], &rec, GIT_SHA1_RAWSZ));
+
+ want.len--;
+ ret = block_iter_seek_key(&it, &br, &want);
+ check_int(ret, ==, 0);
+
+ ret = block_iter_next(&it, &rec);
+ check_int(ret, ==, 0);
+ check(reftable_record_equal(&recs[10 * (i / 10)], &rec, GIT_SHA1_RAWSZ));
+ }
+
+ block_reader_release(&br);
+ block_iter_close(&it);
+ reftable_record_release(&rec);
+ reftable_block_done(&br.block);
+ strbuf_release(&want);
+ strbuf_release(&buf);
+ for (i = 0; i < N; i++)
+ reftable_record_release(&recs[i]);
+}
+
+int cmd_main(int argc UNUSED, const char *argv[] UNUSED)
+{
+ TEST(t_index_block_read_write(), "read-write operations on index blocks work");
+ TEST(t_log_block_read_write(), "read-write operations on log blocks work");
+ TEST(t_obj_block_read_write(), "read-write operations on obj blocks work");
+ TEST(t_ref_block_read_write(), "read-write operations on ref blocks work");
+
+ return test_done();
+}
diff --git a/t/unit-tests/t-reftable-merged.c b/t/unit-tests/t-reftable-merged.c
index 99f8fcadfe..e9d100a01e 100644
--- a/t/unit-tests/t-reftable-merged.c
+++ b/t/unit-tests/t-reftable-merged.c
@@ -12,7 +12,6 @@ https://developers.google.com/open-source/licenses/bsd
#include "reftable/merged.h"
#include "reftable/reader.h"
#include "reftable/reftable-error.h"
-#include "reftable/reftable-generic.h"
#include "reftable/reftable-merged.h"
#include "reftable/reftable-writer.h"
@@ -94,10 +93,8 @@ merged_table_from_records(struct reftable_ref_record **refs,
struct strbuf *buf, const size_t n)
{
struct reftable_merged_table *mt = NULL;
- struct reftable_table *tabs;
int err;
- REFTABLE_CALLOC_ARRAY(tabs, n);
REFTABLE_CALLOC_ARRAY(*readers, n);
REFTABLE_CALLOC_ARRAY(*source, n);
@@ -105,13 +102,12 @@ merged_table_from_records(struct reftable_ref_record **refs,
write_test_table(&buf[i], refs[i], sizes[i]);
block_source_from_strbuf(&(*source)[i], &buf[i]);
- err = reftable_new_reader(&(*readers)[i], &(*source)[i],
+ err = reftable_reader_new(&(*readers)[i], &(*source)[i],
"name");
check(!err);
- reftable_table_from_reader(&tabs[i], (*readers)[i]);
}
- err = reftable_new_merged_table(&mt, tabs, n, GIT_SHA1_FORMAT_ID);
+ err = reftable_merged_table_new(&mt, *readers, n, GIT_SHA1_FORMAT_ID);
check(!err);
return mt;
}
@@ -119,7 +115,7 @@ merged_table_from_records(struct reftable_ref_record **refs,
static void readers_destroy(struct reftable_reader **readers, const size_t n)
{
for (size_t i = 0; i < n; i++)
- reftable_reader_free(readers[i]);
+ reftable_reader_decref(readers[i]);
reftable_free(readers);
}
@@ -272,10 +268,8 @@ merged_table_from_log_records(struct reftable_log_record **logs,
struct strbuf *buf, const size_t n)
{
struct reftable_merged_table *mt = NULL;
- struct reftable_table *tabs;
int err;
- REFTABLE_CALLOC_ARRAY(tabs, n);
REFTABLE_CALLOC_ARRAY(*readers, n);
REFTABLE_CALLOC_ARRAY(*source, n);
@@ -283,13 +277,12 @@ merged_table_from_log_records(struct reftable_log_record **logs,
write_test_log_table(&buf[i], logs[i], sizes[i], i + 1);
block_source_from_strbuf(&(*source)[i], &buf[i]);
- err = reftable_new_reader(&(*readers)[i], &(*source)[i],
+ err = reftable_reader_new(&(*readers)[i], &(*source)[i],
"name");
check(!err);
- reftable_table_from_reader(&tabs[i], (*readers)[i]);
}
- err = reftable_new_merged_table(&mt, tabs, n, GIT_SHA1_FORMAT_ID);
+ err = reftable_merged_table_new(&mt, *readers, n, GIT_SHA1_FORMAT_ID);
check(!err);
return mt;
}
@@ -418,7 +411,6 @@ static void t_default_write_opts(void)
};
int err;
struct reftable_block_source source = { 0 };
- struct reftable_table *tab = reftable_calloc(1, sizeof(*tab));
uint32_t hash_id;
struct reftable_reader *rd = NULL;
struct reftable_merged_table *merged = NULL;
@@ -434,19 +426,18 @@ static void t_default_write_opts(void)
block_source_from_strbuf(&source, &buf);
- err = reftable_new_reader(&rd, &source, "filename");
+ err = reftable_reader_new(&rd, &source, "filename");
check(!err);
hash_id = reftable_reader_hash_id(rd);
check_int(hash_id, ==, GIT_SHA1_FORMAT_ID);
- reftable_table_from_reader(&tab[0], rd);
- err = reftable_new_merged_table(&merged, tab, 1, GIT_SHA256_FORMAT_ID);
+ err = reftable_merged_table_new(&merged, &rd, 1, GIT_SHA256_FORMAT_ID);
check_int(err, ==, REFTABLE_FORMAT_ERROR);
- err = reftable_new_merged_table(&merged, tab, 1, GIT_SHA1_FORMAT_ID);
+ err = reftable_merged_table_new(&merged, &rd, 1, GIT_SHA1_FORMAT_ID);
check(!err);
- reftable_reader_free(rd);
+ reftable_reader_decref(rd);
reftable_merged_table_free(merged);
strbuf_release(&buf);
}
diff --git a/t/unit-tests/t-reftable-readwrite.c b/t/unit-tests/t-reftable-readwrite.c
index 1eae36cc60..82bfaf3287 100644
--- a/t/unit-tests/t-reftable-readwrite.c
+++ b/t/unit-tests/t-reftable-readwrite.c
@@ -26,7 +26,7 @@ static ssize_t strbuf_add_void(void *b, const void *data, size_t sz)
return sz;
}
-static int noop_flush(void *arg)
+static int noop_flush(void *arg UNUSED)
{
return 0;
}
@@ -205,7 +205,7 @@ static void t_log_write_read(void)
struct reftable_log_record log = { 0 };
int n;
struct reftable_iterator it = { 0 };
- struct reftable_reader rd = { 0 };
+ struct reftable_reader *reader;
struct reftable_block_source source = { 0 };
struct strbuf buf = STRBUF_INIT;
struct reftable_writer *w =
@@ -246,10 +246,10 @@ static void t_log_write_read(void)
block_source_from_strbuf(&source, &buf);
- err = init_reader(&rd, &source, "file.log");
+ err = reftable_reader_new(&reader, &source, "file.log");
check(!err);
- reftable_reader_init_ref_iterator(&rd, &it);
+ reftable_reader_init_ref_iterator(reader, &it);
err = reftable_iterator_seek_ref(&it, names[N - 1]);
check(!err);
@@ -264,7 +264,7 @@ static void t_log_write_read(void)
reftable_iterator_destroy(&it);
reftable_ref_record_release(&ref);
- reftable_reader_init_log_iterator(&rd, &it);
+ reftable_reader_init_log_iterator(reader, &it);
err = reftable_iterator_seek_log(&it, "");
check(!err);
@@ -285,7 +285,7 @@ static void t_log_write_read(void)
/* cleanup. */
strbuf_release(&buf);
free_names(names);
- reader_close(&rd);
+ reftable_reader_decref(reader);
}
static void t_log_zlib_corruption(void)
@@ -294,7 +294,7 @@ static void t_log_zlib_corruption(void)
.block_size = 256,
};
struct reftable_iterator it = { 0 };
- struct reftable_reader rd = { 0 };
+ struct reftable_reader *reader;
struct reftable_block_source source = { 0 };
struct strbuf buf = STRBUF_INIT;
struct reftable_writer *w =
@@ -337,18 +337,18 @@ static void t_log_zlib_corruption(void)
block_source_from_strbuf(&source, &buf);
- err = init_reader(&rd, &source, "file.log");
+ err = reftable_reader_new(&reader, &source, "file.log");
check(!err);
- reftable_reader_init_log_iterator(&rd, &it);
+ reftable_reader_init_log_iterator(reader, &it);
err = reftable_iterator_seek_log(&it, "refname");
check_int(err, ==, REFTABLE_ZLIB_ERROR);
reftable_iterator_destroy(&it);
/* cleanup. */
+ reftable_reader_decref(reader);
strbuf_release(&buf);
- reader_close(&rd);
}
static void t_table_read_write_sequential(void)
@@ -358,7 +358,7 @@ static void t_table_read_write_sequential(void)
int N = 50;
struct reftable_iterator it = { 0 };
struct reftable_block_source source = { 0 };
- struct reftable_reader rd = { 0 };
+ struct reftable_reader *reader;
int err = 0;
int j = 0;
@@ -366,10 +366,10 @@ static void t_table_read_write_sequential(void)
block_source_from_strbuf(&source, &buf);
- err = init_reader(&rd, &source, "file.ref");
+ err = reftable_reader_new(&reader, &source, "file.ref");
check(!err);
- reftable_reader_init_ref_iterator(&rd, &it);
+ reftable_reader_init_ref_iterator(reader, &it);
err = reftable_iterator_seek_ref(&it, "");
check(!err);
@@ -384,11 +384,11 @@ static void t_table_read_write_sequential(void)
reftable_ref_record_release(&ref);
}
check_int(j, ==, N);
+
reftable_iterator_destroy(&it);
+ reftable_reader_decref(reader);
strbuf_release(&buf);
free_names(names);
-
- reader_close(&rd);
}
static void t_table_write_small_table(void)
@@ -407,7 +407,7 @@ static void t_table_read_api(void)
char **names;
struct strbuf buf = STRBUF_INIT;
int N = 50;
- struct reftable_reader rd = { 0 };
+ struct reftable_reader *reader;
struct reftable_block_source source = { 0 };
int err;
struct reftable_log_record log = { 0 };
@@ -417,10 +417,10 @@ static void t_table_read_api(void)
block_source_from_strbuf(&source, &buf);
- err = init_reader(&rd, &source, "file.ref");
+ err = reftable_reader_new(&reader, &source, "file.ref");
check(!err);
- reftable_reader_init_ref_iterator(&rd, &it);
+ reftable_reader_init_ref_iterator(reader, &it);
err = reftable_iterator_seek_ref(&it, names[0]);
check(!err);
@@ -430,7 +430,7 @@ static void t_table_read_api(void)
strbuf_release(&buf);
free_names(names);
reftable_iterator_destroy(&it);
- reader_close(&rd);
+ reftable_reader_decref(reader);
strbuf_release(&buf);
}
@@ -439,7 +439,7 @@ static void t_table_read_write_seek(int index, int hash_id)
char **names;
struct strbuf buf = STRBUF_INIT;
int N = 50;
- struct reftable_reader rd = { 0 };
+ struct reftable_reader *reader;
struct reftable_block_source source = { 0 };
int err;
int i = 0;
@@ -452,17 +452,18 @@ static void t_table_read_write_seek(int index, int hash_id)
block_source_from_strbuf(&source, &buf);
- err = init_reader(&rd, &source, "file.ref");
+ err = reftable_reader_new(&reader, &source, "file.ref");
check(!err);
- check_int(hash_id, ==, reftable_reader_hash_id(&rd));
+ check_int(hash_id, ==, reftable_reader_hash_id(reader));
- if (!index)
- rd.ref_offsets.index_offset = 0;
- else
- check_int(rd.ref_offsets.index_offset, >, 0);
+ if (!index) {
+ reader->ref_offsets.index_offset = 0;
+ } else {
+ check_int(reader->ref_offsets.index_offset, >, 0);
+ }
for (i = 1; i < N; i++) {
- reftable_reader_init_ref_iterator(&rd, &it);
+ reftable_reader_init_ref_iterator(reader, &it);
err = reftable_iterator_seek_ref(&it, names[i]);
check(!err);
err = reftable_iterator_next_ref(&it, &ref);
@@ -478,7 +479,7 @@ static void t_table_read_write_seek(int index, int hash_id)
strbuf_addstr(&pastLast, names[N - 1]);
strbuf_addstr(&pastLast, "/");
- reftable_reader_init_ref_iterator(&rd, &it);
+ reftable_reader_init_ref_iterator(reader, &it);
err = reftable_iterator_seek_ref(&it, pastLast.buf);
if (err == 0) {
struct reftable_ref_record ref = { 0 };
@@ -493,7 +494,7 @@ static void t_table_read_write_seek(int index, int hash_id)
strbuf_release(&buf);
free_names(names);
- reader_close(&rd);
+ reftable_reader_decref(reader);
}
static void t_table_read_write_seek_linear(void)
@@ -525,7 +526,7 @@ static void t_table_refs_for(int indexed)
int i = 0;
int n;
int err;
- struct reftable_reader rd;
+ struct reftable_reader *reader;
struct reftable_block_source source = { 0 };
struct strbuf buf = STRBUF_INIT;
@@ -573,17 +574,17 @@ static void t_table_refs_for(int indexed)
block_source_from_strbuf(&source, &buf);
- err = init_reader(&rd, &source, "file.ref");
+ err = reftable_reader_new(&reader, &source, "file.ref");
check(!err);
if (!indexed)
- rd.obj_offsets.is_present = 0;
+ reader->obj_offsets.is_present = 0;
- reftable_reader_init_ref_iterator(&rd, &it);
+ reftable_reader_init_ref_iterator(reader, &it);
err = reftable_iterator_seek_ref(&it, "");
check(!err);
reftable_iterator_destroy(&it);
- err = reftable_reader_refs_for(&rd, &it, want_hash);
+ err = reftable_reader_refs_for(reader, &it, want_hash);
check(!err);
for (j = 0; ; j++) {
@@ -600,7 +601,7 @@ static void t_table_refs_for(int indexed)
strbuf_release(&buf);
free_names(want_names);
reftable_iterator_destroy(&it);
- reader_close(&rd);
+ reftable_reader_decref(reader);
}
static void t_table_refs_for_no_index(void)
@@ -635,7 +636,7 @@ static void t_write_empty_table(void)
block_source_from_strbuf(&source, &buf);
- err = reftable_new_reader(&rd, &source, "filename");
+ err = reftable_reader_new(&rd, &source, "filename");
check(!err);
reftable_reader_init_ref_iterator(rd, &it);
@@ -646,7 +647,7 @@ static void t_write_empty_table(void)
check_int(err, >, 0);
reftable_iterator_destroy(&it);
- reftable_reader_free(rd);
+ reftable_reader_decref(rd);
strbuf_release(&buf);
}
@@ -844,7 +845,7 @@ static void t_write_multiple_indices(void)
check_int(stats->log_stats.index_offset, >, 0);
block_source_from_strbuf(&source, &writer_buf);
- err = reftable_new_reader(&reader, &source, "filename");
+ err = reftable_reader_new(&reader, &source, "filename");
check(!err);
/*
@@ -857,7 +858,7 @@ static void t_write_multiple_indices(void)
reftable_iterator_destroy(&it);
reftable_writer_free(writer);
- reftable_reader_free(reader);
+ reftable_reader_decref(reader);
strbuf_release(&writer_buf);
strbuf_release(&buf);
}
@@ -901,7 +902,7 @@ static void t_write_multi_level_index(void)
check_int(stats->ref_stats.max_index_level, ==, 2);
block_source_from_strbuf(&source, &writer_buf);
- err = reftable_new_reader(&reader, &source, "filename");
+ err = reftable_reader_new(&reader, &source, "filename");
check(!err);
/*
@@ -913,7 +914,7 @@ static void t_write_multi_level_index(void)
reftable_iterator_destroy(&it);
reftable_writer_free(writer);
- reftable_reader_free(reader);
+ reftable_reader_decref(reader);
strbuf_release(&writer_buf);
strbuf_release(&buf);
}
@@ -922,11 +923,11 @@ static void t_corrupt_table_empty(void)
{
struct strbuf buf = STRBUF_INIT;
struct reftable_block_source source = { 0 };
- struct reftable_reader rd = { 0 };
+ struct reftable_reader *reader;
int err;
block_source_from_strbuf(&source, &buf);
- err = init_reader(&rd, &source, "file.log");
+ err = reftable_reader_new(&reader, &source, "file.log");
check_int(err, ==, REFTABLE_FORMAT_ERROR);
}
@@ -935,13 +936,14 @@ static void t_corrupt_table(void)
uint8_t zeros[1024] = { 0 };
struct strbuf buf = STRBUF_INIT;
struct reftable_block_source source = { 0 };
- struct reftable_reader rd = { 0 };
+ struct reftable_reader *reader;
int err;
strbuf_add(&buf, zeros, sizeof(zeros));
block_source_from_strbuf(&source, &buf);
- err = init_reader(&rd, &source, "file.log");
+ err = reftable_reader_new(&reader, &source, "file.log");
check_int(err, ==, REFTABLE_FORMAT_ERROR);
+
strbuf_release(&buf);
}
diff --git a/t/unit-tests/t-urlmatch-normalization.c b/t/unit-tests/t-urlmatch-normalization.c
new file mode 100644
index 0000000000..1769c357b9
--- /dev/null
+++ b/t/unit-tests/t-urlmatch-normalization.c
@@ -0,0 +1,271 @@
+#include "test-lib.h"
+#include "urlmatch.h"
+
+static void check_url_normalizable(const char *url, unsigned int normalizable)
+{
+ char *url_norm = url_normalize(url, NULL);
+
+ if (!check_int(normalizable, ==, url_norm ? 1 : 0))
+ test_msg("input url: %s", url);
+ free(url_norm);
+}
+
+static void check_normalized_url(const char *url, const char *expect)
+{
+ char *url_norm = url_normalize(url, NULL);
+
+ if (!check_str(url_norm, expect))
+ test_msg("input url: %s", url);
+ free(url_norm);
+}
+
+static void compare_normalized_urls(const char *url1, const char *url2,
+ unsigned int equal)
+{
+ char *url1_norm = url_normalize(url1, NULL);
+ char *url2_norm = url_normalize(url2, NULL);
+
+ if (equal) {
+ if (!check_str(url1_norm, url2_norm))
+ test_msg("input url1: %s\n input url2: %s", url1,
+ url2);
+ } else if (!check_int(strcmp(url1_norm, url2_norm), !=, 0)) {
+ test_msg(" normalized url1: %s\n normalized url2: %s\n"
+ " input url1: %s\n input url2: %s",
+ url1_norm, url2_norm, url1, url2);
+ }
+ free(url1_norm);
+ free(url2_norm);
+}
+
+static void check_normalized_url_length(const char *url, size_t len)
+{
+ struct url_info info;
+ char *url_norm = url_normalize(url, &info);
+
+ if (!check_int(info.url_len, ==, len))
+ test_msg(" input url: %s\n normalized url: %s", url,
+ url_norm);
+ free(url_norm);
+}
+
+/* Note that only "file:" URLs should be allowed without a host */
+static void t_url_scheme(void)
+{
+ check_url_normalizable("", 0);
+ check_url_normalizable("_", 0);
+ check_url_normalizable("scheme", 0);
+ check_url_normalizable("scheme:", 0);
+ check_url_normalizable("scheme:/", 0);
+ check_url_normalizable("scheme://", 0);
+ check_url_normalizable("file", 0);
+ check_url_normalizable("file:", 0);
+ check_url_normalizable("file:/", 0);
+ check_url_normalizable("file://", 1);
+ check_url_normalizable("://acme.co", 0);
+ check_url_normalizable("x_test://acme.co", 0);
+ check_url_normalizable("-test://acme.co", 0);
+ check_url_normalizable("0test://acme.co", 0);
+ check_url_normalizable("+test://acme.co", 0);
+ check_url_normalizable(".test://acme.co", 0);
+ check_url_normalizable("schem%6e://", 0);
+ check_url_normalizable("x-Test+v1.0://acme.co", 1);
+ check_normalized_url("AbCdeF://x.Y", "abcdef://x.y/");
+}
+
+static void t_url_authority(void)
+{
+ check_url_normalizable("scheme://user:pass@", 0);
+ check_url_normalizable("scheme://?", 0);
+ check_url_normalizable("scheme://#", 0);
+ check_url_normalizable("scheme:///", 0);
+ check_url_normalizable("scheme://:", 0);
+ check_url_normalizable("scheme://:555", 0);
+ check_url_normalizable("file://user:pass@", 1);
+ check_url_normalizable("file://?", 1);
+ check_url_normalizable("file://#", 1);
+ check_url_normalizable("file:///", 1);
+ check_url_normalizable("file://:", 1);
+ check_url_normalizable("file://:555", 0);
+ check_url_normalizable("scheme://user:pass@host", 1);
+ check_url_normalizable("scheme://@host", 1);
+ check_url_normalizable("scheme://%00@host", 1);
+ check_url_normalizable("scheme://%%@host", 0);
+ check_url_normalizable("scheme://host_", 1);
+ check_url_normalizable("scheme://user:pass@host/", 1);
+ check_url_normalizable("scheme://@host/", 1);
+ check_url_normalizable("scheme://host/", 1);
+ check_url_normalizable("scheme://host?x", 1);
+ check_url_normalizable("scheme://host#x", 1);
+ check_url_normalizable("scheme://host/@", 1);
+ check_url_normalizable("scheme://host?@x", 1);
+ check_url_normalizable("scheme://host#@x", 1);
+ check_url_normalizable("scheme://[::1]", 1);
+ check_url_normalizable("scheme://[::1]/", 1);
+ check_url_normalizable("scheme://hos%41/", 0);
+ check_url_normalizable("scheme://[invalid....:/", 1);
+ check_url_normalizable("scheme://invalid....:]/", 1);
+ check_url_normalizable("scheme://invalid....:[/", 0);
+ check_url_normalizable("scheme://invalid....:[", 0);
+}
+
+static void t_url_port(void)
+{
+ check_url_normalizable("xyz://q@some.host:", 1);
+ check_url_normalizable("xyz://q@some.host:456/", 1);
+ check_url_normalizable("xyz://q@some.host:0", 0);
+ check_url_normalizable("xyz://q@some.host:0000000", 0);
+ check_url_normalizable("xyz://q@some.host:0000001?", 1);
+ check_url_normalizable("xyz://q@some.host:065535#", 1);
+ check_url_normalizable("xyz://q@some.host:65535", 1);
+ check_url_normalizable("xyz://q@some.host:65536", 0);
+ check_url_normalizable("xyz://q@some.host:99999", 0);
+ check_url_normalizable("xyz://q@some.host:100000", 0);
+ check_url_normalizable("xyz://q@some.host:100001", 0);
+ check_url_normalizable("http://q@some.host:80", 1);
+ check_url_normalizable("https://q@some.host:443", 1);
+ check_url_normalizable("http://q@some.host:80/", 1);
+ check_url_normalizable("https://q@some.host:443?", 1);
+ check_url_normalizable("http://q@:8008", 0);
+ check_url_normalizable("http://:8080", 0);
+ check_url_normalizable("http://:", 0);
+ check_url_normalizable("xyz://q@some.host:456/", 1);
+ check_url_normalizable("xyz://[::1]:456/", 1);
+ check_url_normalizable("xyz://[::1]:/", 1);
+ check_url_normalizable("xyz://[::1]:000/", 0);
+ check_url_normalizable("xyz://[::1]:0%300/", 0);
+ check_url_normalizable("xyz://[::1]:0x80/", 0);
+ check_url_normalizable("xyz://[::1]:4294967297/", 0);
+ check_url_normalizable("xyz://[::1]:030f/", 0);
+}
+
+static void t_url_port_normalization(void)
+{
+ check_normalized_url("http://x:800", "http://x:800/");
+ check_normalized_url("http://x:0800", "http://x:800/");
+ check_normalized_url("http://x:00000800", "http://x:800/");
+ check_normalized_url("http://x:065535", "http://x:65535/");
+ check_normalized_url("http://x:1", "http://x:1/");
+ check_normalized_url("http://x:80", "http://x/");
+ check_normalized_url("http://x:080", "http://x/");
+ check_normalized_url("http://x:000000080", "http://x/");
+ check_normalized_url("https://x:443", "https://x/");
+ check_normalized_url("https://x:0443", "https://x/");
+ check_normalized_url("https://x:000000443", "https://x/");
+}
+
+static void t_url_general_escape(void)
+{
+ check_url_normalizable("http://x.y?%fg", 0);
+ check_normalized_url("X://W/%7e%41^%3a", "x://w/~A%5E%3A");
+ check_normalized_url("X://W/:/?#[]@", "x://w/:/?#[]@");
+ check_normalized_url("X://W/$&()*+,;=", "x://w/$&()*+,;=");
+ check_normalized_url("X://W/'", "x://w/'");
+ check_normalized_url("X://W?!", "x://w/?!");
+}
+
+static void t_url_high_bit(void)
+{
+ check_normalized_url(
+ "x://q/\x01\x02\x03\x04\x05\x06\x07\x08\x0e\x0f\x10\x11\x12",
+ "x://q/%01%02%03%04%05%06%07%08%0E%0F%10%11%12");
+ check_normalized_url(
+ "x://q/\x13\x14\x15\x16\x17\x18\x19\x1b\x1c\x1d\x1e\x1f\x7f",
+ "x://q/%13%14%15%16%17%18%19%1B%1C%1D%1E%1F%7F");
+ check_normalized_url(
+ "x://q/\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f",
+ "x://q/%80%81%82%83%84%85%86%87%88%89%8A%8B%8C%8D%8E%8F");
+ check_normalized_url(
+ "x://q/\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f",
+ "x://q/%90%91%92%93%94%95%96%97%98%99%9A%9B%9C%9D%9E%9F");
+ check_normalized_url(
+ "x://q/\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf",
+ "x://q/%A0%A1%A2%A3%A4%A5%A6%A7%A8%A9%AA%AB%AC%AD%AE%AF");
+ check_normalized_url(
+ "x://q/\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf",
+ "x://q/%B0%B1%B2%B3%B4%B5%B6%B7%B8%B9%BA%BB%BC%BD%BE%BF");
+ check_normalized_url(
+ "x://q/\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf",
+ "x://q/%C0%C1%C2%C3%C4%C5%C6%C7%C8%C9%CA%CB%CC%CD%CE%CF");
+ check_normalized_url(
+ "x://q/\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf",
+ "x://q/%D0%D1%D2%D3%D4%D5%D6%D7%D8%D9%DA%DB%DC%DD%DE%DF");
+ check_normalized_url(
+ "x://q/\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef",
+ "x://q/%E0%E1%E2%E3%E4%E5%E6%E7%E8%E9%EA%EB%EC%ED%EE%EF");
+ check_normalized_url(
+ "x://q/\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+ "x://q/%F0%F1%F2%F3%F4%F5%F6%F7%F8%F9%FA%FB%FC%FD%FE%FF");
+}
+
+static void t_url_utf8_escape(void)
+{
+ check_normalized_url(
+ "x://q/\xc2\x80\xdf\xbf\xe0\xa0\x80\xef\xbf\xbd\xf0\x90\x80\x80\xf0\xaf\xbf\xbd",
+ "x://q/%C2%80%DF%BF%E0%A0%80%EF%BF%BD%F0%90%80%80%F0%AF%BF%BD");
+}
+
+static void t_url_username_pass(void)
+{
+ check_normalized_url("x://%41%62(^):%70+d@foo", "x://Ab(%5E):p+d@foo/");
+}
+
+static void t_url_length(void)
+{
+ check_normalized_url_length("Http://%4d%65:%4d^%70@The.Host", 25);
+ check_normalized_url_length("http://%41:%42@x.y/%61/", 17);
+ check_normalized_url_length("http://@x.y/^", 15);
+}
+
+static void t_url_dots(void)
+{
+ check_normalized_url("x://y/.", "x://y/");
+ check_normalized_url("x://y/./", "x://y/");
+ check_normalized_url("x://y/a/.", "x://y/a");
+ check_normalized_url("x://y/a/./", "x://y/a/");
+ check_normalized_url("x://y/.?", "x://y/?");
+ check_normalized_url("x://y/./?", "x://y/?");
+ check_normalized_url("x://y/a/.?", "x://y/a?");
+ check_normalized_url("x://y/a/./?", "x://y/a/?");
+ check_normalized_url("x://y/a/./b/.././../c", "x://y/c");
+ check_normalized_url("x://y/a/./b/../.././c/", "x://y/c/");
+ check_normalized_url("x://y/a/./b/.././../c/././.././.", "x://y/");
+ check_url_normalizable("x://y/a/./b/.././../c/././.././..", 0);
+ check_normalized_url("x://y/a/./?/././..", "x://y/a/?/././..");
+ check_normalized_url("x://y/%2e/", "x://y/");
+ check_normalized_url("x://y/%2E/", "x://y/");
+ check_normalized_url("x://y/a/%2e./", "x://y/");
+ check_normalized_url("x://y/b/.%2E/", "x://y/");
+ check_normalized_url("x://y/c/%2e%2E/", "x://y/");
+}
+
+/*
+ * "http://@foo" specifies an empty user name but does not specify a password.
+ * "http://foo" specifies neither a user name nor a password.
+ * So they should not be equivalent.
+ */
+static void t_url_equivalents(void)
+{
+ compare_normalized_urls("httP://x", "Http://X/", 1);
+ compare_normalized_urls("Http://%4d%65:%4d^%70@The.Host", "hTTP://Me:%4D^p@the.HOST:80/", 1);
+ compare_normalized_urls("https://@x.y/^", "httpS://x.y:443/^", 0);
+ compare_normalized_urls("https://@x.y/^", "httpS://@x.y:0443/^", 1);
+ compare_normalized_urls("https://@x.y/^/../abc", "httpS://@x.y:0443/abc", 1);
+ compare_normalized_urls("https://@x.y/^/..", "httpS://@x.y:0443/", 1);
+}
+
+int cmd_main(int argc UNUSED, const char **argv UNUSED)
+{
+ TEST(t_url_scheme(), "url scheme");
+ TEST(t_url_authority(), "url authority");
+ TEST(t_url_port(), "url port checks");
+ TEST(t_url_port_normalization(), "url port normalization");
+ TEST(t_url_general_escape(), "url general escapes");
+ TEST(t_url_high_bit(), "url high-bit escapes");
+ TEST(t_url_utf8_escape(), "url utf8 escapes");
+ TEST(t_url_username_pass(), "url username/password escapes");
+ TEST(t_url_length(), "url normalized lengths");
+ TEST(t_url_dots(), "url . and .. segments");
+ TEST(t_url_equivalents(), "url equivalents");
+ return test_done();
+}
diff --git a/trace2/tr2_tgt_event.c b/trace2/tr2_tgt_event.c
index 59910a1a4f..45b0850a5e 100644
--- a/trace2/tr2_tgt_event.c
+++ b/trace2/tr2_tgt_event.c
@@ -24,7 +24,7 @@ static struct tr2_dst tr2dst_event = {
* a new field to an existing event, do not require an increment to the EVENT
* format version.
*/
-#define TR2_EVENT_VERSION "3"
+#define TR2_EVENT_VERSION "4"
/*
* Region nesting limit for messages written to the event target.
@@ -622,6 +622,24 @@ static void fn_data_json_fl(const char *file, int line,
}
}
+static void fn_printf_va_fl(const char *file, int line,
+ uint64_t us_elapsed_absolute,
+ const char *fmt, va_list ap)
+{
+ const char *event_name = "printf";
+ struct json_writer jw = JSON_WRITER_INIT;
+ double t_abs = (double)us_elapsed_absolute / 1000000.0;
+
+ jw_object_begin(&jw, 0);
+ event_fmt_prepare(event_name, file, line, NULL, &jw);
+ jw_object_double(&jw, "t_abs", 6, t_abs);
+ maybe_add_string_va(&jw, "msg", fmt, ap);
+ jw_end(&jw);
+
+ tr2_dst_write_line(&tr2dst_event, &jw.json);
+ jw_release(&jw);
+}
+
static void fn_timer(const struct tr2_timer_metadata *meta,
const struct tr2_timer *timer,
int is_final_data)
@@ -694,7 +712,7 @@ struct tr2_tgt tr2_tgt_event = {
.pfn_region_leave_printf_va_fl = fn_region_leave_printf_va_fl,
.pfn_data_fl = fn_data_fl,
.pfn_data_json_fl = fn_data_json_fl,
- .pfn_printf_va_fl = NULL,
+ .pfn_printf_va_fl = fn_printf_va_fl,
.pfn_timer = fn_timer,
.pfn_counter = fn_counter,
};
diff --git a/transport.c b/transport.c
index bab28965f9..3c4714581f 100644
--- a/transport.c
+++ b/transport.c
@@ -189,6 +189,8 @@ static int fetch_refs_from_bundle(struct transport *transport,
&extra_index_pack_args,
fetch_pack_fsck_objects() ? VERIFY_BUNDLE_FSCK : 0);
transport->hash_algo = data->header.hash_algo;
+
+ strvec_clear(&extra_index_pack_args);
return ret;
}
@@ -945,7 +947,13 @@ static int disconnect_git(struct transport *transport)
finish_connect(data->conn);
}
+ if (data->options.negotiation_tips) {
+ oid_array_clear(data->options.negotiation_tips);
+ free(data->options.negotiation_tips);
+ }
list_objects_filter_release(&data->options.filter_options);
+ oid_array_clear(&data->extra_have);
+ oid_array_clear(&data->shallow);
free(data);
return 0;
}