diff --git a/CHANGELOG.md b/CHANGELOG.md index 9610f082..cb9699e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ **Implemented enhancements:** - Add dependency security checks in CI [\#1488](https://github.com/jrnl-org/jrnl/issues/1488) +- Add machine-readable format for --list [\#1445](https://github.com/jrnl-org/jrnl/issues/1445) +- Add machine readable --list output [\#1592](https://github.com/jrnl-org/jrnl/pull/1592) ([apainintheneck](https://github.com/apainintheneck)) **Build:** diff --git a/jrnl/args.py b/jrnl/args.py index 4b2ba8ce..c6b0f1a0 100644 --- a/jrnl/args.py +++ b/jrnl/args.py @@ -85,7 +85,13 @@ def parse_args(args=[]): action="store_const", const=postconfig_list, dest="postconfig_cmd", - help="List all configured journals", + help=""" + List all configured journals. + + Optional parameters: + + --format [json or yaml] + """, ) standalone.add_argument( "--ls", diff --git a/jrnl/commands.py b/jrnl/commands.py index af373531..02446b77 100644 --- a/jrnl/commands.py +++ b/jrnl/commands.py @@ -56,10 +56,10 @@ def preconfig_version(_): print(output) -def postconfig_list(config, **kwargs): +def postconfig_list(args, config, **kwargs): from jrnl.output import list_journals - print(list_journals(config)) + print(list_journals(config, args.export)) def postconfig_import(args, config, **kwargs): diff --git a/jrnl/output.py b/jrnl/output.py index 4b18a344..d512415a 100644 --- a/jrnl/output.py +++ b/jrnl/output.py @@ -25,19 +25,50 @@ def deprecated_cmd(old_cmd, new_cmd, callback=None, **kwargs): callback(**kwargs) -def list_journals(configuration): - from jrnl import config +def journal_list_to_json(journal_list): + import json - """List the journals specified in the configuration file""" - result = f"Journals defined in config ({config.get_config_path()})\n" - ml = min(max(len(k) for k in configuration["journals"]), 20) - for journal, cfg in configuration["journals"].items(): + return json.dumps(journal_list) + + +def journal_list_to_yaml(journal_list): + from io import StringIO + + from ruamel.yaml import YAML + + output = StringIO() + YAML().dump(journal_list, output) + return output.getvalue() + + +def journal_list_to_stdout(journal_list): + result = f"Journals defined in config ({journal_list['config_path']})\n" + ml = min(max(len(k) for k in journal_list["journals"]), 20) + for journal, cfg in journal_list["journals"].items(): result += " * {:{}} -> {}\n".format( journal, ml, cfg["journal"] if isinstance(cfg, dict) else cfg ) return result +def list_journals(configuration, format=None): + from jrnl import config + + """List the journals specified in the configuration file""" + + journal_list = { + "config_path": config.get_config_path(), + "journals": configuration["journals"], + } + + if format == "json": + return journal_list_to_json(journal_list) + elif format == "yaml": + return journal_list_to_yaml(journal_list) + else: + return journal_list_to_stdout(journal_list) + + def print_msg(msg: Message, **kwargs) -> None | str: """Helper function to print a single message""" kwargs["style"] = msg.style diff --git a/tests/bdd/features/format.feature b/tests/bdd/features/format.feature index 8e395d05..2cc7d9a1 100644 --- a/tests/bdd/features/format.feature +++ b/tests/bdd/features/format.feature @@ -597,3 +597,18 @@ Feature: Custom formats When we run "jrnl --format text --file {cache_dir}" Then the cache directory should contain 5 files And we should get no error + + Scenario: Export journal list to multiple formats. + Given we use the config "basic_onefile.yaml" + When we run "jrnl --list" + Then the output should match + Journals defined in config \(.+basic_onefile\.yaml\) + \* default -> features/journals/basic_onefile\.journal + When we run "jrnl --list --format json" + Then the output should match + {"config_path": ".+basic_onefile\.yaml", "journals": {"default": "features/journals/basic_onefile\.journal"}} + When we run "jrnl --list --format yaml" + Then the output should match + config_path: .+basic_onefile\.yaml + journals: + default: features/journals/basic_onefile\.journal diff --git a/tests/lib/then_steps.py b/tests/lib/then_steps.py index 28bc41cf..cb7e9766 100644 --- a/tests/lib/then_steps.py +++ b/tests/lib/then_steps.py @@ -23,6 +23,7 @@ def should_get_no_error(cli_run): assert cli_run["status"] == 0, cli_run["status"] +@then(parse("the output should match\n{regex}")) @then(parse('the output should match "{regex}"')) def output_should_match(regex, cli_run): out = cli_run["stdout"]