From e716b2fa66161b5317fb2a51178f2a3219cfa76d Mon Sep 17 00:00:00 2001 From: Ed Santiago Date: Mon, 28 Jun 2021 16:17:13 -0600 Subject: [PATCH] man page checker - part 1 of 2 Add new script, hack/man-page-checker, copied from podman. Run it in 'make validate-local' target. This is NOT the checker requested in #1332 (verify that flags listed in 'skopeo foo --help' are documented in man pages and vice-versa). This is a much simpler script that merely looks for very basic typos or discrepancies between skopeo.1.md and skopeo-foo.1.md. The next part (cross-checking flags) is in progress but will require a huge number of changes to the man pages. I'm submitting this now because it's easy to review. Signed-off-by: Ed Santiago --- Makefile | 2 + cmd/skopeo/login.go | 2 +- cmd/skopeo/logout.go | 2 +- cmd/skopeo/manifest.go | 2 +- cmd/skopeo/sync.go | 2 +- docs/skopeo-copy.1.md | 3 +- docs/skopeo-delete.1.md | 3 +- docs/skopeo-list-tags.1.md | 9 +- docs/skopeo-login.1.md | 2 +- docs/skopeo-logout.1.md | 2 +- docs/skopeo-standalone-sign.1.md | 3 +- docs/skopeo-standalone-verify.1.md | 3 +- docs/skopeo-sync.1.md | 2 +- docs/skopeo.1.md | 14 +-- hack/man-page-checker | 153 +++++++++++++++++++++++++++++ 15 files changed, 177 insertions(+), 27 deletions(-) create mode 100755 hack/man-page-checker diff --git a/Makefile b/Makefile index f728266b5d..3bf64b9614 100644 --- a/Makefile +++ b/Makefile @@ -209,8 +209,10 @@ validate: build-container # This target is only intended for development, e.g. executing it from an IDE. Use (make test) for CI or pre-release testing. test-all-local: validate-local test-unit-local +.PHONY: validate-local validate-local: hack/make.sh validate-git-marks validate-gofmt validate-lint validate-vet + hack/man-page-checker test-unit-local: $(GPGME_ENV) $(GO) test $(MOD_VENDOR) -tags "$(BUILDTAGS)" $$($(GO) list $(MOD_VENDOR) -tags "$(BUILDTAGS)" -e ./... | grep -v '^github\.com/containers/skopeo/\(integration\|vendor/.*\)$$') diff --git a/cmd/skopeo/login.go b/cmd/skopeo/login.go index a9faaa58d4..151db60587 100644 --- a/cmd/skopeo/login.go +++ b/cmd/skopeo/login.go @@ -21,7 +21,7 @@ func loginCmd(global *globalOptions) *cobra.Command { global: global, } cmd := &cobra.Command{ - Use: "login", + Use: "login [command options] REGISTRY", Short: "Login to a container registry", Long: "Login to a container registry on a specified server.", RunE: commandAction(opts.run), diff --git a/cmd/skopeo/logout.go b/cmd/skopeo/logout.go index 92dc308fd8..b47ccffbf2 100644 --- a/cmd/skopeo/logout.go +++ b/cmd/skopeo/logout.go @@ -17,7 +17,7 @@ func logoutCmd(global *globalOptions) *cobra.Command { global: global, } cmd := &cobra.Command{ - Use: "logout", + Use: "logout [command options] REGISTRY", Short: "Logout of a container registry", Long: "Logout of a container registry on a specified server.", RunE: commandAction(opts.run), diff --git a/cmd/skopeo/manifest.go b/cmd/skopeo/manifest.go index 1bf00db74b..8a8fd0ff1d 100644 --- a/cmd/skopeo/manifest.go +++ b/cmd/skopeo/manifest.go @@ -16,7 +16,7 @@ type manifestDigestOptions struct { func manifestDigestCmd() *cobra.Command { var opts manifestDigestOptions cmd := &cobra.Command{ - Use: "manifest-digest MANIFEST", + Use: "manifest-digest MANIFEST-FILE", Short: "Compute a manifest digest of a file", RunE: commandAction(opts.run), Example: "skopeo manifest-digest manifest.json", diff --git a/cmd/skopeo/sync.go b/cmd/skopeo/sync.go index d3a51d64eb..8669409818 100644 --- a/cmd/skopeo/sync.go +++ b/cmd/skopeo/sync.go @@ -80,7 +80,7 @@ func syncCmd(global *globalOptions) *cobra.Command { } cmd := &cobra.Command{ - Use: "sync [command options] --src SOURCE-LOCATION --dest DESTINATION-LOCATION SOURCE DESTINATION", + Use: "sync [command options] --src TRANSPORT --dest TRANSPORT SOURCE DESTINATION", Short: "Synchronize one or more images from one location to another", Long: fmt.Sprint(`Copy all the images from a SOURCE to a DESTINATION. diff --git a/docs/skopeo-copy.1.md b/docs/skopeo-copy.1.md index f87e5c0122..506c72c9e0 100644 --- a/docs/skopeo-copy.1.md +++ b/docs/skopeo-copy.1.md @@ -4,7 +4,7 @@ skopeo\-copy - Copy an image (manifest, filesystem layers, signatures) from one location to another. ## SYNOPSIS -**skopeo copy** [**--sign-by=**_key-ID_] _source-image destination-image_ +**skopeo copy** [*options*] _source-image_ _destination-image_ ## DESCRIPTION Copy an image (manifest, filesystem layers, signatures) from one location to another. @@ -155,4 +155,3 @@ skopeo(1), skopeo-login(1), docker-login(1), containers-auth.json(5), containers ## AUTHORS Antonio Murdaca , Miloslav Trmac , Jhon Honce - diff --git a/docs/skopeo-delete.1.md b/docs/skopeo-delete.1.md index 199cd1eaaa..5406516254 100644 --- a/docs/skopeo-delete.1.md +++ b/docs/skopeo-delete.1.md @@ -4,7 +4,7 @@ skopeo\-delete - Mark the _image-name_ for later deletion by the registry's garbage collector. ## SYNOPSIS -**skopeo delete** _image-name_ +**skopeo delete** [*options*] _image-name_ Mark _image-name_ for deletion. To release the allocated disk space, you must login to the container registry server and execute the container registry garbage collector. E.g., @@ -53,4 +53,3 @@ skopeo(1), skopeo-login(1), docker-login(1), containers-auth.json(5) ## AUTHORS Antonio Murdaca , Miloslav Trmac , Jhon Honce - diff --git a/docs/skopeo-list-tags.1.md b/docs/skopeo-list-tags.1.md index 349bf8b1a7..47b85e3d1d 100644 --- a/docs/skopeo-list-tags.1.md +++ b/docs/skopeo-list-tags.1.md @@ -4,7 +4,7 @@ skopeo\-list\-tags - Return a list of tags for the transport-specific image repository. ## SYNOPSIS -**skopeo list-tags** _repository-name_ +**skopeo list-tags** [*options*] _repository-name_ Return a list of tags from _repository-name_ in a registry. @@ -36,18 +36,18 @@ This commands refers to repositories using a _transport_`:`_details_ format. The **docker://**_docker-repository-reference_ A repository in a registry implementing the "Docker Registry HTTP API V2". By default, uses the authorization state in either `$XDG_RUNTIME_DIR/containers/auth.json`, which is set using `(skopeo login)`. If the authorization state is not found there, `$HOME/.docker/config.json` is checked, which is set using `(docker login)`. A _docker-repository-reference_ is of the form: **registryhost:port/repositoryname** which is similar to an _image-reference_ but with no tag or digest allowed as the last component (e.g no `:latest` or `@sha256:xyz`) - + Examples of valid docker-repository-references: "docker.io/myuser/myrepo" "docker.io/nginx" "docker.io/library/fedora" "localhost:5000/myrepository" - + Examples of invalid references: "docker.io/nginx:latest" "docker.io/myuser/myimage:v1.0" "docker.io/myuser/myimage@sha256:f48c4cc192f4c3c6a069cb5cca6d0a9e34d6076ba7c214fd0cc3ca60e0af76bb" - + ## EXAMPLES @@ -103,4 +103,3 @@ skopeo(1), skopeo-login(1), docker-login(1), containers-auth.json(5) ## AUTHORS Zach Hill - diff --git a/docs/skopeo-login.1.md b/docs/skopeo-login.1.md index 92e298c0e0..06332fcb3d 100644 --- a/docs/skopeo-login.1.md +++ b/docs/skopeo-login.1.md @@ -4,7 +4,7 @@ skopeo\-login - Login to a container registry. ## SYNOPSIS -**skopeo login** [*options*] *registry* +**skopeo login** [*options*] _registry_ ## DESCRIPTION **skopeo login** logs into a specified registry server with the correct username diff --git a/docs/skopeo-logout.1.md b/docs/skopeo-logout.1.md index 7527adb6db..fc56275564 100644 --- a/docs/skopeo-logout.1.md +++ b/docs/skopeo-logout.1.md @@ -4,7 +4,7 @@ skopeo\-logout - Logout of a container registry. ## SYNOPSIS -**skopeo logout** [*options*] *registry* +**skopeo logout** [*options*] _registry_ ## DESCRIPTION **skopeo logout** logs out of a specified registry server by deleting the cached credentials diff --git a/docs/skopeo-standalone-sign.1.md b/docs/skopeo-standalone-sign.1.md index dad70dceb5..b123d04bd1 100644 --- a/docs/skopeo-standalone-sign.1.md +++ b/docs/skopeo-standalone-sign.1.md @@ -4,7 +4,7 @@ skopeo\-standalone-sign - Debugging tool - Publish and sign an image in one step. ## SYNOPSIS -**skopeo standalone-sign** _manifest docker-reference key-fingerprint_ **--output**|**-o** _signature_ +**skopeo standalone-sign** [*options*] _manifest_ _docker-reference_ _key-fingerprint_ ## DESCRIPTION This is primarily a debugging tool, or useful for special cases, @@ -31,4 +31,3 @@ skopeo(1), skopeo-copy(1), containers-signature(5) ## AUTHORS Antonio Murdaca , Miloslav Trmac , Jhon Honce - diff --git a/docs/skopeo-standalone-verify.1.md b/docs/skopeo-standalone-verify.1.md index 649f640614..872b52165c 100644 --- a/docs/skopeo-standalone-verify.1.md +++ b/docs/skopeo-standalone-verify.1.md @@ -4,7 +4,7 @@ skopeo\-standalone\-verify - Verify an image signature. ## SYNOPSIS -**skopeo standalone-verify** _manifest docker-reference key-fingerprint signature_ +**skopeo standalone-verify** _manifest_ _docker-reference_ _key-fingerprint_ _signature_ ## DESCRIPTION @@ -33,4 +33,3 @@ skopeo(1), containers-signature(5) ## AUTHORS Antonio Murdaca , Miloslav Trmac , Jhon Honce - diff --git a/docs/skopeo-sync.1.md b/docs/skopeo-sync.1.md index bedf63013a..c19ccae571 100644 --- a/docs/skopeo-sync.1.md +++ b/docs/skopeo-sync.1.md @@ -5,7 +5,7 @@ skopeo\-sync - Synchronize images between container registries and local directo ## SYNOPSIS -**skopeo sync** --src _transport_ --dest _transport_ _source_ _destination_ +**skopeo sync** [*options*] --src _transport_ --dest _transport_ _source_ _destination_ ## DESCRIPTION Synchronize images between container registries and local directories. diff --git a/docs/skopeo.1.md b/docs/skopeo.1.md index 851909fd50..1f7413ce2f 100644 --- a/docs/skopeo.1.md +++ b/docs/skopeo.1.md @@ -78,15 +78,15 @@ See [containers-transports(5)](https://github.com/containers/image/blob/master/d | Command | Description | | ----------------------------------------- | ------------------------------------------------------------------------------ | | [skopeo-copy(1)](skopeo-copy.1.md) | Copy an image (manifest, filesystem layers, signatures) from one location to another. | -| [skopeo-delete(1)](skopeo-delete.1.md) | Mark image-name for deletion. | -| [skopeo-inspect(1)](skopeo-inspect.1.md) | Return low-level information about image-name in a registry. | -| [skopeo-list-tags(1)](skopeo-list-tags.1.md) | List the tags for the given transport/repository. | +| [skopeo-delete(1)](skopeo-delete.1.md) | Mark the _image-name_ for later deletion by the registry's garbage collector. | +| [skopeo-inspect(1)](skopeo-inspect.1.md) | Return low-level information about _image-name_ in a registry. | +| [skopeo-list-tags(1)](skopeo-list-tags.1.md) | Return a list of tags for the transport-specific image repository. | | [skopeo-login(1)](skopeo-login.1.md) | Login to a container registry. | | [skopeo-logout(1)](skopeo-logout.1.md) | Logout of a container registry. | -| [skopeo-manifest-digest(1)](skopeo-manifest-digest.1.md) | Compute a manifest digest of manifest-file and write it to standard output.| -| [skopeo-standalone-sign(1)](skopeo-standalone-sign.1.md) | Sign an image. | -| [skopeo-standalone-verify(1)](skopeo-standalone-verify.1.md)| Verify an image. | -| [skopeo-sync(1)](skopeo-sync.1.md)| Copy images from one or more repositories to a user specified destination. | +| [skopeo-manifest-digest(1)](skopeo-manifest-digest.1.md) | Compute a manifest digest for a manifest-file and write it to standard output. | +| [skopeo-standalone-sign(1)](skopeo-standalone-sign.1.md) | Debugging tool - Publish and sign an image in one step. | +| [skopeo-standalone-verify(1)](skopeo-standalone-verify.1.md)| Verify an image signature. | +| [skopeo-sync(1)](skopeo-sync.1.md)| Synchronize images between container registries and local directories. | ## FILES **/etc/containers/policy.json** diff --git a/hack/man-page-checker b/hack/man-page-checker new file mode 100755 index 0000000000..28dc73f5d5 --- /dev/null +++ b/hack/man-page-checker @@ -0,0 +1,153 @@ +#!/usr/bin/env bash +# +# man-page-checker - validate and cross-reference man page names +# +# This is the script that cross-checks BETWEEN MAN PAGES. It is not the +# script that cross-checks that each option in skopeo foo --help is listed +# in skopeo-foo.1.md and vice-versa; that one is xref-helpmsgs-manpages. +# +# IMPORTANT NOTE: this script runs on Macs, on which sed is an ancient +# non-gnu version. To make sed work on all platforms, we invoke with '-E'. +# + +verbose= +for i; do + case "$i" in + -v|--verbose) verbose=verbose ;; + esac +done + + +die() { + echo "$(basename $0): $*" >&2 + exit 1 +} + +cd $(dirname $0)/../docs || die "Please run me from top-level skopeo dir" + +rc=0 + +# Pass 1: cross-check file names with NAME section +# +# for a given skopeo-foo.1.md, the NAME should be 'skopeo-foo' +for md in *.1.md;do + # Read the first line after '## NAME' + name=$(egrep -A1 '^## NAME' $md|tail -1|awk '{print $1}' | tr -d \\\\) + + expect=$(basename $md .1.md) + if [ "$name" != "$expect" ]; then + echo + printf "Inconsistent program NAME in %s:\n" $md + printf " NAME= %s (expected: %s)\n" $name $expect + rc=1 + fi +done + +# Pass 2: compare descriptions. +# +# Make sure the descriptive text in skopeo-foo.1.md matches the one +# in the table in skopeo.1.md. +for md in $(ls -1 *-*.1.md);do + desc=$(egrep -A1 '^## NAME' $md|tail -1|sed -E -e 's/^skopeo[^[:space:]]+ - //') + + # Find the descriptive text in the main skopeo man page. + parent=skopeo.1.md + parent_desc=$(grep $md $parent | awk -F'|' '{print $3}' | sed -E -e 's/^[[:space:]]+//' -e 's/[[:space:]]+$//') + + if [ "$desc" != "$parent_desc" ]; then + echo + printf "Inconsistent subcommand descriptions:\n" + printf " %-32s = '%s'\n" $md "$desc" + printf " %-32s = '%s'\n" $parent "$parent_desc" + printf "Please ensure that the NAME section of $md\n" + printf "matches the subcommand description in $parent\n" + rc=1 + fi +done + +# Helper function: compares man page synopsis vs --help usage message +function compare_usage() { + local cmd="$1" + local from_man="$2" + + # Sometimes in CI we run before skopeo gets built. + test -x ../bin/skopeo || return + + # Run 'cmd --help', grab the line immediately after 'Usage:' + local help_output=$(../bin/$cmd --help) + local from_help=$(echo "$help_output" | grep -A1 '^Usage:' | tail -1) + + # strip off command name from both + from_man=$(sed -E -e "s/\*\*$cmd\*\*[[:space:]]*//" <<<"$from_man") + from_help=$(sed -E -e "s/^[[:space:]]*$cmd[[:space:]]*//" <<<"$from_help") + + # man page lists 'foo [*options*]', help msg shows 'foo [flags]'. + # Make sure if one has it, the other does too. + if expr "$from_man" : "\[\*options\*\]" >/dev/null; then + if expr "$from_help" : "\[command options\]" >/dev/null; then + : + else + echo "WARNING: $cmd: man page shows '[*options*]', help does not show [command options]" + rc=1 + fi + elif expr "$from_help" : "\[command options\]" >/dev/null; then + echo "WARNING: $cmd: --help shows [command options], man page does not show [*options*]" + rc=1 + fi + + # Strip off options and flags; start comparing arguments + from_man=$(sed -E -e 's/^\[\*options\*\][[:space:]]*//' <<<"$from_man") + from_help=$(sed -E -e 's/^\[command options\][[:space:]]*//' <<<"$from_help") + + # Args in man page are '*foo*', in --help are 'FOO'. Convert all to + # UPCASE simply because it stands out better to the eye. + from_man=$(sed -E -e 's/_([a-z-]+)_/\U\1/g' <<<"$from_man") + + # Compare man-page and --help usage strings. Skip 'skopeo' itself, + # because the man page includes '[global options]' which we don't grok. + if [[ "$from_man" != "$from_help" && "$cmd" != "skopeo" ]]; then + printf "%-25s man='%s' help='%s'\n" "$cmd:" "$from_man" "$from_help" + rc=1 + fi +} + +# Pass 3: compare synopses. +# +# Make sure the SYNOPSIS line in skopeo-foo.1.md reads '**skopeo foo** ...' +for md in *.1.md;do + synopsis=$(egrep -A1 '^#* SYNOPSIS' $md|tail -1) + + # Command name must be bracketed by double asterisks; options and + # arguments are bracketed by single ones. + # E.g. '**skopeo copy** [*options*] _..._' + # Get the command name, and confirm that it matches the md file name. + cmd=$(echo "$synopsis" | sed -E -e 's/(.*)\*\*.*/\1/' | tr -d \*) + # Use sed, not tr, so we only replace the first dash: we want + # skopeo-list-tags -> "skopeo list-tags", not "skopeo list tags" + md_nodash=$(basename "$md" .1.md | sed -e 's/-/ /') + if [ "$cmd" != "$md_nodash" ]; then + echo + printf "Inconsistent program name in SYNOPSIS in %s:\n" $md + printf " SYNOPSIS = %s (expected: '%s')\n" "$cmd" "$md_nodash" + rc=1 + fi + + # The convention is to use UPPER CASE in 'skopeo foo --help', + # but *lower case bracketed by asterisks* in the man page + if expr "$synopsis" : ".*[A-Z]" >/dev/null; then + echo + printf "Inconsistent capitalization in SYNOPSIS in %s\n" $md + printf " '%s' should not contain upper-case characters\n" "$synopsis" + rc=1 + fi + + # (for debugging, and getting a sense of standard conventions) + #printf " %-32s ------ '%s'\n" $md "$synopsis" + + # If bin/skopeo is available, run "cmd --help" and compare Usage + # messages. This is complicated, so do it in a helper function. + compare_usage "$md_nodash" "$synopsis" +done + + +exit $rc