Skip to content

Commit

Permalink
Merge pull request #233 from CycloneDX/fix/issue-230-hang-with-no-rf-…
Browse files Browse the repository at this point in the history
…flag

Fix for hang when no `-rf` flag supplied with `-r` flag
  • Loading branch information
madpah authored Sep 27, 2021
2 parents 5587777 + bb7e30a commit 651b35f
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 28 deletions.
58 changes: 30 additions & 28 deletions cyclonedx_py/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,30 +20,24 @@

import argparse
import os
import sys
from datetime import datetime

from cyclonedx.model.bom import Bom
from cyclonedx.output import BaseOutput, get_instance, OutputFormat, SchemaVersion
from cyclonedx.parser import BaseParser
from cyclonedx.parser.environment import EnvironmentParser
from cyclonedx.parser.requirements import RequirementsParser, RequirementsFileParser
from cyclonedx.parser.requirements import RequirementsFileParser


class CycloneDxCmd:
# Whether debug output is enabled
_DEBUG_ENABLED: bool = False

# Argument Parser
_arg_parser: argparse.ArgumentParser

# Parsed Arguments
_arguments: argparse.Namespace

def __init__(self):
# Build and parse command arguments
self._build_arg_parser()
self._parse_arguments()
def __init__(self, args: argparse.Namespace):
self._arguments = args

if self._arguments.debug_enabled:
self._DEBUG_ENABLED = True
Expand Down Expand Up @@ -71,10 +65,11 @@ def execute(self):
self._debug_message('Will be outputting SBOM to file at: {}'.format(output_filename))
output.output_to_file(filename=output_filename, allow_overwrite=self._arguments.output_file_overwrite)

def _build_arg_parser(self):
self._arg_parser = argparse.ArgumentParser(description='CycloneDX SBOM Generator')
@staticmethod
def get_arg_parser() -> argparse.ArgumentParser:
arg_parser = argparse.ArgumentParser(description='CycloneDX SBOM Generator')

input_group = self._arg_parser.add_mutually_exclusive_group(required=True)
input_group = arg_parser.add_mutually_exclusive_group(required=True)
input_group.add_argument(
'-e', '--e', '--environment', action='store_true',
help='Build a SBOM based on the packages installed in your current Python environment (default)',
Expand All @@ -86,16 +81,16 @@ def _build_arg_parser(self):
dest='input_from_requirements'
)

req_input_group = self._arg_parser.add_argument_group(
req_input_group = arg_parser.add_argument_group(
title='Requirements',
description='Additional optional arguments if you are setting the input type to `requirements`.'
)
req_input_group.add_argument(
'-rf', '--rf', '--requirements-file', action='store', metavar='FILE_PATH',
'-rf', '--rf', '--requirements-file', action='store', metavar='FILE_PATH', default='requirements.txt',
help='Path to a the requirements.txt file you wish to parse', dest='input_requirements_file', required=False
)

output_group = self._arg_parser.add_argument_group(
output_group = arg_parser.add_argument_group(
title='SBOM Output Configuration',
description='Choose the output format and schema version'
)
Expand All @@ -118,7 +113,9 @@ def _build_arg_parser(self):
help='If outputting to a file and the stated file already exists, it will be overwritten.'
)

self._arg_parser.add_argument('-X', action='store_true', help='Enable debug output', dest='debug_enabled')
arg_parser.add_argument('-X', action='store_true', help='Enable debug output', dest='debug_enabled')

return arg_parser

def _debug_message(self, message: str):
if self._DEBUG_ENABLED:
Expand All @@ -133,23 +130,28 @@ def _get_input_parser(self) -> BaseParser:
if self._arguments.input_from_environment:
return EnvironmentParser()
elif self._arguments.input_from_requirements:
if self._arguments.input_requirements_file:
if os.path.exists(self._arguments.input_requirements_file):
# A requirements.txt path was provided
return RequirementsFileParser(requirements_file=self._arguments.input_requirements_file)
else:
self._error_and_exit('The requirements.txt file path provided does not exist ({})'.format(
self._arguments.input_requirements_file
))
# if self._arguments.input_requirements_file:
requirements_file = os.path.realpath(self._arguments.input_requirements_file)
# requirements_file = self._arguments.input_requirements_file
if CycloneDxCmd._validate_requirements_file(self._arguments.input_requirements_file):
# A requirements.txt path was provided
return RequirementsFileParser(requirements_file=requirements_file)
else:
return RequirementsParser(requirements_content=sys.stdin.readlines())
self._error_and_exit('The requirements.txt file path provided does not exist ({})'.format(
requirements_file
))
else:
raise ValueError('Parser type could not be determined.')

def _parse_arguments(self):
self._arguments = self._arg_parser.parse_args()
@staticmethod
def _validate_requirements_file(requirements_file_path: str) -> bool:
return os.path.exists(requirements_file_path)


def main():
CycloneDxCmd().execute()
parser = CycloneDxCmd.get_arg_parser()
args = parser.parse_args()
CycloneDxCmd(args).execute()


if __name__ == "__main__":
Expand Down
17 changes: 17 additions & 0 deletions tests/test_cyclonedx.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
import os.path
import subprocess
import tempfile
from unittest.mock import mock_open, patch

from cyclonedx_py.client import CycloneDxCmd

from base import BaseXmlTestCase

Expand All @@ -30,6 +33,20 @@

class TestCycloneDxXml(BaseXmlTestCase):

def test_run(self):
parser = CycloneDxCmd.get_arg_parser()
with tempfile.TemporaryDirectory() as dirname:
args = parser.parse_args(args=('-r', '-o', os.path.join(dirname, 'sbom.xml')))
with open(os.path.join(FIXTURES_DIRECTORY, 'requirements-simple.txt'), 'r') as req_file:
with patch('builtins.open', mock_open(read_data=req_file.read())) as mock_req_file:
with patch('cyclonedx_py.client.CycloneDxCmd._validate_requirements_file') as mock_exists:
CycloneDxCmd(args).execute()

mock_exists.assert_called_with('requirements.txt')
mock_req_file.assert_called()

req_file.close()

def test_requirements_txt_file(self):
with tempfile.TemporaryDirectory() as dirname:
# Run command to generate latest 1.3 XML SBOM from Requirements File
Expand Down

0 comments on commit 651b35f

Please sign in to comment.