combine-packs.sh: update to latest
[girocco.git] / bin / format-readme
blob07d82046da63b331a542598ad74f6d9f04cf36e0
1 #!/bin/sh
3 # format-readme -- find and format a repository's readme blob
4 # Copyright (C) 2015,2016 Kyle J. McKay. All rights reserved.
6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation, either version 2 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
19 # Version 1.2.5
21 # Usage: format-readme [-r <prefix> | -p <prefix> [ -i <imgprefix ] ]
22 # <path-to-repo.git> [<treeish>]
24 # With -r <prefix>, prefix all non-absolute URLs with <prefix>
26 # With -p <prefix>, prefix all non-aboslute URLs with <prefix>/<symlink-path>
27 # where <symlink-path> is the dirname portion of symlink if the selected readme
28 # is a symlink that needs to be followed. If it's not a symlink or it's in the
29 # same directory, the "/<symlink-path>" is not added but <prefix> still is.
31 # With -i <imgprefix> use <imgprefix> instead of <prefix> when link is to
32 # an image. If -p was used it will include the path, if -r was used it won't.
34 set -e
36 nl="$(printf '\n*')"
37 nl="${nl%?}"
38 symlinks=
40 addprefix=
41 addpath=
42 urlprefix=
43 imgprefix=
44 if [ "$1" = "-r" -o "$1" = "-p" ]; then
45 addprefix=1
46 [ "$1" != "-p" ] || addpath=1
47 shift
48 [ -n "$1" ] || exit 2
49 urlprefix="${1%/}/"
50 shift
51 if [ "$1" = "-i" ]; then
52 shift
53 [ -n "$1" ] || exit 2
54 imgprefix="${1%/}/"
55 shift
58 projdir="$1"
59 [ -n "$projdir" -a -d "$projdir" ] || exit 2
60 cd "$projdir" || exit 2
61 unset GIT_DIR
62 gd="$(git rev-parse --git-dir 2>&1)" || exit 2
63 cd "$gd" || exit 2
64 treeish="${2:-HEAD}"
65 tree="$(git rev-parse --quiet --verify "$treeish"^{tree} 2>/dev/null)" || exit 2
67 # We prefer the first file or symlink we find with
68 # a supported extension and then we will follow it
69 # if it's a relative symlink with no '.' or '..' components.
70 # If we don't find a supported extension, we use just plain README
71 # which we assume to be plain text (and we will follow a symlink).
72 # We prefer a markdown extension over others and any extension
73 # other than plain text next followed by plain text and then no extension.
75 haspod=
76 ! perl -MPod::Html -e 1 >/dev/null 2>&1 || haspod=1
78 readme=
79 readmenm=
80 readmelnk=
81 readmefb=
82 readmefbnm=
83 readmefblnk=
84 readmeext=
85 readmeextnm=
86 readmeextlnk=
87 readmeextfmt=
88 while read -r mode type hash size name; do
89 [ "$mode" = "100644" -o "$mode" = "100755" -o "$mode" = "120000" ] || continue
90 [ "$size" != "0" -a "$size" != "-" ] || continue
91 [ "$type" = "blob" ] || continue
92 [ "$mode" != "120000" -o "$size" -lt 1024 ] || continue
93 [ "$mode" != "120000" ] || symlinks="$symlinks$hash $name$nl"
94 case "$name" in
96 [Rr][Ee][Aa][Dd][Mm][Ee].[Mm][Dd]|\
97 [Rr][Ee][Aa][Dd][Mm][Ee].[Mm][Kk][Dd][Nn]|\
98 [Rr][Ee][Aa][Dd][Mm][Ee].[Mm][Dd][Oo][Ww][Nn]|\
99 [Rr][Ee][Aa][Dd][Mm][Ee].[Mm][Aa][Rr][Kk][Dd][Oo][Ww][Nn])
100 if [ -n "$readmeext" ]; then
101 [ "$readmeextfmt" != "md" -o "$mode" != "120000" ] || continue
103 readmeext="$hash"
104 readmeextnm="$name"
105 readmeextlnk=
106 [ "$mode" != "120000" ] || readmeextlnk=1
107 readmeextfmt=md
110 [Rr][Ee][Aa][Dd][Mm][Ee].[Pp][Oo][Dd])
111 [ -n "$haspod" ] || continue
112 if [ -n "$readmeext" ]; then
113 [ "$readmeextfmt" != "md" ] || continue
114 [ "$readmeextfmt" = "txt" -o "$mode" != "120000" ] || continue
116 readmeext="$hash"
117 readmeextnm="$name"
118 readmeextlnk=
119 [ "$mode" != "120000" ] || readmeextlnk=1
120 readmeextfmt=pod
123 [Rr][Ee][Aa][Dd][Mm][Ee].[Tt][Xx][Tt]|\
124 [Rr][Ee][Aa][Dd][Mm][Ee].[Tt][Ee][Xx][Tt])
125 if [ -n "$readmeext" ]; then
126 [ "$readmeextfmt" = "txt" -a "$mode" != "120000" ] || continue
128 readmeext="$hash"
129 readmeextnm="$name"
130 readmeextlnk=
131 [ "$mode" != "120000" ] || readmeextlnk=1
132 readmeextfmt=txt
135 [Rr][Ee][Aa][Dd][Mm][Ee])
136 [ -z "$readme" -o "$mode" != "120000" ] || continue
137 readme="$hash"
138 readmenm="$name"
139 readmelnk=
140 [ "$mode" != "120000" ] || readmelnk=1
143 [Rr][Ee][Aa][Dd][Mm][Ee].?*)
144 [ -z "$readmefb" -o "$mode" != "120000" ] || continue
145 [ "${name%.*}" = "${name%%.*}" ] || continue
146 [ "${name#*.}" = "${name##*[!A-Za-z0-9+_]}" ] || continue
147 [ "${name%[$ws]*}" = "$name" ] || continue
148 readmefb="$hash"
149 readmefbnm="$name"
150 readmefblnk=
151 [ "$mode" != "120000" ] || readmefblnk=1
154 esac
155 done <<EOT
156 $(git ls-tree -l $tree)
158 if [ -n "$readmefb" -a -z "$readme" ]; then
159 readme="$readmefb"
160 readmenm="$readmefbnm"
161 readmelnk="$readmefblnk"
163 if [ -n "$readme" -a -z "$readmeext" ]; then
164 readmeext="$readme"
165 readmeextnm="$readmenm"
166 readmeextlnk="$readmelnk"
167 readmeextfmt=txt
169 [ -n "$readmeext" ] || exit 1
170 if [ -n "$readmeextlnk" ]; then
171 rel="$(git cat-file blob $readmeext 2>/dev/null)" || exit 1
172 case "$rel" in /*) exit 1; esac
173 case "/$rel/" in */../*|*/./*) exit 1; esac
174 case "$rel" in */*) :;; ?*)
175 while read -r hash name; do
176 if [ -n "$hash" -a "$name" = "$rel" ]; then
177 rel2="$(git cat-file blob $hash 2>/dev/null)" || exit 1
178 case "$rel2" in /*) exit 1; esac
179 case "/$rel2/" in */../*|*/./*) exit 1; esac
180 rel="$rel2"
181 break
183 done <<-EOT
184 ${symlinks%?}
186 esac
187 case "$rel" in *?/?*)
188 suffix="${rel#*/}"
189 prefix="${rel%/$suffix}"
190 while read -r hash name; do
191 if [ -n "$hash" -a "$name" = "$prefix" ]; then
192 rel2="$(git cat-file blob $hash 2>/dev/null)" || exit 1
193 case "$rel2" in /*) exit 1; esac
194 case "/$rel2/" in */../*|*/./*) exit 1; esac
195 rel="$rel2/$suffix"
196 break
198 done <<-EOT
199 ${symlinks%?}
201 esac
202 if [ -n "$addpath" ]; then
203 dir="$(dirname "$rel")"
204 if [ "$dir" != "." ]; then
205 urlprefix="${urlprefix%/}/$dir"
206 [ -z "$imgprefix" ] || imgprefix="${imgprefix%/}/$dir"
209 read -r mode type hash size name <<EOT
210 $(git ls-tree -l $tree -- "$rel")
212 [ "$mode" = "100644" -o "$mode" = "100755" ] || exit 1
213 [ "$type" = "blob" ] || exit 1
214 [ "$size" != "0" -a "$size" != "-" ] || exit 1
215 # Fail if > 32K
216 [ "$size" -le 32768 ] || exit 1
217 readmeext="$hash"
220 # Allow up to 32K, but fail if it doesn't look like it's text.
222 contents="$(git cat-file blob $readmeext | perl -e '
223 use 5.008;
224 use strict;
225 use warnings;
226 binmode STDIN, ":perlio" or exit 1
227 unless grep /^perlio$/, PerlIO::get_layers(STDIN);
228 exit 1 unless -T STDIN;
229 undef $/;
230 my $contents = <STDIN>;
231 exit 1 unless defined($contents) && length($contents) > 0 && length($contents) <= 32768;
232 print $contents;
233 exit 0;
234 ' 2>/dev/null)" || exit 1
236 # Format the result
237 case "$readmeextfmt" in
240 # Run Markdown.pl on it
241 cmd='Markdown.pl'
242 if [ -n "$addprefix" ]; then
243 cmd="$cmd -r \"$urlprefix\""
244 [ -z "$imgprefix" ] || cmd="$cmd -i \"$imgprefix\""
246 printf '<!-- README NAME: %s -->\n' "$readmeextnm"
247 printf '%s' "$contents" | eval "$cmd 2>/dev/null"
248 exit $?
251 pod)
252 # Run pod2html and extract the contents
253 arg=
254 if [ -n "$addprefix" -a -n "${urlprefix%/}" ]; then
255 arg=", \"--htmlroot=${urlprefix%/}\""
257 printf '<!-- README NAME: %s -->\n' "$readmeextnm"
258 printf '%s' "$contents" | \
259 perl -MPod::Html -e "pod2html \"--quiet\", \"--no-index\"$arg" 2>/dev/null | \
260 perl -e '
261 use strict;
262 use warnings;
263 undef $/;
264 my $contents = <STDIN>;
265 $contents =~ s,^.*<body[^>]*>\s*,,is;
266 $contents =~ s,\s*</body[^>]*>.*$,,is;
267 $contents =~ s,^.*<!--\s*INDEX\s+END\s*-->\s*,,is;
268 $contents =~ s,^\s*(?:<p>\s*</p>\s*)+,,is;
269 print $contents;
271 exit $?
274 txt)
275 # It's a <pre> block but we need some escaping
276 printf '<!-- README NAME: %s -->\n' "$readmeextnm"
277 printf '%s' '<pre class="plaintext">'
278 printf '%s' "$contents" | LC_ALL=C sed -e 's/&/\&amp;/g' -e 's/</\&lt;/g'
279 printf '%s\n' '</pre>'
280 exit 0
283 esac
284 exit 1