From dafb14426ddbd6d7b0743324c5f1e6588bd4d5b8 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Mon, 16 Sep 2019 11:45:26 +0100 Subject: [PATCH] cli: Expose knobs for date and version Provide a way to override the date and version used in generated man pages. This can be useful where you want to generate man pages before actually releasing something and don't want to manually edit them. Signed-off-by: Stephen Finucane --- click_man/core.py | 23 ++++++++++++++++++----- click_man/shell.py | 21 ++++++++++++++++++--- tests/test_shell.py | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 8 deletions(-) diff --git a/click_man/core.py b/click_man/core.py index de9d93e..fcca91d 100644 --- a/click_man/core.py +++ b/click_man/core.py @@ -26,15 +26,17 @@ def get_short_help_str(command, limit=45): return command.short_help or command.help and click.utils.make_default_short_help(command.help, limit) or '' -def generate_man_page(ctx, version=None): +def generate_man_page(ctx, version=None, date=None): """ Generate documentation for the given command. :param click.Context ctx: the click context for the - cli application. + cli application. + :param str version: The version information to include in the man page. + :param str date: The date information to include in the man page. - :rtype: str :returns: the generate man page from the given click Context. + :rtype: str """ # Create man page with the details from the given context man_page = ManPage(ctx.command_path) @@ -43,6 +45,10 @@ def generate_man_page(ctx, version=None): man_page.description = ctx.command.help man_page.synopsis = ' '.join(ctx.command.collect_usage_pieces(ctx)) man_page.options = [x.get_help_record(ctx) for x in ctx.command.params if isinstance(x, click.Option) and not getattr(x, 'hidden', False)] + + if date: + man_page.date = date + commands = getattr(ctx.command, 'commands', None) if commands: man_page.commands = [ @@ -52,7 +58,9 @@ def generate_man_page(ctx, version=None): return str(man_page) -def write_man_pages(name, cli, parent_ctx=None, version=None, target_dir=None): +def write_man_pages( + name, cli, parent_ctx=None, version=None, target_dir=None, date=None, +): """ Generate man page files recursively for the given click cli function. @@ -62,6 +70,7 @@ def write_man_pages(name, cli, parent_ctx=None, version=None, target_dir=None): :param click.Context parent_ctx: the parent click context :param str target_dir: the directory where the generated man pages are stored. + :param date: the date to include in the header """ ctx = click.Context(cli, info_name=name, parent=parent_ctx) @@ -80,4 +89,8 @@ def write_man_pages(name, cli, parent_ctx=None, version=None, target_dir=None): if command.hidden: # Do not write a man page for a hidden command continue - write_man_pages(name, command, parent_ctx=ctx, version=version, target_dir=target_dir) + + write_man_pages( + name, command, parent_ctx=ctx, version=version, + target_dir=target_dir, date=date, + ) diff --git a/click_man/shell.py b/click_man/shell.py index c8a3181..06587b6 100644 --- a/click_man/shell.py +++ b/click_man/shell.py @@ -9,10 +9,12 @@ :license: MIT, see LICENSE for more details. """ +from datetime import datetime import os -import click from pkg_resources import iter_entry_points, get_distribution +import click + from click_man.core import write_man_pages @@ -22,9 +24,11 @@ type=click.Path(file_okay=False, dir_okay=True, resolve_path=True), help='Target location for the man pages' ) +@click.option('--man-version', help='Version to use in generated man page(s)') +@click.option('--man-date', help='Date to use in generated man page(s)') @click.version_option(get_distribution('click-man').version, '-V', '--version') @click.argument('name') -def cli(target, name): +def cli(target, name, man_version, man_date): """ Generate man pages for the scripts defined in the ``console_scripts`` entry point. @@ -50,6 +54,17 @@ def cli(target, name): except OSError: pass + if not man_version: + man_version = entry_point.dist.version + + if man_date: + try: + datetime.strptime(man_date, '%Y-%m-%d') + except ValueError: + raise click.ClickException( + '"{0}" is not a valid date.'.format(man_date) + ) + click.echo('Load entry point {0}'.format(name)) cli = entry_point.resolve() @@ -81,5 +96,5 @@ def cli(target, name): click.echo('Generate man pages for {0} in {1}'.format(name, target)) write_man_pages( - name, cli, version=entry_point.dist.version, target_dir=target, + name, cli, version=man_version, target_dir=target, date=man_date, ) diff --git a/tests/test_shell.py b/tests/test_shell.py index e3821da..0b90fa2 100644 --- a/tests/test_shell.py +++ b/tests/test_shell.py @@ -50,4 +50,37 @@ def test_is_click_command(mock_entry_points, mock_echo, mock_write): ]) mock_write.assert_called_once_with( 'foo', fake_command, version=fake_version, target_dir=fake_target, + date=None, + ) + + +@mock.patch('os.makedirs', new=mock.Mock()) +@mock.patch.object(shell, 'write_man_pages') +@mock.patch.object(click, 'echo') +@mock.patch.object(shell, 'iter_entry_points') +def test_man_date_version(mock_entry_points, mock_echo, mock_write): + fake_target = os.path.join(os.getcwd(), 'man') + fake_command = click.Command(name='foo') + entry_point = mock.Mock() + entry_point.resolve.return_value = fake_command + + mock_entry_points.return_value = iter([entry_point]) + + runner = CLIRunner() + result = runner.invoke( + shell.cli, + ['foo', '--man-version', '3.2.1', '--man-date', '2020-01-01'], + ) + + assert result.exit_code == 0, result.output + + mock_entry_points.assert_called_once_with('console_scripts', name='foo') + entry_point.dist.version.assert_not_called() + mock_echo.assert_has_calls([ + mock.call('Load entry point foo'), + mock.call('Generate man pages for foo in %s' % fake_target), + ]) + mock_write.assert_called_once_with( + 'foo', fake_command, version='3.2.1', target_dir=fake_target, + date='2020-01-01', )