Skip to content

Commit 0571730

Browse files
committed
Fixed #584 - Add support for the special '-' FILE
* The `inventory` can now used `-` to print result to stdout. * Updated docs and changelog. Signed-off-by: Chin Yeung Li <[email protected]>
1 parent 126e636 commit 0571730

File tree

8 files changed

+98
-18
lines changed

8 files changed

+98
-18
lines changed

-

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
[
2+
{
3+
"about_resource": "/aboutcode-toolkit/",
4+
"name": "AboutCode-toolkit",
5+
"version": "11.1.0",
6+
"description": "AboutCode Toolkit is a tool to process ABOUT files. An ABOUT file\nprovides a simple way to document the provenance (origin and license)\n'about' a software component. This is a small text file stored in the\ncodebase side-by-side with the documented software component.",
7+
"homepage_url": "http://www.nexb.com/community.html",
8+
"license_expression": "apache-2.0",
9+
"spdx_license_key": [
10+
"Apache-2.0"
11+
],
12+
"copyright": "Copyright (c) nexB Inc.",
13+
"notice_file": "NOTICE",
14+
"owner": "nexB Inc.",
15+
"author": "Jillian Daguil, Chin Yeung Li, Philippe Ombredanne, Thomas Druez",
16+
"vcs_tool": "git",
17+
"vcs_repository": "https://github.com/nexB/aboutcode-toolkit.git",
18+
"licenses": [
19+
{
20+
"key": "apache-2.0",
21+
"name": "Apache License 2.0",
22+
"file": "apache-2.0.LICENSE",
23+
"url": "https://enterprise.dejacode.com/urn/?urn=urn:dje:license:apache-2.0"
24+
}
25+
]
26+
}
27+
]

CHANGELOG.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ xxxx-xx-xx
66

77
* Drop support for python version earlier than 3.9
88
* Add ability to "exclude" path in the check and inventory #583
9+
* Add support for the special '-' FILE to print to on screen/to stdout in inventory #584
910

1011
2024-09-16
1112
Release 11.0.2

docs/source/reference.rst

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -586,7 +586,9 @@ Syntax
586586
about inventory [OPTIONS] LOCATION OUTPUT
587587
588588
LOCATION: Path to an ABOUT file or a directory with ABOUT files.
589-
OUTPUT: Path to the CSV/JSON/XLSX inventory file to create.
589+
OUTPUT: Path to the CSV/JSON/XLSX inventory file to create, or using '-' to
590+
print result on screen/to stdout (Excel-formatted output cannot be used in
591+
stdout).
590592
591593
Options
592594
-------
@@ -603,19 +605,27 @@ Options
603605
Purpose
604606
-------
605607

606-
Create a JSON/CSV/XLSX inventory of components from ABOUT files.
608+
Create a JSON/CSV/XLSX inventory of components from ABOUT files, or use `-` to print result to stdout.
607609

608610
Details
609611
^^^^^^^
610612

611613
.. code-block:: none
612614
615+
--exclude PATTERN
616+
617+
Exclude the processing of the specified input pattern
618+
619+
$ about inventory --exclude "tests*" LOCATION OUTPUT
620+
613621
-f, --format [json|csv|excel]
614622
615623
Set OUTPUT file format. [default: csv]
616624
617625
$ about inventory -f json LOCATION OUTPUT
618626
627+
$ about inventory -f json LOCATION -
628+
619629
--verbose
620630
621631
This option tells the tool to show all errors found.

src/attributecode/cmd.py

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -143,16 +143,15 @@ def validate_extensions(ctx, param, value, extensions=tuple(('.csv', '.json',)))
143143

144144

145145
@about.command(cls=AboutCommand,
146-
short_help='Collect the inventory of .ABOUT files to a CSV/JSON/XLSX file.')
146+
short_help='Collect the inventory of .ABOUT files to a CSV/JSON/XLSX file or stdout.')
147147
@click.argument('location',
148148
required=True,
149149
metavar='LOCATION',
150150
type=click.Path(
151151
exists=True, file_okay=True, dir_okay=True, readable=True, resolve_path=True))
152152
@click.argument('output',
153153
required=True,
154-
metavar='OUTPUT',
155-
type=click.Path(exists=False, dir_okay=False, writable=True, resolve_path=True))
154+
metavar='OUTPUT')
156155
@click.option('--exclude',
157156
multiple=True,
158157
metavar='PATTERN',
@@ -176,8 +175,25 @@ def inventory(location, output, exclude, format, quiet, verbose): # NOQA
176175
177176
LOCATION: Path to an ABOUT file or a directory with ABOUT files.
178177
179-
OUTPUT: Path to the CSV/JSON/XLSX inventory file to create.
178+
OUTPUT: Path to the CSV/JSON/XLSX inventory file to create, or
179+
using '-' to print result on screen/to stdout (Excel-formatted output
180+
cannot be used in stdout).
180181
"""
182+
# We are not using type=click.Path() to validate the output location as
183+
# it does not support `-` , which is used to print the result to stdout.
184+
if not output == '-':
185+
parent_dir = os.path.dirname(output)
186+
if not os.path.exists(parent_dir):
187+
msg = 'The OUTPUT directory: {parent_dir} does not exist.'.format(**locals())
188+
msg += '\nPlease correct and re-run'
189+
click.echo(msg)
190+
sys.exit(1)
191+
else:
192+
# Check the format if output is stdout as xlsx format cannot be displayed.
193+
if format == 'excel':
194+
msg = 'Excel-formatted output cannot be used in stdout.'
195+
click.echo(msg)
196+
sys.exit(0)
181197
if not quiet:
182198
print_version()
183199
click.echo('Collecting inventory from ABOUT files...')
@@ -188,9 +204,13 @@ def inventory(location, output, exclude, format, quiet, verbose): # NOQA
188204
errors, abouts = collect_inventory(location, exclude)
189205
write_output(abouts=abouts, location=output, format=format)
190206

207+
if output == '-':
208+
log_file_loc = None
209+
else:
210+
log_file_loc = output + '-error.log'
191211
errors_count = report_errors(
192-
errors, quiet, verbose, log_file_loc=output + '-error.log')
193-
if not quiet:
212+
errors, quiet, verbose, log_file_loc)
213+
if not quiet and not output == '-':
194214
msg = 'Inventory collected in {output}.'.format(**locals())
195215
click.echo(msg)
196216
sys.exit(errors_count)

src/attributecode/model.py

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import os
2929
import posixpath
3030
from requests import get, head, exceptions
31+
import sys
3132
import traceback
3233
from itertools import zip_longest
3334

@@ -1849,7 +1850,8 @@ def write_output(abouts, location, format): # NOQA
18491850
Return a list of Error objects.
18501851
"""
18511852
about_dicts = about_object_to_list_of_dictionary(abouts)
1852-
location = add_unc(location)
1853+
if not location == '-':
1854+
location = add_unc(location)
18531855
if format == 'csv':
18541856
save_as_csv(location, about_dicts, get_field_names(abouts))
18551857
elif format == 'json':
@@ -1859,21 +1861,40 @@ def write_output(abouts, location, format): # NOQA
18591861

18601862

18611863
def save_as_json(location, about_dicts):
1862-
with open(location, mode='w') as output_file:
1863-
data = util.format_about_dict_for_json_output(about_dicts)
1864-
output_file.write(json.dumps(data, indent=2))
1864+
"""
1865+
Save the given data as a JSON file or print it to standard output.
1866+
"""
1867+
data = util.format_about_dict_for_json_output(about_dicts)
1868+
if location == '-':
1869+
json.dump(data, sys.stdout, indent=2)
1870+
else:
1871+
with open(location, mode='w') as output_file:
1872+
output_file.write(json.dumps(data, indent=2))
18651873

18661874

18671875
def save_as_csv(location, about_dicts, field_names):
1868-
with open(location, mode='w', encoding='utf-8', newline='', errors='replace') as output_file:
1869-
writer = csv.DictWriter(output_file, field_names)
1876+
"""
1877+
Save the given data as a CSV file or print it to standard output.
1878+
"""
1879+
if location == '-':
1880+
writer = csv.DictWriter(sys.stdout, field_names)
18701881
writer.writeheader()
18711882
csv_formatted_list = util.format_about_dict_output(about_dicts)
18721883
for row in csv_formatted_list:
18731884
writer.writerow(row)
1885+
else:
1886+
with open(location, mode='w', encoding='utf-8', newline='', errors='replace') as output_file:
1887+
writer = csv.DictWriter(output_file, field_names)
1888+
writer.writeheader()
1889+
csv_formatted_list = util.format_about_dict_output(about_dicts)
1890+
for row in csv_formatted_list:
1891+
writer.writerow(row)
18741892

18751893

18761894
def save_as_excel(location, about_dicts):
1895+
"""
1896+
Save the given data as a Excel file.
1897+
"""
18771898
formatted_list = util.format_about_dict_output(about_dicts)
18781899
write_excel(location, formatted_list)
18791900

tests/test_cmd.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,6 @@ def check_about_stdout(options, expected_loc, regen=False):
334334
with open(expected_file, 'r') as ef:
335335
expected = ef.read()
336336

337-
print("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
338337
print(result.output)
339338
assert expected.splitlines(False) == result.output.splitlines(False)
340339

tests/testdata/test_cmd/help/about_help.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,6 @@ Commands:
2222
gen-license Fetch and save all the licenses in the license_expression
2323
field to a directory.
2424
inventory Collect the inventory of .ABOUT files to a CSV/JSON/XLSX
25-
file.
25+
file or stdout.
2626
transform Transform a CSV/JSON/XLSX by applying renamings, filters
27-
and checks.
27+
and checks.

tests/testdata/test_cmd/help/about_inventory_help.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ Usage: about inventory [OPTIONS] LOCATION OUTPUT
44

55
LOCATION: Path to an ABOUT file or a directory with ABOUT files.
66

7-
OUTPUT: Path to the CSV/JSON/XLSX inventory file to create.
7+
OUTPUT: Path to the CSV/JSON/XLSX inventory file to create, or using '-' to
8+
print result on screen/to stdout (Excel-formatted output cannot be used in
9+
stdout).
810

911
Options:
1012
--exclude PATTERN Exclude the processing of the specified input

0 commit comments

Comments
 (0)