Jeff King | beb188e | 2018-08-06 13:37:20 -0400 | [diff] [blame] | 1 | #!/bin/sh |
Jeff King | 7a76f5c | 2018-08-21 15:23:22 -0400 | [diff] [blame] | 2 | # |
| 3 | # Build two documentation trees and diff the resulting formatted output. |
| 4 | # Compared to a source diff, this can reveal mistakes in the formatting. |
| 5 | # For example: |
| 6 | # |
| 7 | # ./doc-diff origin/master HEAD |
| 8 | # |
| 9 | # would show the differences introduced by a branch based on master. |
Jeff King | beb188e | 2018-08-06 13:37:20 -0400 | [diff] [blame] | 10 | |
| 11 | OPTIONS_SPEC="\ |
| 12 | doc-diff [options] <from> <to> [-- <diff-options>] |
Eric Sunshine | ad51743 | 2018-08-31 02:33:17 -0400 | [diff] [blame] | 13 | doc-diff (-c|--clean) |
Jeff King | beb188e | 2018-08-06 13:37:20 -0400 | [diff] [blame] | 14 | -- |
Martin Ågren | 2be39bb | 2019-03-17 19:36:02 +0100 | [diff] [blame] | 15 | j=n parallel argument to pass to make |
| 16 | f force rebuild; do not rely on cached results |
| 17 | c,clean cleanup temporary working files |
| 18 | from-asciidoc use asciidoc with the 'from'-commit |
| 19 | from-asciidoctor use asciidoctor with the 'from'-commit |
| 20 | asciidoc use asciidoc with both commits |
| 21 | to-asciidoc use asciidoc with the 'to'-commit |
| 22 | to-asciidoctor use asciidoctor with the 'to'-commit |
| 23 | asciidoctor use asciidoctor with both commits |
Martin Ågren | 83b0b89 | 2019-09-16 21:00:28 +0200 | [diff] [blame] | 24 | cut-footer cut away footer |
Jeff King | beb188e | 2018-08-06 13:37:20 -0400 | [diff] [blame] | 25 | " |
| 26 | SUBDIRECTORY_OK=1 |
| 27 | . "$(git --exec-path)/git-sh-setup" |
| 28 | |
| 29 | parallel= |
| 30 | force= |
Eric Sunshine | ad51743 | 2018-08-31 02:33:17 -0400 | [diff] [blame] | 31 | clean= |
Martin Ågren | 2be39bb | 2019-03-17 19:36:02 +0100 | [diff] [blame] | 32 | from_program= |
| 33 | to_program= |
Martin Ågren | 83b0b89 | 2019-09-16 21:00:28 +0200 | [diff] [blame] | 34 | cut_footer= |
Jeff King | beb188e | 2018-08-06 13:37:20 -0400 | [diff] [blame] | 35 | while test $# -gt 0 |
| 36 | do |
| 37 | case "$1" in |
| 38 | -j) |
| 39 | parallel=$2; shift ;; |
Eric Sunshine | ad51743 | 2018-08-31 02:33:17 -0400 | [diff] [blame] | 40 | -c|--clean) |
| 41 | clean=t ;; |
Jeff King | beb188e | 2018-08-06 13:37:20 -0400 | [diff] [blame] | 42 | -f) |
| 43 | force=t ;; |
Martin Ågren | 2be39bb | 2019-03-17 19:36:02 +0100 | [diff] [blame] | 44 | --from-asciidoctor) |
| 45 | from_program=-asciidoctor ;; |
| 46 | --to-asciidoctor) |
| 47 | to_program=-asciidoctor ;; |
| 48 | --asciidoctor) |
| 49 | from_program=-asciidoctor |
| 50 | to_program=-asciidoctor ;; |
| 51 | --from-asciidoc) |
| 52 | from_program=-asciidoc ;; |
| 53 | --to-asciidoc) |
| 54 | to_program=-asciidoc ;; |
| 55 | --asciidoc) |
| 56 | from_program=-asciidoc |
| 57 | to_program=-asciidoc ;; |
Martin Ågren | 83b0b89 | 2019-09-16 21:00:28 +0200 | [diff] [blame] | 58 | --cut-footer) |
| 59 | cut_footer=-cut-footer ;; |
Jeff King | beb188e | 2018-08-06 13:37:20 -0400 | [diff] [blame] | 60 | --) |
| 61 | shift; break ;; |
| 62 | *) |
| 63 | usage ;; |
| 64 | esac |
| 65 | shift |
| 66 | done |
| 67 | |
Martin Ågren | 2afe927 | 2019-02-04 21:50:37 +0100 | [diff] [blame] | 68 | tmp="$(git rev-parse --show-toplevel)/Documentation/tmp-doc-diff" || exit 1 |
Eric Sunshine | ad51743 | 2018-08-31 02:33:17 -0400 | [diff] [blame] | 69 | |
| 70 | if test -n "$clean" |
| 71 | then |
| 72 | test $# -eq 0 || usage |
| 73 | git worktree remove --force "$tmp/worktree" 2>/dev/null |
| 74 | rm -rf "$tmp" |
| 75 | exit 0 |
| 76 | fi |
| 77 | |
Jeff King | beb188e | 2018-08-06 13:37:20 -0400 | [diff] [blame] | 78 | if test -z "$parallel" |
| 79 | then |
| 80 | parallel=$(getconf _NPROCESSORS_ONLN 2>/dev/null) |
| 81 | if test $? != 0 || test -z "$parallel" |
| 82 | then |
| 83 | parallel=1 |
| 84 | fi |
| 85 | fi |
| 86 | |
| 87 | test $# -gt 1 || usage |
| 88 | from=$1; shift |
| 89 | to=$1; shift |
| 90 | |
| 91 | from_oid=$(git rev-parse --verify "$from") || exit 1 |
| 92 | to_oid=$(git rev-parse --verify "$to") || exit 1 |
| 93 | |
Jeff King | beb188e | 2018-08-06 13:37:20 -0400 | [diff] [blame] | 94 | if test -n "$force" |
| 95 | then |
| 96 | rm -rf "$tmp" |
| 97 | fi |
| 98 | |
| 99 | # We'll do both builds in a single worktree, which lets "make" reuse |
| 100 | # results that don't differ between the two trees. |
| 101 | if ! test -d "$tmp/worktree" |
| 102 | then |
Jeff King | 684e742 | 2018-08-30 03:54:31 -0400 | [diff] [blame] | 103 | git worktree add -f --detach "$tmp/worktree" "$from" && |
Jeff King | beb188e | 2018-08-06 13:37:20 -0400 | [diff] [blame] | 104 | dots=$(echo "$tmp/worktree" | sed 's#[^/]*#..#g') && |
| 105 | ln -s "$dots/config.mak" "$tmp/worktree/config.mak" |
| 106 | fi |
| 107 | |
Martin Ågren | 2be39bb | 2019-03-17 19:36:02 +0100 | [diff] [blame] | 108 | construct_makemanflags () { |
| 109 | if test "$1" = "-asciidoc" |
| 110 | then |
| 111 | echo USE_ASCIIDOCTOR= |
| 112 | elif test "$1" = "-asciidoctor" |
| 113 | then |
| 114 | echo USE_ASCIIDOCTOR=YesPlease |
| 115 | fi |
| 116 | } |
| 117 | |
| 118 | from_makemanflags=$(construct_makemanflags "$from_program") && |
| 119 | to_makemanflags=$(construct_makemanflags "$to_program") && |
| 120 | |
Martin Ågren | 83b0b89 | 2019-09-16 21:00:28 +0200 | [diff] [blame] | 121 | from_dir=$from_oid$from_program$cut_footer && |
| 122 | to_dir=$to_oid$to_program$cut_footer && |
Martin Ågren | bc71dc3 | 2019-03-17 19:36:01 +0100 | [diff] [blame] | 123 | |
Jeff King | beb188e | 2018-08-06 13:37:20 -0400 | [diff] [blame] | 124 | # generate_render_makefile <srcdir> <dstdir> |
| 125 | generate_render_makefile () { |
| 126 | find "$1" -type f | |
| 127 | while read src |
| 128 | do |
| 129 | dst=$2/${src#$1/} |
Jeff King | 2607d39 | 2020-02-18 16:40:09 -0500 | [diff] [blame] | 130 | printf 'all: %s\n' "$dst" |
Jeff King | beb188e | 2018-08-06 13:37:20 -0400 | [diff] [blame] | 131 | printf '%s: %s\n' "$dst" "$src" |
| 132 | printf '\t@echo >&2 " RENDER $(notdir $@)" && \\\n' |
| 133 | printf '\tmkdir -p $(dir $@) && \\\n' |
Eric Sunshine | 83d4b5f | 2018-08-31 02:33:16 -0400 | [diff] [blame] | 134 | printf '\tMANWIDTH=80 man $< >$@+ && \\\n' |
Jeff King | beb188e | 2018-08-06 13:37:20 -0400 | [diff] [blame] | 135 | printf '\tmv $@+ $@\n' |
| 136 | done |
| 137 | } |
| 138 | |
Martin Ågren | 2be39bb | 2019-03-17 19:36:02 +0100 | [diff] [blame] | 139 | # render_tree <committish_oid> <directory_name> <makemanflags> |
Jeff King | beb188e | 2018-08-06 13:37:20 -0400 | [diff] [blame] | 140 | render_tree () { |
| 141 | # Skip install-man entirely if we already have an installed directory. |
| 142 | # We can't rely on make here, since "install-man" unconditionally |
| 143 | # copies the files (spending effort, but also updating timestamps that |
| 144 | # we then can't rely on during the render step). We use "mv" to make |
| 145 | # sure we don't get confused by a previous run that failed partway |
| 146 | # through. |
Martin Ågren | bc71dc3 | 2019-03-17 19:36:01 +0100 | [diff] [blame] | 147 | oid=$1 && |
| 148 | dname=$2 && |
Martin Ågren | 2be39bb | 2019-03-17 19:36:02 +0100 | [diff] [blame] | 149 | makemanflags=$3 && |
Martin Ågren | bc71dc3 | 2019-03-17 19:36:01 +0100 | [diff] [blame] | 150 | if ! test -d "$tmp/installed/$dname" |
Jeff King | beb188e | 2018-08-06 13:37:20 -0400 | [diff] [blame] | 151 | then |
Martin Ågren | bc71dc3 | 2019-03-17 19:36:01 +0100 | [diff] [blame] | 152 | git -C "$tmp/worktree" checkout --detach "$oid" && |
Jeff King | beb188e | 2018-08-06 13:37:20 -0400 | [diff] [blame] | 153 | make -j$parallel -C "$tmp/worktree" \ |
Martin Ågren | 2be39bb | 2019-03-17 19:36:02 +0100 | [diff] [blame] | 154 | $makemanflags \ |
Jeff King | beb188e | 2018-08-06 13:37:20 -0400 | [diff] [blame] | 155 | GIT_VERSION=omitted \ |
Felipe Contreras | 1c301bc | 2023-05-03 17:23:49 -0600 | [diff] [blame] | 156 | GIT_DATE=1970-01-01 \ |
Martin Ågren | bc71dc3 | 2019-03-17 19:36:01 +0100 | [diff] [blame] | 157 | DESTDIR="$tmp/installed/$dname+" \ |
Jeff King | beb188e | 2018-08-06 13:37:20 -0400 | [diff] [blame] | 158 | install-man && |
Martin Ågren | bc71dc3 | 2019-03-17 19:36:01 +0100 | [diff] [blame] | 159 | mv "$tmp/installed/$dname+" "$tmp/installed/$dname" |
Jeff King | beb188e | 2018-08-06 13:37:20 -0400 | [diff] [blame] | 160 | fi && |
| 161 | |
| 162 | # As with "installed" above, we skip the render if it's already been |
| 163 | # done. So using make here is primarily just about running in |
| 164 | # parallel. |
Martin Ågren | bc71dc3 | 2019-03-17 19:36:01 +0100 | [diff] [blame] | 165 | if ! test -d "$tmp/rendered/$dname" |
Jeff King | beb188e | 2018-08-06 13:37:20 -0400 | [diff] [blame] | 166 | then |
Martin Ågren | bc71dc3 | 2019-03-17 19:36:01 +0100 | [diff] [blame] | 167 | generate_render_makefile "$tmp/installed/$dname" \ |
| 168 | "$tmp/rendered/$dname+" | |
Jeff King | beb188e | 2018-08-06 13:37:20 -0400 | [diff] [blame] | 169 | make -j$parallel -f - && |
Martin Ågren | bc71dc3 | 2019-03-17 19:36:01 +0100 | [diff] [blame] | 170 | mv "$tmp/rendered/$dname+" "$tmp/rendered/$dname" |
Martin Ågren | e605077 | 2019-03-17 19:36:03 +0100 | [diff] [blame] | 171 | |
Martin Ågren | 83b0b89 | 2019-09-16 21:00:28 +0200 | [diff] [blame] | 172 | if test "$cut_footer" = "-cut-footer" |
Martin Ågren | e605077 | 2019-03-17 19:36:03 +0100 | [diff] [blame] | 173 | then |
| 174 | for f in $(find "$tmp/rendered/$dname" -type f) |
| 175 | do |
Martin Ågren | 83b0b89 | 2019-09-16 21:00:28 +0200 | [diff] [blame] | 176 | head -n -2 "$f" | sed -e '${/^$/d}' >"$f+" && |
Martin Ågren | e605077 | 2019-03-17 19:36:03 +0100 | [diff] [blame] | 177 | mv "$f+" "$f" || |
| 178 | return 1 |
| 179 | done |
| 180 | fi |
Jeff King | beb188e | 2018-08-06 13:37:20 -0400 | [diff] [blame] | 181 | fi |
| 182 | } |
| 183 | |
Martin Ågren | 2be39bb | 2019-03-17 19:36:02 +0100 | [diff] [blame] | 184 | render_tree $from_oid $from_dir $from_makemanflags && |
| 185 | render_tree $to_oid $to_dir $to_makemanflags && |
Martin Ågren | bc71dc3 | 2019-03-17 19:36:01 +0100 | [diff] [blame] | 186 | git -C $tmp/rendered diff --no-index "$@" $from_dir $to_dir |