Skip to content

Instantly share code, notes, and snippets.

@ernstki
Last active May 9, 2025 16:09
Show Gist options
  • Save ernstki/ea2649e5ec34dacd9b1d13a8eae10a54 to your computer and use it in GitHub Desktop.
Save ernstki/ea2649e5ec34dacd9b1d13a8eae10a54 to your computer and use it in GitHub Desktop.
Render a roff man page from the apple-oss-distributions GitHub org
#!/usr/bin/env bash
##
## Fetch macOS manual pages from the apple-oss-distributions GitHub org
##
## Author: Kevin Ernst <ernstki -at- mail.uc.edu>
## Date: 8 May 2025
## Source: https://gist.github.com/ernstki/ea2649e5ec34dacd9b1d13a8eae10a54
## License: WTFPL
##
## To do: caching
## See also: https://apple.stackexchange.com/questions/239484
##
set -euo pipefail
TRACE=${TRACE:-}; (( TRACE )) && set -x
ME=${BASH_SOURCE##*/}
NEEDS=(jq curl groff ps2pdf)
GITHUB_API_KEY=${GITHUB_API_KEY:-${MACMAN_API_KEY:?Please set MACMAN_API_KEY in the environment}}
CURLARGS=(--fail -H "Authorization: Bearer $GITHUB_API_KEY")
GHAPI='https://api.github.com'
ORG='apple-oss-distributions'
OOPS="$(tput bold)$(tput setaf 1)OOPS!$(tput sgr0)"
pdf=
list=
exact=
overwrite=
cols=$(tput cols)
width=$(( cols > 100 ? 100 : cols )) # restrict to 100 columns
leftpad=
verbose=
section='[0-9]' # any section
while (( $# )); do
case $1 in
-h|--flags|--help|-\?)
echo "
usage: $ME [-h|--help]
$ME [-v|--verbose] [-p|--pdf [-o|--overwrite]] [-w|--width WIDTH] manpage
$ME {-l|--list} [-x|--exact] manpage
examples:
$ $ME grep
$ $ME grep --pdf --overwrite
$ $ME grep --width=70
$ $ME 5 crontab
homepage:
https://gist.github.com/ernstki/ea2649e5ec34dacd9b1d13a8eae10a54
"
exit
;;
-v|--verbose)
verbose=1
;;
-p|--pdf)
pdf=1
;;
-o|--overwrite)
overwrite=1
;;
-w*|--width*)
if [[ $1 =~ --?w(idth=)?(.+) ]]; then
width=${BASH_REMATCH[2]}
else
shift
width=${1:-$width}
fi
;;
-l|--list)
list=1
;;
-x|--exact)
exact=1
;;
-*)
echo "$OOPS Unknown argument '$1'." >&2;
exit 1
;;
*)
if [[ $1 =~ ^[0-9]$ ]]; then
section=$1
else
manpage=$1
fi
;;
esac
shift
done
for util in ${NEEDS[*]}; do
if ! type $util &>/dev/null; then
if [[ $util =~ pdf && -z $pdf ]]; then continue; fi
echo "$OOPS Missing required utility '$util'" >&2
exit 1
fi
done
if (( !TRACE )); then
CURLARGS+=(--silent)
fi
if (( exact && !list )); then
echo "$OOPS The '--exact' option requires '--list'." >&2
exit 1
fi
# left margin that's half the difference between terminal size and `width`
if (( cols > width )); then
leftpad=$(printf " %.0s" $(seq 1 $(( (cols-width)/2 ))))
fi
# ref: https://docs.github.com/en/rest/search/search#search-code
manpages() (
(( verbose )) && set -x
curl "${CURLARGS[@]}" "$GHAPI/search/code?q=org:$ORG%20in:path%20$1.[0-9]" | {
# TODO: revisit this later, when I'm not being rate-limited
if (( exact )); then
jq -r ".items[]|select(.name|test(\"$manpage\\\\.$section\"))|.url"
else
jq -r ".items[]|select(.name|test(\".*$manpage\\\\.$section\"))|.url"
fi
}
)
list() {
while read -r url; do
curl "${CURLARGS[@]}" "$url" | jq -r .html_url
done
}
getraw() {
curl "${CURLARGS[@]}" -H 'Accept: application/vnd.github.raw+json' "$1"
}
if (( list )); then
manpages "$manpage" | list
exit
fi
if ! url=$(exact=1 manpages "$manpage" | head -1) || [[ -z $url ]]; then
echo "Sorry, no results for '$manpage'." >&2
exit 1
fi
getraw "$url" | {
if (( pdf )); then
if [[ -f $manpage.pdf && -z $overwrite ]]; then
echo "File '$manpage.pdf' exists." \
"Pass '-o' / '--overwrite' to overwrite it." >&2
exit 1
fi
groff -man -Tps | ps2pdf - $manpage.pdf
echo "Wrote '$manpage.pdf'." >&2
else
groff -man -Tutf8 -rLL=${width}n \
| sed "s/^/$leftpad/" | less -RX
fi
}
@ernstki
Copy link
Author

ernstki commented May 9, 2025

Only half-way works, because API-based search seems a bit flaky; path: doesn't work, in:path gives mixed results, and and API-based search doesn't (yet) support regular expressions. So, for example, you should get a man page for kextfind when you macman -l find, but you don't.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment