Skip to content

Commit

Permalink
Man page clean-up (#1508)
Browse files Browse the repository at this point in the history
Ensure we don’t include dynamic content in the static man pages.
  • Loading branch information
jkbrzt authored May 22, 2023
1 parent c2677ee commit 2da955f
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 48 deletions.
Original file line number Diff line number Diff line change
@@ -1,27 +1,22 @@
name: Update Autogenerated Files

name: Update Generated Content
on:
push:
branches:
- master

jobs:
regen-autogenerated-files:
update-content:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- uses: actions/setup-python@v4
with:
python-version: 3.9

- run: make regen-all

- run: make content
- name: Create Pull Request
id: cpr
uses: peter-evans/create-pull-request@v4
with:
commit-message: "[automated] Update auto-generated files"
title: "[automated] Update auto-generated files"
commit-message: "[automated] Update generated content"
title: "[automated] Update generated content"
delete-branch: true
token: ${{ secrets.GITHUB_TOKEN }}
8 changes: 4 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -231,15 +231,15 @@ brew-test:
brew audit --strict httpie

###############################################################################
# Regeneration
# Generated content
###############################################################################

regen-all: regen-man-pages regen-install-methods
content: man installation-docs

regen-man-pages: install
man: install
@echo $(H1)Regenerate man pages$(H1END)
$(VENV_PYTHON) extras/scripts/generate_man_pages.py

regen-install-methods:
installation-docs:
@echo $(H1)Updating installation instructions in the docs$(H1END)
$(VENV_PYTHON) docs/installation/generate.py
7 changes: 3 additions & 4 deletions extras/man/http.1
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ The authentication mechanism to be used. Defaults to \[dq]basic\[dq].

\[dq]bearer\[dq]: Bearer HTTP Auth

For finding out all available authentication types in your system, try:
To see all available auth types on your system, including ones installed via plugins, run:

$ http \fB\,--auth-type\/\fR

Expand Down Expand Up @@ -510,11 +510,10 @@ are shown here).



A string in the OpenSSL cipher list format. By default, the following
ciphers are used on your system:
A string in the OpenSSL cipher list format.

TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:DHE-RSA-AES256-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES128-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA

See `http \fB\,--help\/\fR` for the default ciphers list on you system.


.IP "\fB\,--cert\/\fR"
Expand Down
8 changes: 3 additions & 5 deletions extras/man/https.1
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ The authentication mechanism to be used. Defaults to \[dq]basic\[dq].

\[dq]bearer\[dq]: Bearer HTTP Auth

For finding out all available authentication types in your system, try:
To see all available auth types on your system, including ones installed via plugins, run:

$ http \fB\,--auth-type\/\fR

Expand Down Expand Up @@ -509,12 +509,10 @@ are shown here).
.IP "\fB\,--ciphers\/\fR"


A string in the OpenSSL cipher list format.

A string in the OpenSSL cipher list format. By default, the following
ciphers are used on your system:

TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:DHE-RSA-AES256-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES128-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA

See `http \fB\,--help\/\fR` for the default ciphers list on you system.


.IP "\fB\,--cert\/\fR"
Expand Down
21 changes: 13 additions & 8 deletions extras/scripts/generate_man_pages.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
import os
import re
from contextlib import contextmanager
from pathlib import Path
from typing import Optional, Iterator, Iterable


# So that httpie.cli.definition can provide man-page-specific output. Must be set before importing httpie.
os.environ['HTTPIE_BUILDING_MAN_PAGES'] = '1'

import httpie
from httpie.cli.definition import options as core_options
from httpie.cli.definition import options as core_options, IS_MAN_PAGE
from httpie.cli.options import ParserSpec
from httpie.manager.cli import options as manager_options
from httpie.output.ui.rich_help import OptionsHighlighter, to_usage
from httpie.output.ui.rich_utils import render_as_string
from httpie.utils import split_iterable


# Escape certain characters so they are rendered properly on
# all terminals.
# https://man7.org/linux/man-pages/man7/groff_char.7.html
assert IS_MAN_PAGE, 'CLI definition does not understand we’re building man pages'

# Escape certain characters, so they are rendered properly on all terminals.
# <https://man7.org/linux/man-pages/man7/groff_char.7.html>
ESCAPE_MAP = {
'"': '\[dq]',
"'": '\[aq]',
Expand All @@ -32,6 +37,7 @@
OptionsHighlighter.highlights[0]
)


class ManPageBuilder:
def __init__(self):
self.source = []
Expand Down Expand Up @@ -125,7 +131,7 @@ def to_man_page(program_name: str, spec: ParserSpec, *, is_top_level_cmd: bool =

with builder.section('SYNOPSIS'):
# `http` and `https` are commands that can be directly used, so they can have
# have a valid usage. But `httpie` is a top-level command with multiple sub commands,
# a valid usage. But `httpie` is a top-level command with multiple sub commands,
# so for the synopsis we'll only reference the `httpie` name.
if is_top_level_cmd:
synopsis = program_name
Expand Down Expand Up @@ -153,7 +159,7 @@ def to_man_page(program_name: str, spec: ParserSpec, *, is_top_level_cmd: bool =
if raw_arg.get('is_positional'):
# In case of positional arguments, metavar is always equal
# to the list of options (e.g `METHOD`).
metavar = None
metavar = None
builder.add_options(raw_arg['options'], metavar=metavar)

desc = builder.format_desc(raw_arg.get('description', ''))
Expand All @@ -178,6 +184,5 @@ def main() -> None:
stream.write(to_man_page(program_name, spec, **config))



if __name__ == '__main__':
main()
37 changes: 29 additions & 8 deletions httpie/cli/definition.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

import os
import textwrap
from argparse import FileType

Expand All @@ -22,6 +23,12 @@
from httpie.plugins.registry import plugin_manager
from httpie.ssl_ import AVAILABLE_SSL_VERSION_ARG_MAPPING, DEFAULT_SSL_CIPHERS_STRING


# Man pages are static (built when making a release).
# We use this check to not include generated, system-specific information there (e.g., default --ciphers).
IS_MAN_PAGE = bool(os.environ.get('HTTPIE_BUILDING_MAN_PAGES'))


options = ParserSpec(
'http',
description=f'{__doc__.strip()} <https://httpie.io>',
Expand All @@ -35,7 +42,6 @@
source_file=__file__
)


#######################################################################
# Positional arguments.
#######################################################################
Expand Down Expand Up @@ -234,6 +240,7 @@
""",
)


#######################################################################
# Output processing
#######################################################################
Expand Down Expand Up @@ -610,6 +617,7 @@ def format_style_help(available_styles, *, isolation_mode: bool = False):
""",
)


#######################################################################
# Authentication
#######################################################################
Expand All @@ -630,7 +638,7 @@ def format_auth_help(auth_plugins_mapping, *, isolation_mode: bool = False):
if issubclass(auth_plugin, BuiltinAuthPlugin)
]
text += '\n'
text += 'For finding out all available authentication types in your system, try:\n\n'
text += 'To see all available auth types on your system, including ones installed via plugins, run:\n\n'
text += ' $ http --auth-type'

auth_types = '\n\n '.join(
Expand All @@ -646,7 +654,7 @@ def format_auth_help(auth_plugins_mapping, *, isolation_mode: bool = False):
''
if not plugin.description
else '\n '
+ ('\n '.join(textwrap.wrap(plugin.description)))
+ ('\n '.join(textwrap.wrap(plugin.description)))
),
)
for plugin in auth_plugins
Expand Down Expand Up @@ -826,23 +834,36 @@ def format_auth_help(auth_plugins_mapping, *, isolation_mode: bool = False):
""",
)

CIPHERS_CURRENT_DEFAULTS = (
"""
See `http --help` for the default ciphers list on you system.
"""
if IS_MAN_PAGE else
f"""
By default, the following ciphers are used on your system:
{DEFAULT_SSL_CIPHERS_STRING}
"""
)
ssl.add_argument(
'--ciphers',
short_help='A string in the OpenSSL cipher list format.',
help=f"""
A string in the OpenSSL cipher list format. By default, the following
ciphers are used on your system:
A string in the OpenSSL cipher list format.
{DEFAULT_SSL_CIPHERS_STRING}
{CIPHERS_CURRENT_DEFAULTS}
""",
"""
)
ssl.add_argument(
'--cert',
default=None,
type=readable_file_arg,
short_help='Specifys a local cert to use as client side SSL certificate.',
short_help='Specifies a local cert to use as the client-side SSL certificate.',
help="""
You can specify a local cert to use as client side SSL certificate.
This file may either contain both private key and certificate or you may
Expand Down
19 changes: 10 additions & 9 deletions httpie/output/ui/man_pages.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,22 @@
import os
from httpie.context import Environment


MAN_COMMAND = 'man'
NO_MAN_PAGES = os.getenv('HTTPIE_NO_MAN_PAGES', False)

# On some systems, HTTP(n) might exist but we are only
# interested in HTTP(1).
#
# For more information on man page sections: https://unix.stackexchange.com/a/138643

# On some systems, HTTP(n) might exist, but we are only interested in HTTP(1).
# For more information on man page sections: <https://unix.stackexchange.com/a/138643>
MAN_PAGE_SECTION = '1'


def is_available(program: str) -> bool:
"""Check whether HTTPie's man pages are available in this system."""
"""
Check whether `program`'s man pages are available on this system.
"""
if NO_MAN_PAGES or os.system == 'nt':
return False

try:
process = subprocess.run(
[MAN_COMMAND, MAN_PAGE_SECTION, program],
Expand All @@ -29,7 +28,7 @@ def is_available(program: str) -> bool:
stderr=subprocess.DEVNULL
)
except Exception:
# There might be some errors outside of the process, e.g
# There might be some errors outside the process, e.g
# a permission error to execute something that is not an
# executable.
return False
Expand All @@ -38,8 +37,10 @@ def is_available(program: str) -> bool:


def display_for(env: Environment, program: str) -> None:
"""Display the man page for the given command (http/https)."""
"""
Open the system man page for the given command (http/https/httpie).
"""
subprocess.run(
[MAN_COMMAND, MAN_PAGE_SECTION, program],
stdout=env.stdout,
Expand Down

0 comments on commit 2da955f

Please sign in to comment.