diff --git a/docs/cli.md b/docs/cli.md index 5b36675..7d5fb6e 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -6,16 +6,25 @@ The following are the command's options and arguments: ``` Usage: xrlint [OPTIONS] [FILES]... - Lint the given FILES. + Lint the given dataset FILES. + + Reads configuration from `./xrlint.config.py` if `--no-default-config` is + not set and `--config PATH` is not provided, then validates each dataset in + FILES against the configuration. The validation result is dumped to standard + output if not otherwise stated by `--output-file PATH`. The output format is + `simple`. Other inbuilt formats are `json` and `html` which can by setting + the `--format NAME` option. Options: - --no-default-config Disable use of default configuration from - xrlint.config.* - -c, --config PATH Use this configuration, overriding xrlint.config.* - config options if present - -f, --format NAME Use a specific output format - default: simple - --max-warnings COUNT Number of warnings to trigger nonzero exit code - - default: -1 - --version Show the version and exit. - --help Show this message and exit. + --no-default-config Disable use of default configuration from + xrlint.config.* + -c, --config PATH Use this configuration, overriding xrlint.config.* + config options if present + -f, --format NAME Use a specific output format - default: simple + -o, --output-file PATH Specify file to write report to + --max-warnings COUNT Number of warnings to trigger nonzero exit code - + default: -1 + --version Show the version and exit. + --help Show this message and exit. + ``` diff --git a/tests/cli/test_main.py b/tests/cli/test_main.py index b2a70be..61a0d37 100644 --- a/tests/cli/test_main.py +++ b/tests/cli/test_main.py @@ -58,6 +58,11 @@ def test_default_config(self): finally: os.remove("xrlint.config.json") + def test_output_file(self): + runner = CliRunner() + result = runner.invoke(main, ["-o", "memory://report.txt"] + self.files) + self.assertEqual(result.exit_code, 0) + def test_config_missing(self): runner = CliRunner() result = runner.invoke(main, ["-c", "pippo.py"] + self.files) diff --git a/xrlint/cli/engine.py b/xrlint/cli/engine.py index 6dcd003..bbe73a5 100644 --- a/xrlint/cli/engine.py +++ b/xrlint/cli/engine.py @@ -1,4 +1,5 @@ import click +import fsspec from xrlint.cli.config import read_config from xrlint.cli.constants import CONFIG_DEFAULT_FILENAMES @@ -20,20 +21,19 @@ def __init__( no_default_config: int = False, config_path: str | None = None, output_format: str = DEFAULT_OUTPUT_FORMAT, + output_path: str | None = None, files: list[str] | None = None, recommended: bool = True, ): - from xrlint.plugins.core import export_plugin as import_core_plugin - from xrlint.plugins.xcube import export_plugin as import_xcube_plugin - self.no_default_config = no_default_config self.config_path = config_path self.output_format = output_format + self.output_path = output_path self.files = files self.base_config = get_base_config(recommended=recommended) self.config_list = ConfigList([self.base_config]) - def load_config(self): + def load_config(self) -> None: config_list = None if self.config_path: @@ -83,3 +83,10 @@ def format_results(self, results: list[Result]) -> str: ) # TODO: pass format-specific args/kwargs return formatter.op_class().format(FormatterContext(False), results) + + def write_report(self, report: str): + if not self.output_path: + print(report) + else: + with fsspec.open(self.output_path, mode="w") as f: + f.write(report) diff --git a/xrlint/cli/main.py b/xrlint/cli/main.py index 34dc16f..79a1a4b 100644 --- a/xrlint/cli/main.py +++ b/xrlint/cli/main.py @@ -35,12 +35,19 @@ default=DEFAULT_OUTPUT_FORMAT, metavar="NAME", ) +@click.option( + "-o", + "--output-file", + "output_file", + help=f"Specify file to write report to", + metavar="PATH", +) @click.option( "--max-warnings", "max_warnings", help=( f"Number of warnings to trigger nonzero exit code" - f" - default: {DEFAULT_MAX_WARNINGS})" + f" - default: {DEFAULT_MAX_WARNINGS}" ), type=int, default=DEFAULT_MAX_WARNINGS, @@ -54,9 +61,19 @@ def main( config_path: str | None, max_warnings: int, output_format: str, + output_file: str | None, files: list[str] | None, ): - """Lint the given FILES.""" + """Lint the given dataset FILES. + + Reads configuration from `./xrlint.config.py` if `--no-default-config` + is not set and `--config PATH` is not provided, then validates + each dataset in FILES against the configuration. + The validation result is dumped to standard output if not otherwise + stated by `--output-file PATH`. The output format is `simple`. Other + inbuilt formats are `json` and `html` which can by setting the + `--format NAME` option. + """ from xrlint.cli.engine import CliEngine cli_engine = CliEngine( @@ -64,12 +81,13 @@ def main( config_path=config_path, files=files, output_format=output_format, + output_path=output_file, ) cli_engine.load_config() results = cli_engine.verify_datasets() - output_text = cli_engine.format_results(results) - print(output_text) + report = cli_engine.format_results(results) + cli_engine.write_report(report) errors = sum(r.error_count for r in results) warnings = sum(r.warning_count for r in results)