Skip to content

Commit

Permalink
Merge pull request #257 from CycloneDX/fix/256-no-default-file-when-n…
Browse files Browse the repository at this point in the history
…o-input-on-stdin

FIX: Fallback to default manifest names in current directory when no `-i` supplied and nothing piped in via STDIN
  • Loading branch information
madpah authored Nov 12, 2021
2 parents 6924dac + 47612e6 commit c0f0766
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 4 deletions.
28 changes: 26 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,26 @@ You can then run `cyclonedx-bom` as follows:
cyclonedx-bom -p -i PATH/TO/poetry.lock -o sbom.xml
```

#### Pip / Requirements
If your `poetry.lock` is in the current working directory, you can also shorten this to:
```
cyclonedx-bom -p -o sbom.xml
```

#### Pip

We currently support `Pipfile.lock` manifest files.

You can then run `cyclonedx-bom` as follows:
```
cyclonedx-bom -pip -i PATH/TO/Pipfile.lock -o sbom.xml
```

If your `Pipfile.lock` is in the current working directory, you can also shorten this to:
```
cyclonedx-bom -pip -o sbom.xml
```

#### Requirements

We currently support `requirements.txt` manifest files. Note that a BOM such as CycloneDX expects exact version numbers,
therefore if you wish to generate a BOM from a `requirements.txt`, these must be frozen. This can be accomplished via:
Expand All @@ -144,11 +163,16 @@ therefore if you wish to generate a BOM from a `requirements.txt`, these must be
pip freeze > requirements.txt
```

You can then run `cyclonedx-py` as follows:
You can then run `cyclonedx-bom` as follows:
```
cyclonedx-bom -r -i PATH/TO/requirements.txt -o sbom.xml
```

If your `requirements.txt` is in the current working directory, you can also shorten this to:
```
cyclonedx-bom -r -o sbom.xml
```

This will generate a CycloneDX and output to STDOUT in XML using the latest schema version `1.3` by default.

**Note:** If you failed to freeze your dependencies before passing the `requirements.txt` data to `cyclonedx-bom`,
Expand Down
42 changes: 40 additions & 2 deletions cyclonedx_py/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@
from cyclonedx.parser.requirements import RequirementsParser


class CycloneDxCmdException(Exception):
pass


class CycloneDxCmdNoInputFileSupplied(CycloneDxCmdException):
pass


class CycloneDxCmd:
# Whether debug output is enabled
_DEBUG_ENABLED: bool = False
Expand All @@ -49,7 +57,14 @@ def __init__(self, args: argparse.Namespace):
self._debug_message('Parsed Arguments: {}'.format(self._arguments))

def get_output(self) -> BaseOutput:
parser = self._get_input_parser()
try:
parser = self._get_input_parser()
except CycloneDxCmdNoInputFileSupplied as e:
print(f'ERROR: {str(e)}')
exit(1)
except CycloneDxCmdException as e:
print(f'ERROR: {str(e)}')
exit(1)

if parser.has_warnings():
print('')
Expand Down Expand Up @@ -186,6 +201,29 @@ def _get_input_parser(self) -> BaseParser:
return EnvironmentParser()

# All other Parsers will require some input - grab it now!
if not self._arguments.input_source:
# Nothing passed via STDIN, and no FILENAME supplied, let's assume a default by input type for ease
current_directory = os.getcwd()
try:
if self._arguments.input_from_conda_explicit:
raise CycloneDxCmdNoInputFileSupplied('When using input from Conda Explicit, you need to pipe input'
'via STDIN')
elif self._arguments.input_from_conda_json:
raise CycloneDxCmdNoInputFileSupplied('When using input from Conda JSON, you need to pipe input'
'via STDIN')
elif self._arguments.input_from_pip:
self._arguments.input_source = open(os.path.join(current_directory, 'Pipfile.lock'), 'r')
elif self._arguments.input_from_poetry:
self._arguments.input_source = open(os.path.join(current_directory, 'poetry.lock'), 'r')
elif self._arguments.input_from_requirements:
self._arguments.input_source = open(os.path.join(current_directory, 'requirements.txt'), 'r')
else:
raise CycloneDxCmdException('Parser type could not be determined.')
except FileNotFoundError as e:
raise CycloneDxCmdNoInputFileSupplied(
f'No input file was supplied and no input was provided on STDIN:\n{str(e)}'
)

input_data_fh = self._arguments.input_source
with input_data_fh:
input_data = input_data_fh.read()
Expand All @@ -202,7 +240,7 @@ def _get_input_parser(self) -> BaseParser:
elif self._arguments.input_from_requirements:
return RequirementsParser(requirements_content=input_data)
else:
raise ValueError('Parser type could not be determined.')
raise CycloneDxCmdException('Parser type could not be determined.')


def main():
Expand Down

0 comments on commit c0f0766

Please sign in to comment.