Files
git-mirror/Documentation/cmd-list.sh
Patrick Steinhardt a7fa5b2f0c Documentation: stop depending on Perl to generate command list
The "cmd-list.perl" script is used to extract the list of commands part
of a specific category and extracts the description of each command from
its respective manpage. The generated output is then included in git(1)
to list all Git commands.

The script is written in Perl. Refactor it to use shell scripting
exclusively so that we can get rid of the mandatory dependency on Perl
to build our documentation.

The converted script is slower compared to its Perl implementation. But
by being careful and not spawning external commands in `format_one ()`
we can mitigate the performance hit to a reasonable level:

    Benchmark 1: Perl
      Time (mean ± σ):      10.3 ms ±   0.2 ms    [User: 7.0 ms, System: 3.3 ms]
      Range (min … max):    10.0 ms …  11.1 ms    200 runs

    Benchmark 2: Shell
      Time (mean ± σ):      74.4 ms ±   0.4 ms    [User: 48.6 ms, System: 24.7 ms]
      Range (min … max):    73.1 ms …  75.5 ms    200 runs

    Summary
      Perl ran
        7.23 ± 0.13 times faster than Shell

While a sevenfold slowdown is significant, the benefit of not requiring
Perl for a fully-functioning Git installation outweighs waiting a couple
of milliseconds longer during the build process.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-04-16 07:30:30 -07:00

105 lines
1.6 KiB
Bash
Executable File

#!/bin/sh
set -e
format_one () {
source_dir="$1"
command="$2"
attributes="$3"
path="$source_dir/Documentation/$command.adoc"
if ! test -f "$path"
then
echo >&2 "No such file $path"
exit 1
fi
state=0
while read line
do
case "$state" in
0)
case "$line" in
git*\(*\)|scalar*\(*\))
mansection="${line##*\(}"
mansection="${mansection%\)}"
;;
NAME)
state=1;;
esac
;;
1)
if test "$line" = "----"
then
state=2
fi
;;
2)
description="$line"
break
;;
esac
done <"$path"
if test -z "$mansection"
then
echo "No man section found in $path" >&2
exit 1
fi
if test -z "$description"
then
echo >&2 "No description found in $path"
exit 1
fi
case "$description" in
"$command - "*)
text="${description#$command - }"
printf "linkgit:%s[%s]::\n\t" "$command" "$mansection"
case "$attributes" in
*" deprecated "*)
printf "(deprecated) "
;;
esac
printf "$text.\n\n"
;;
*)
echo >&2 "Description does not match $command: $description"
exit 1
;;
esac
}
source_dir="$1"
build_dir="$2"
shift 2
for out
do
category="${out#cmds-}"
category="${category%.adoc}"
path="$build_dir/$out"
while read command command_category attributes
do
case "$command" in
"#"*)
continue;;
esac
case "$command_category" in
"$category")
format_one "$source_dir" "$command" " $attributes ";;
esac
done <"$source_dir/command-list.txt" >"$build_dir/$out+"
if cmp "$build_dir/$out+" "$build_dir/$out" >/dev/null 2>&1
then
rm "$build_dir/$out+"
else
mv "$build_dir/$out+" "$build_dir/$out"
fi
done