From 4a56b750686a320eee23b9351dc7d4465c87a448 Mon Sep 17 00:00:00 2001 From: Joachim Metz Date: Wed, 21 Feb 2024 19:24:41 +0100 Subject: [PATCH] Changed tools to entry points #4769 (#4811) --- config/end-to-end.ini | 14 ++++----- config/end_to_end/run_tests_with_docker.sh | 4 +-- config/jenkins/linux/run_end_to_end_tests.sh | 2 +- .../user/Log2Timeline-Perl-(Legacy).md | 4 +-- {tools => plaso/scripts}/__init__.py | 0 {tools => plaso/scripts}/image_export.py | 27 ++++++++--------- {tools => plaso/scripts}/log2timeline.py | 29 ++++++++++--------- {tools => plaso/scripts}/pinfo.py | 28 ++++++++++-------- {tools => plaso/scripts}/psort.py | 27 ++++++++--------- {tools => plaso/scripts}/psteal.py | 29 ++++++++++--------- setup.cfg | 14 +++++---- tests/end-to-end.py | 11 +++---- tox.ini | 4 +-- 13 files changed, 100 insertions(+), 93 deletions(-) rename {tools => plaso/scripts}/__init__.py (100%) rename {tools => plaso/scripts}/image_export.py (87%) rename {tools => plaso/scripts}/log2timeline.py (89%) rename {tools => plaso/scripts}/pinfo.py (86%) rename {tools => plaso/scripts}/psort.py (89%) rename {tools => plaso/scripts}/psteal.py (88%) diff --git a/config/end-to-end.ini b/config/end-to-end.ini index c51f862ec9..fa97fead1c 100644 --- a/config/end-to-end.ini +++ b/config/end-to-end.ini @@ -18,7 +18,7 @@ source=test_data/vsstest.qcow2 [extract_and_output1] case=extract_and_output -extract_options=--no-vss +extract_options=--vss_stores=none output_file=extract_and_output1.log output_format=dynamic output_options=--dynamic-time @@ -27,7 +27,7 @@ source=test_data/vsstest.qcow2 [extract_and_output2] case=extract_and_output -extract_options=--no-vss +extract_options=--vss_stores=none output_file=extract_and_output2.log output_format=dynamic output_options=--additional-fields=myfield --dynamic-time @@ -36,7 +36,7 @@ source=test_data/vsstest.qcow2 [extract_and_output3] case=extract_and_output -extract_options=--no-vss +extract_options=--vss_stores=none output_file=extract_and_output3.log output_format=dynamic output_options=--custom-fields=custom:MyField --dynamic-time @@ -45,7 +45,7 @@ source=test_data/vsstest.qcow2 [extract_and_output4] case=extract_and_output_with_psteal -extract_options=--no-vss +extract_options=--vss_stores=none output_file=extract_and_output4.log output_format=dynamic output_options=--dynamic-time @@ -54,7 +54,7 @@ source=test_data/vsstest.qcow2 [extract_and_output5] case=extract_and_output -extract_options=--no-vss +extract_options=--vss_stores=none output_file=extract_and_output5.log output_format=dynamic output_options=--dynamic-time @@ -64,7 +64,7 @@ source=test_data/vsstest.qcow2 [extract_and_output_empty] case=extract_and_output -extract_options=--no-vss --parsers=bodyfile +extract_options=--parsers=bodyfile --vss_stores=none output_file=extract_and_output_empty.log output_format=dynamic output_options=--dynamic-time @@ -89,7 +89,7 @@ source=test_data/syslog.zip [extract_and_output_no_hashers1] case=extract_and_output -extract_options=--no-vss --hashers=none +extract_options=--hashers=none --vss_stores=none output_file=extract_and_output_no_hashers1.log output_format=dynamic output_options=--dynamic-time diff --git a/config/end_to_end/run_tests_with_docker.sh b/config/end_to_end/run_tests_with_docker.sh index 95c1a2857d..774f2784d4 100755 --- a/config/end_to_end/run_tests_with_docker.sh +++ b/config/end_to_end/run_tests_with_docker.sh @@ -69,7 +69,7 @@ do # Note that output is mapped to /home/test/plaso/plaso-out to ensure files # created by the end-to-end.py script are stored outside the container. - COMMAND="./tests/end-to-end.py --config /config/${TEST_NAME}.ini --references-directory test_data/end_to_end --results-directory plaso-out --sources-directory /sources --tools-directory ./tools"; + COMMAND="./tests/end-to-end.py --config /config/${TEST_NAME}.ini --references-directory test_data/end_to_end --results-directory plaso-out --sources-directory /sources --scripts-directory plaso/scripts"; # TODO: move custom test setup and teardown scripts to configuration parameter? @@ -81,7 +81,7 @@ do if [[ ${TEST_NAME} == "acserver-mounted" ]]; then - COMMAND="mkdir -p /mnt/acserver_mount && mount -o ro,noload,noacl,loop,offset=1048576 /sources/acserver.dd /mnt/acserver_mount && ./tests/end-to-end.py --config /config/${TEST_NAME}.ini --references-directory test_data/end_to_end --results-directory plaso-out --sources-directory /mnt --tools-directory ./tools && umount /mnt/acserver_mount && rmdir /mnt/acserver_mount"; + COMMAND="mkdir -p /mnt/acserver_mount && mount -o ro,noload,noacl,loop,offset=1048576 /sources/acserver.dd /mnt/acserver_mount && ./tests/end-to-end.py --config /config/${TEST_NAME}.ini --references-directory test_data/end_to_end --results-directory plaso-out --sources-directory /mnt --scripts-directory plaso/scripts && umount /mnt/acserver_mount && rmdir /mnt/acserver_mount"; elif [[ ${TEST_NAME} == *\-nsrlsvr ]]; then diff --git a/config/jenkins/linux/run_end_to_end_tests.sh b/config/jenkins/linux/run_end_to_end_tests.sh index 3e8124ca51..07df627d73 100755 --- a/config/jenkins/linux/run_end_to_end_tests.sh +++ b/config/jenkins/linux/run_end_to_end_tests.sh @@ -43,7 +43,7 @@ PYTHONPATH=. python3 ./utils/check_dependencies.py # Start the end-to-end tests in the background so we can capture the PID of # the process while the script is running. -PYTHONPATH=. python3 ./tests/end-to-end.py --config ${CONFIGURATION_FILE} --sources-directory ${SOURCES_DIRECTORY} --tools-directory ./tools --results-directory ${RESULTS_DIRECTORY} --references-directory ${REFERENCES_DIRECTORY} & +PYTHONPATH=. python3 ./tests/end-to-end.py --config ${CONFIGURATION_FILE} --sources-directory ${SOURCES_DIRECTORY} --scripts-directory plaso/scripts --results-directory ${RESULTS_DIRECTORY} --references-directory ${REFERENCES_DIRECTORY} & PID_COMMAND=$!; diff --git a/docs/sources/user/Log2Timeline-Perl-(Legacy).md b/docs/sources/user/Log2Timeline-Perl-(Legacy).md index 15f2898e66..43bb908c4b 100644 --- a/docs/sources/user/Log2Timeline-Perl-(Legacy).md +++ b/docs/sources/user/Log2Timeline-Perl-(Legacy).md @@ -109,8 +109,8 @@ none will be processed. You can abort with Ctrl^C. ``` The options can also be supplied on the command line, `--vss_stores '1,2'` for -defining the VSS stores to parse, or `--no-vss` or `-vss-stores all` for -processing all VSS stores. +defining the VSS stores to parse, or `--vss_stores=none` or `-vss-stores=all` +for respectively processing no or all VSS stores. This can be achieved without calculating the offset into the disk image. diff --git a/tools/__init__.py b/plaso/scripts/__init__.py similarity index 100% rename from tools/__init__.py rename to plaso/scripts/__init__.py diff --git a/tools/image_export.py b/plaso/scripts/image_export.py similarity index 87% rename from tools/image_export.py rename to plaso/scripts/image_export.py index c37ce92aaf..c8a9b87f4c 100755 --- a/tools/image_export.py +++ b/plaso/scripts/image_export.py @@ -13,15 +13,15 @@ def Main(): - """The main function. + """Entry point of console script to extract files from images. Returns: - bool: True if successful or False otherwise. + int: exit code that is provided to sys.exit(). """ tool = image_export_tool.ImageExportTool() if not tool.ParseArguments(sys.argv[1:]): - return False + return 1 if tool.show_troubleshooting: print('Using Python version {0!s}'.format(sys.version)) @@ -34,12 +34,12 @@ def Main(): print('Also see: https://plaso.readthedocs.io/en/latest/sources/user/' 'Troubleshooting.html') - return True + return 0 try: tool.CheckOutDated() except KeyboardInterrupt: - return False + return 1 if tool.list_signature_identifiers: try: @@ -48,9 +48,9 @@ def Main(): # BadConfigOption will be raised if signatures.conf cannot be found. except errors.BadConfigOption as exception: logging.warning(exception) - return False + return 1 - return True + return 0 if not tool.has_filters: logging.warning('No filter defined exporting all files.') @@ -68,20 +68,20 @@ def Main(): except (KeyboardInterrupt, errors.UserAbort): logging.warning('Aborted by user.') - return False + return 1 except errors.BadConfigOption as exception: logging.warning(exception) - return False + return 1 except errors.SourceScannerError as exception: logging.warning(( 'Unable to scan for a supported file system with error: {0!s}\n' 'Most likely the image format is not supported by the ' 'tool.').format(exception)) - return False + return 1 - return True + return 0 if __name__ == '__main__': @@ -89,7 +89,4 @@ def Main(): # https://github.com/pyinstaller/pyinstaller/wiki/Recipe-Multiprocessing multiprocessing.freeze_support() - if not Main(): - sys.exit(1) - else: - sys.exit(0) + sys.exit(Main()) diff --git a/tools/log2timeline.py b/plaso/scripts/log2timeline.py similarity index 89% rename from tools/log2timeline.py rename to plaso/scripts/log2timeline.py index a852ccd55d..684bfc4b2e 100755 --- a/tools/log2timeline.py +++ b/plaso/scripts/log2timeline.py @@ -13,11 +13,15 @@ def Main(): - """The main function.""" + """Entry point of console script to extract events. + + Returns: + int: exit code that is provided to sys.exit(). + """ tool = log2timeline_tool.Log2TimelineTool() if not tool.ParseArguments(sys.argv[1:]): - return False + return 1 if tool.show_troubleshooting: print('Using Python version {0!s}'.format(sys.version)) @@ -30,16 +34,16 @@ def Main(): print('Also see: https://plaso.readthedocs.io/en/latest/sources/user/' 'Troubleshooting.html') - return True + return 0 try: tool.CheckOutDated() except KeyboardInterrupt: - return False + return 1 if tool.show_info: tool.ShowInfo() - return True + return 0 have_list_option = False if tool.list_archive_types: @@ -67,11 +71,11 @@ def Main(): have_list_option = True if have_list_option: - return True + return 0 if tool.dependencies_check and not dependencies.CheckDependencies( verbose_output=False): - return False + return 1 try: tool.ExtractEventsFromSources() @@ -83,16 +87,16 @@ def Main(): except (KeyboardInterrupt, errors.UserAbort): logging.warning('Aborted by user.') - return False + return 1 except (IOError, errors.BadConfigOption, errors.SourceScannerError) as exception: # Display message on stdout as well as the log file. print(exception) logging.error(exception) - return False + return 1 - return True + return 0 if __name__ == '__main__': @@ -100,7 +104,4 @@ def Main(): # https://github.com/pyinstaller/pyinstaller/wiki/Recipe-Multiprocessing multiprocessing.freeze_support() - if not Main(): - sys.exit(1) - else: - sys.exit(0) + sys.exit(Main()) diff --git a/tools/pinfo.py b/plaso/scripts/pinfo.py similarity index 86% rename from tools/pinfo.py rename to plaso/scripts/pinfo.py index bfca01b01b..3db8527911 100755 --- a/tools/pinfo.py +++ b/plaso/scripts/pinfo.py @@ -16,11 +16,15 @@ def Main(): - """The main function.""" + """Entry point of console script to provide information about extracted data. + + Returns: + int: exit code that is provided to sys.exit(). + """ tool = pinfo_tool.PinfoTool() if not tool.ParseArguments(sys.argv[1:]): - return False + return 1 if tool.show_troubleshooting: print('Using Python version {0!s}'.format(sys.version)) @@ -33,12 +37,12 @@ def Main(): print('Also see: https://plaso.readthedocs.io/en/latest/sources/user/' 'Troubleshooting.html') - return True + return 0 try: tool.CheckOutDated() except KeyboardInterrupt: - return False + return 1 have_list_option = False if tool.list_reports: @@ -50,7 +54,7 @@ def Main(): have_list_option = True if have_list_option: - return True + return 0 result = True try: @@ -68,13 +72,16 @@ def Main(): except (KeyboardInterrupt, errors.UserAbort): logging.warning('Aborted by user.') - return False + return 1 except errors.BadConfigOption as exception: logging.warning(exception) - return False + return 1 + + if not result: + return 1 - return result + return 0 if __name__ == '__main__': @@ -82,7 +89,4 @@ def Main(): # https://github.com/pyinstaller/pyinstaller/wiki/Recipe-Multiprocessing multiprocessing.freeze_support() - if not Main(): - sys.exit(1) - else: - sys.exit(0) + sys.exit(Main()) diff --git a/tools/psort.py b/plaso/scripts/psort.py similarity index 89% rename from tools/psort.py rename to plaso/scripts/psort.py index e12299e007..379ffa75d2 100755 --- a/tools/psort.py +++ b/plaso/scripts/psort.py @@ -21,12 +21,16 @@ def Main(): - """The main function.""" + """Entry point of console script to analyze and output events. + + Returns: + int: exit code that is provided to sys.exit(). + """ input_reader = cli_tools.StdinInputReader() tool = psort_tool.PsortTool(input_reader=input_reader) if not tool.ParseArguments(sys.argv[1:]): - return False + return 1 if tool.show_troubleshooting: print('Using Python version {0!s}'.format(sys.version)) @@ -39,12 +43,12 @@ def Main(): print('Also see: https://plaso.readthedocs.io/en/latest/sources/user/' 'Troubleshooting.html') - return True + return 0 try: tool.CheckOutDated() except KeyboardInterrupt: - return False + return 1 have_list_option = False if tool.list_analysis_plugins: @@ -68,7 +72,7 @@ def Main(): have_list_option = True if have_list_option: - return True + return 0 try: tool.ProcessStorage() @@ -80,17 +84,17 @@ def Main(): except (KeyboardInterrupt, errors.UserAbort): logging.warning('Aborted by user.') - return False + return 1 except RuntimeError as exception: print(exception) - return False + return 1 except errors.BadConfigOption as exception: logging.warning(exception) - return False + return 1 - return True + return 0 if __name__ == '__main__': @@ -98,7 +102,4 @@ def Main(): # https://github.com/pyinstaller/pyinstaller/wiki/Recipe-Multiprocessing multiprocessing.freeze_support() - if not Main(): - sys.exit(1) - else: - sys.exit(0) + sys.exit(Main()) diff --git a/tools/psteal.py b/plaso/scripts/psteal.py similarity index 88% rename from tools/psteal.py rename to plaso/scripts/psteal.py index a0bcdc270e..f4d40528b6 100755 --- a/tools/psteal.py +++ b/plaso/scripts/psteal.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- """Psteal (Plaso SýndarheimsTímalína sem Er ALgjörlega sjálfvirk). -Psteal Combines the log2timeline and psort tools into a single tool. +Psteal combines the log2timeline and psort tools into a single tool. Currently doesn't support any of the two tools flags. Sample Usage: @@ -23,11 +23,15 @@ def Main(): - """The main function.""" + """Entry point of console script to extract and output events. + + Returns: + int: exit code that is provided to sys.exit(). + """ tool = psteal_tool.PstealTool() if not tool.ParseArguments(sys.argv[1:]): - return False + return 1 if tool.show_troubleshooting: print('Using Python version {0!s}'.format(sys.version)) @@ -40,12 +44,12 @@ def Main(): print('Also see: https://plaso.readthedocs.io/en/latest/sources/user/' 'Troubleshooting.html') - return True + return 0 try: tool.CheckOutDated() except KeyboardInterrupt: - return False + return 1 have_list_option = False if tool.list_archive_types: @@ -73,11 +77,11 @@ def Main(): have_list_option = True if have_list_option: - return True + return 0 if tool.dependencies_check and not dependencies.CheckDependencies( verbose_output=False): - return False + return 1 try: tool.ExtractEventsFromSources() @@ -90,13 +94,13 @@ def Main(): except (KeyboardInterrupt, errors.UserAbort): logging.warning('Aborted by user.') - return False + return 1 except errors.SourceScannerError as exception: logging.warning(exception) - return False + return 1 - return True + return 0 if __name__ == '__main__': @@ -104,7 +108,4 @@ def Main(): # https://github.com/pyinstaller/pyinstaller/wiki/Recipe-Multiprocessing multiprocessing.freeze_support() - if not Main(): - sys.exit(1) - else: - sys.exit(0) + sys.exit(Main()) diff --git a/setup.cfg b/setup.cfg index 45a8f14656..c3d3f48bb7 100644 --- a/setup.cfg +++ b/setup.cfg @@ -23,12 +23,6 @@ package_dir = plaso = plaso packages = find: python_requires = >=3.8 -scripts = - tools/image_export.py - tools/log2timeline.py - tools/pinfo.py - tools/psort.py - tools/psteal.py [options.package_data] plaso = @@ -49,6 +43,14 @@ exclude = utils where = . +[options.entry_points] +console_scripts = + image_export = plaso.scripts.image_export:Main + log2timeline = plaso.scripts.log2timeline:Main + pinfo = plaso.scripts.pinfo:Main + psort = plaso.scripts.psort:Main + psteal = plaso.scripts.psteal:Main + [sdist] template = MANIFEST.in manifest = MANIFEST diff --git a/tests/end-to-end.py b/tests/end-to-end.py index 74e93356b5..7a8d025c5b 100755 --- a/tests/end-to-end.py +++ b/tests/end-to-end.py @@ -1978,9 +1978,10 @@ def Main(): 'The location of the directory where the test sources are stored.')) argument_parser.add_argument( - '--tools-directory', '--tools_directory', action='store', - metavar='DIRECTORY', dest='tools_directory', type=str, - default=None, help='The location of the plaso tools directory.') + '--scripts-directory', '--scripts_directory', '--tools-directory', + '--tools_directory', action='store', metavar='DIRECTORY', + dest='scripts_directory', type=str, default=None, + help='The location of the plaso scripts directory.') options = argument_parser.parse_args() @@ -1998,10 +1999,10 @@ def Main(): logging.basicConfig( format='[%(levelname)s] %(message)s', level=logging.INFO) - tools_path = options.tools_directory + tools_path = options.scripts_directory if not tools_path: tools_path = os.path.join( - os.path.dirname(os.path.dirname(__file__)), 'tools') + os.path.dirname(os.path.dirname(__file__)), 'plaso', 'scripts') test_sources_path = options.sources_directory if test_sources_path and not os.path.isdir(test_sources_path): diff --git a/tox.ini b/tox.ini index eb32b9539b..2e0c2cdf8d 100644 --- a/tox.ini +++ b/tox.ini @@ -60,6 +60,6 @@ commands = docformatter --version pylint --version yamllint -v - docformatter --check --diff --recursive plaso setup.py tests tools - pylint --rcfile=.pylintrc plaso setup.py tests tools + docformatter --check --diff --recursive plaso setup.py tests + pylint --rcfile=.pylintrc plaso setup.py tests yamllint -c .yamllint.yaml plaso test_data