diff --git a/borgmatic/execute.py b/borgmatic/execute.py index 611a67c1..629ad946 100644 --- a/borgmatic/execute.py +++ b/borgmatic/execute.py @@ -179,13 +179,14 @@ def log_outputs(processes, exclude_stdouts, output_log_level, borg_local_path, b log level. Additionally, raise a CalledProcessError if a process exits with an error (or a warning for exit code 1, if that process does not match the Borg local path). - If output log level is None, then instead of logging, capture output for each process and return - it as a dict from the process to its output. Use the given Borg local path and exit code - configuration to decide what's an error and what's a warning. + If the output log level is None, then instead of logging, capture output for each process and + return it as a dict from the process to its output. If the output log level is not None, return + an empty dict. - If any stdouts are given to exclude, then for any matching processes, ignore those buffers. Also - note that stdout for a process can be None if output is intentionally not captured, in which - case it won't be logged. + Use the given Borg local path and exit code configuration to decide what's an error and what's a + warning. If any stdouts are given to exclude, then for any matching processes, ignore those + buffers. Also note that stdout for a process can be None if output is intentionally not + captured, in which case it won't be logged. ''' # Map from output buffer to sequence of last lines. buffer_last_lines = collections.defaultdict(list) @@ -262,7 +263,7 @@ def log_outputs(processes, exclude_stdouts, output_log_level, borg_local_path, b exit_status = interpret_exit_code(command, exit_code, borg_local_path, borg_exit_codes) if exit_status in {Exit_status.ERROR, Exit_status.WARNING}: - # execute_command_and_capture_output If an error occurs, include its output in the raised exception so that we don't + # If an error occurs, include its output in the raised exception so that we don't # inadvertently hide error output. for output_buffer in output_buffers_for_process(process, exclude_stdouts): last_lines = buffer_last_lines[output_buffer] if output_buffer else [] @@ -305,12 +306,12 @@ def log_outputs(processes, exclude_stdouts, output_log_level, borg_local_path, b still_running = False break - if captured_outputs: + if output_log_level is None: return { process: '\n'.join(output_lines) for process, output_lines in captured_outputs.items() } - return None + return {} SECRET_COMMAND_FLAG_NAMES = {'--password'} @@ -438,14 +439,14 @@ def execute_command_and_capture_output( ): ''' Execute the given command (a sequence of command/argument strings), capturing and returning its - output (stdout). If an input file descriptor is given, then pipe it to the command's stdin. If - capture stderr is True, then capture and return stderr in addition to stdout. If shell is True, - execute the command within a shell. If an environment variables dict is given, then pass it into - the command. If a working directory is given, use that as the present working directory when - running the command. If a Borg local path is given, and the command matches it (regardless of - arguments), treat exit code 1 as a warning instead of an error. But if Borg exit codes are given - as a sequence of exit code configuration dicts, then use that configuration to decide what's an - error and what's a warning. + output (stdout) as a string. If an input file descriptor is given, then pipe it to the command's + stdin. If capture stderr is True, then capture and return stderr in addition to stdout. If shell + is True, execute the command within a shell. If an environment variables dict is given, then + pass it into the command. If a working directory is given, use that as the present working + directory when running the command. If a Borg local path is given, and the command matches it + (regardless of arguments), treat exit code 1 as a warning instead of an error. But if Borg exit + codes are given as a sequence of exit code configuration dicts, then use that configuration to + decide what's an error and what's a warning. Raise subprocesses.CalledProcessError if an error occurs while running the command. ''' @@ -481,7 +482,7 @@ def execute_command_and_capture_output( borg_exit_codes, ) - return captured_outputs.get(process) + return captured_outputs.get(process, '') def execute_command_with_processes( @@ -551,6 +552,6 @@ def execute_command_with_processes( ) if output_log_level is None: - return captured_outputs.get(command_process) + return captured_outputs.get(command_process, '') return None diff --git a/tests/integration/test_execute.py b/tests/integration/test_execute.py index 47bb4316..5e72f930 100644 --- a/tests/integration/test_execute.py +++ b/tests/integration/test_execute.py @@ -43,12 +43,15 @@ def test_log_outputs_logs_each_line_separately(): (), ).and_return((there_process.stdout,)) - module.log_outputs( - (hi_process, there_process), - exclude_stdouts=(), - output_log_level=logging.INFO, - borg_local_path='borg', - borg_exit_codes=None, + assert ( + module.log_outputs( + (hi_process, there_process), + exclude_stdouts=(), + output_log_level=logging.INFO, + borg_local_path='borg', + borg_exit_codes=None, + ) + == {} ) @@ -78,12 +81,15 @@ def test_log_outputs_skips_logs_for_process_with_none_stdout(): (), ).and_return((there_process.stdout,)) - module.log_outputs( - (hi_process, there_process), - exclude_stdouts=(), - output_log_level=logging.INFO, - borg_local_path='borg', - borg_exit_codes=None, + assert ( + module.log_outputs( + (hi_process, there_process), + exclude_stdouts=(), + output_log_level=logging.INFO, + borg_local_path='borg', + borg_exit_codes=None, + ) + == {} ) @@ -268,12 +274,15 @@ def test_log_outputs_kills_other_processes_and_returns_when_one_exits_with_warni ).and_return((other_process.stdout,)) flexmock(other_process).should_receive('kill').once() - module.log_outputs( - (process, other_process), - exclude_stdouts=(), - output_log_level=logging.INFO, - borg_local_path='borg', - borg_exit_codes=None, + assert ( + module.log_outputs( + (process, other_process), + exclude_stdouts=(), + output_log_level=logging.INFO, + borg_local_path='borg', + borg_exit_codes=None, + ) + == {} ) @@ -312,12 +321,15 @@ def test_log_outputs_vents_other_processes_when_one_exits(): ).and_return((other_process.stdout,)) flexmock(process.stdout).should_call('readline').at_least().once() - module.log_outputs( - (process, other_process), - exclude_stdouts=(process.stdout,), - output_log_level=logging.INFO, - borg_local_path='borg', - borg_exit_codes=None, + assert ( + module.log_outputs( + (process, other_process), + exclude_stdouts=(process.stdout,), + output_log_level=logging.INFO, + borg_local_path='borg', + borg_exit_codes=None, + ) + == {} ) @@ -349,12 +361,15 @@ def test_log_outputs_does_not_error_when_one_process_exits(): (process.stdout,), ).and_return((other_process.stdout,)) - module.log_outputs( - (process, other_process), - exclude_stdouts=(process.stdout,), - output_log_level=logging.INFO, - borg_local_path='borg', - borg_exit_codes=None, + assert ( + module.log_outputs( + (process, other_process), + exclude_stdouts=(process.stdout,), + output_log_level=logging.INFO, + borg_local_path='borg', + borg_exit_codes=None, + ) + == {} ) @@ -397,12 +412,15 @@ def test_log_outputs_with_no_output_logs_nothing(): process = subprocess.Popen(['true'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) flexmock(module).should_receive('output_buffers_for_process').and_return((process.stdout,)) - module.log_outputs( - (process,), - exclude_stdouts=(), - output_log_level=logging.INFO, - borg_local_path='borg', - borg_exit_codes=None, + assert ( + module.log_outputs( + (process,), + exclude_stdouts=(), + output_log_level=logging.INFO, + borg_local_path='borg', + borg_exit_codes=None, + ) + == {} ) @@ -414,10 +432,13 @@ def test_log_outputs_with_unfinished_process_re_polls(): flexmock(process).should_receive('poll').and_return(None).and_return(0).times(3) flexmock(module).should_receive('output_buffers_for_process').and_return((process.stdout,)) - module.log_outputs( - (process,), - exclude_stdouts=(), - output_log_level=logging.INFO, - borg_local_path='borg', - borg_exit_codes=None, + assert ( + module.log_outputs( + (process,), + exclude_stdouts=(), + output_log_level=logging.INFO, + borg_local_path='borg', + borg_exit_codes=None, + ) + == {} )