Re: [PATCH 4/4] Documentation: stop depending on Perl to generate command list
- From
Junio C Hamano <gitster@pobox.com>
- Date
- Apr 15, 2025, 16:32 UTC
- Message-ID
- <xmqqmschmllq.fsf@gitster.g>
- In-Reply-To
- <20250415-b4-pks-drop-perl-v1-4-c6addf175858@pks.im>
Patrick Steinhardt <ps@pks.im> writes:
Show 28 quoted lines
> 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.
I personally do not feel Perl such a drag but whether it is 10ms vs 75ms, as long as we won't run the script excessively (and either meson or make should be set-up to avoid unnecessary work already), I do not think a shell script being slightly slower than a Perl script is a big deal. Thanks for working on this.
Show 27 quoted lines
> diff --git a/Documentation/cmd-list.sh b/Documentation/cmd-list.sh
> new file mode 100755
> index 00000000000..fa90781f3c7
> --- /dev/null
> +++ b/Documentation/cmd-list.sh
> @@ -0,0 +1,104 @@
> +#!/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)Style. label and "case" and "esac" align, just like ...
> + case "$line" in
> + git*\(*\)|scalar*\(*\))
> + mansection="${line##*\(}"... this one.
Show 6 quoted lines
> + mansection="${mansection%\)}"
> + ;;
> + NAME)
> + state=1;;
> + esac
> + ;;> + case "$description" in > + "$command - "*)
Likewise.
Show 5 quoted lines
> + text="${description#$command - }"
> +
> + printf "linkgit:%s[%s]::\n\t" "$command" "$mansection"
> + case "$attributes" in
> + *" deprecated "*)Ditto.
Show 17 quoted lines
> + 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 in "$@"
Let's omit 'in "$@"' when iterationg over "$@".
Show 25 quoted lines
> +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
> +doneOK.