bwrap 1.0.0.pre.alpha5 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,152 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "bwrap/version"
4
+ require "bwrap/output"
5
+ require_relative "exceptions"
6
+ require_relative "execute"
7
+ require_relative "path"
4
8
 
5
- # Generic execution functionality.
9
+ # Provides methods to execute commands and handle its output.
10
+ #
11
+ # Output can be controlled by using log levels of Output module.
12
+ #
13
+ # @example Executing a command
14
+ # class MyClass
15
+ # include Bwrap::Execution
16
+ #
17
+ # def my_method
18
+ # execute %w{ ls /dev/null }
6
19
  module Bwrap::Execution
7
- # Nyan.
8
- end
20
+ include Bwrap::Output
21
+ include Bwrap::Execution::Path
22
+
23
+ # Actual implementation of execution command. Can be used when static method is needed.
24
+ #
25
+ # @note When an array is given as a command, empty strings are passed as empty arguments.
26
+ #
27
+ # This means that `[ "foo", "bar" ]` passes one argument to "foo" command, when
28
+ # `[ "foo", "", "bar" ]` passes two arguments.
29
+ #
30
+ # This may or may not be what is assumed, so it can’t be fixed here. It is up to the
31
+ # command to decide how to handle empty arguments.
32
+ #
33
+ # Returns pid of executed command if wait is false.
34
+ # Returns command output if wait is true.
35
+ #
36
+ # fail == If true, an error is raised in case the command returns failure code.
37
+ #
38
+ # @param error if :show, warn()s output of the command is shown if execution failed.
39
+ #
40
+ # @see #execute
41
+ def self.do_execute command,
42
+ fail: true,
43
+ wait: true,
44
+ log: true,
45
+ direct_output: false,
46
+ env: {},
47
+ clear_env: false,
48
+ error: nil,
49
+ log_callback: 2,
50
+ rootcmd: nil
51
+ command = Execute.format_command command, rootcmd: rootcmd
52
+ Execute.handle_logging command, log_callback: log_callback, log: log, dry_run: @dry_run
53
+ return if @dry_run || Bwrap::Execution::Execute.dry_run
54
+
55
+ Execute.open_pipes direct_output
56
+
57
+ # If command is an array, there can’t be arrays inside the array.
58
+ # For convenience, the array is flattened here, so callers can construct commands more easily.
59
+ if command.respond_to? :flatten!
60
+ command.flatten!
61
+ end
62
+
63
+ # If command is string, splat operator (the *) does not do anything. If array, it expand the arguments.
64
+ # This causes spawning work correctly, as that’s how spawn() expects to have the argu
65
+ pid = spawn(env, *command, err: [ :child, :out ], out: Execute.w, unsetenv_others: clear_env)
66
+ output = Execute.finish_execution(log: log, wait: wait, direct_output: direct_output)
67
+ return pid unless wait
68
+
69
+ # This is instant return, but allows us to have $?/$CHILD_STATUS set.
70
+ Process.wait pid
71
+ @last_status = $CHILD_STATUS
72
+
73
+ output = Execute.process_output output: output
74
+ Execute.handle_execution_fail fail: fail, error: error, output: output
75
+ output
76
+ ensure
77
+ Execute.clean_variables
78
+ end
79
+
80
+ # Returns Process::Status instance of last execution.
81
+ #
82
+ # @note This only is able to return the status if wait is true, as otherwise caller is assumed to
83
+ # handle execution flow.
84
+ def self.last_status
85
+ @last_status
86
+ end
87
+
88
+ # Execute a command.
89
+ #
90
+ # This method can be used by including Execution module in a class that should be able to
91
+ # execute commands.
92
+ #
93
+ # @see .do_execute .do_execute for documentation of argument syntax
94
+ private def execute *args, **kwargs
95
+ # Mangle proper location to error message.
96
+ if kwargs.is_a? Hash
97
+ kwargs[:log_callback] = 3
98
+ else
99
+ kwargs = { log_callback: 3 }
100
+ end
101
+ Bwrap::Execution.do_execute(*args, **kwargs)
102
+ end
103
+
104
+ # Same as ::execute, but uses log: false to avoid unnecessary output when we’re just getting a
105
+ # value for internal needs.
106
+ #
107
+ # Defaults to fail: false, since when one just wants to get the value, there is not that much
108
+ # need to unconditionally die if getting bad exit code.
109
+ private def execvalue *args, fail: false, log: false, **kwargs
110
+ # This logging handling is a bit of duplication from execute(), but to be extra safe, it is duplicated.
111
+ # The debug message contents will always be evaluated, so can just do it like this.
112
+ log_command = args[0].respond_to?(:join) && args[0].join(" ") || args[0]
113
+ log_command =
114
+ if log_command.frozen?
115
+ log_command.dup.force_encoding("UTF-8")
116
+ else
117
+ log_command.force_encoding("UTF-8")
118
+ end
119
+ if @dry_run
120
+ puts "Would execvalue “#{log_command}” at #{caller_locations(1, 1)[0]}"
121
+ return
122
+ end
123
+ trace "Execvaluing “#{log_command}” at #{caller_locations(1, 1)[0]}"
124
+ execute(*args, fail: fail, log: log, **kwargs)
125
+ end
126
+
127
+ private def exec_success?
128
+ $CHILD_STATUS.success?
129
+ end
130
+
131
+ private def exec_failure?
132
+ !exec_success?
133
+ end
134
+
135
+ # When running through bundler, don’t use whatever it defines as we’re running inside chroot.
136
+ private def clean_execute
137
+ if (Bundler&.bundler_major_version) >= 2
138
+ Bundler.with_unbundled_env do
139
+ yield 2
140
+ end
141
+ elsif Bundler&.bundler_major_version == 1
142
+ Bundler.with_clean_env do
143
+ yield 1
144
+ end
145
+ else
146
+ yield nil
147
+ end
148
+ rescue NameError
149
+ # If NameError is thrown, no Bundler is available.
150
+ yield nil
151
+ end
152
+ end
@@ -1,7 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "bwrap/version"
4
- require_relative "execution"
4
+
5
+ # Just declaring the module here so full Execution module
6
+ # doesn’t need to be required just to have labels.
7
+ #
8
+ # Most users probably should just require bwrap/execution directly
9
+ # instead of this file, but bwrap/output.rb benefits from this.
10
+ module Bwrap::Execution
11
+ end
5
12
 
6
13
  # Exit codes for exit status handling.
7
14
  #
@@ -1,15 +1,29 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "bwrap/output"
4
+ require_relative "exceptions"
4
5
 
5
6
  # Path checking methods.
6
7
  module Bwrap::Execution::Path
7
- # @api internal
8
+ # Utilities to handle environment path operations.
9
+ #
10
+ # @api private
8
11
  class Environment
9
- def self.each_env_path command
12
+ # Loop through each path in global PATH environment variable to
13
+ # perform an operation in each path, for example to resolve
14
+ # absolute path to a command.
15
+ #
16
+ # NOTE: This has nothing to do with {Bwrap::Config#env_paths}, as the
17
+ # env paths looped are what the system has defined, in ENV["PATH"].
18
+ #
19
+ # Should be cross-platform.
20
+ #
21
+ # @yield Command appended to each path in PATH environment variable
22
+ # @yieldparam path [String] Full path to executable
23
+ def self.each_env_path command, env_path_var: ENV["PATH"]
10
24
  exts = ENV["PATHEXT"] ? ENV["PATHEXT"].split(";") : [ "" ]
11
25
 
12
- ENV["PATH"].split(File::PATH_SEPARATOR).each do |env_path|
26
+ env_path_var.split(File::PATH_SEPARATOR).each do |env_path|
13
27
  exts.each do |ext|
14
28
  exe = File.join(env_path, "#{command}#{ext}")
15
29
  yield exe
@@ -20,8 +34,12 @@ module Bwrap::Execution::Path
20
34
 
21
35
  # Check if requested program can be found.
22
36
  #
23
- # Should work cross-platform and in restricted environents pretty well.
24
- private def command_available? command
37
+ # Should work cross-platform and in restricted environments pretty well.
38
+ #
39
+ # @param command [String] executable to be resolved
40
+ # @param env_path_var [String] PATH environment variable as string.
41
+ # Defaults to `ENV["PATH"]`
42
+ private def command_available? command, env_path_var: ENV["PATH"]
25
43
  # Special handling for absolute paths.
26
44
  path = Pathname.new command
27
45
  if path.absolute?
@@ -32,7 +50,7 @@ module Bwrap::Execution::Path
32
50
  return false
33
51
  end
34
52
 
35
- Bwrap::Execution::Path::Environment.each_env_path command do |exe|
53
+ Bwrap::Execution::Path::Environment.each_env_path command, env_path_var: env_path_var do |exe|
36
54
  return true if File.executable?(exe) && !File.directory?(exe)
37
55
  end
38
56
 
@@ -40,7 +58,9 @@ module Bwrap::Execution::Path
40
58
  end
41
59
 
42
60
  # Returns path to given executable.
43
- private def which command, fail: true
61
+ #
62
+ # @param (see #command_available?)
63
+ private def which command, fail: true, env_path_var: ENV["PATH"]
44
64
  # Special handling for absolute paths.
45
65
  path = Pathname.new command
46
66
  if path.absolute?
@@ -48,17 +68,17 @@ module Bwrap::Execution::Path
48
68
  return command
49
69
  end
50
70
 
51
- raise CommandNotFound.new command: command if fail
71
+ raise Bwrap::Execution::CommandNotFound.new command: command if fail
52
72
 
53
73
  return nil
54
74
  end
55
75
 
56
- Bwrap::Execution::Path::Environment.each_env_path command do |exe|
76
+ Bwrap::Execution::Path::Environment.each_env_path command, env_path_var: env_path_var do |exe|
57
77
  return exe if File.executable?(exe) && !File.directory?(exe)
58
78
  end
59
79
 
60
80
  return nil unless fail
61
81
 
62
- raise CommandNotFound.new command: command
82
+ raise Bwrap::Execution::CommandNotFound.new command: command
63
83
  end
64
84
  end
@@ -1,165 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "bwrap/version"
4
- require "bwrap/output"
5
- require_relative "execution/execute"
6
- require_relative "execution/path"
3
+ require_relative "bwrap_module"
7
4
 
8
- # @abstract Module to be included in a class that needs to execute commands.
9
- #
10
- # Methods to execute processes.
5
+ # Declare Execution module here so Bwrap::Execution module is
6
+ # already declared for Execution module classes, to avoid
7
+ # a circular dependency.
11
8
  module Bwrap::Execution
12
- include Bwrap::Output
13
- include Bwrap::Execution::Path
14
-
15
- # Unspecified execution related error.
16
- class CommandError < StandardError
17
- end
18
-
19
- # Signifies that command execution has failed.
20
- class ExecutionFailed < CommandError
21
- end
22
-
23
- # Thrown if given command was not found.
24
- class CommandNotFound < CommandError
25
- # Command that was looked at.
26
- attr_reader :command
27
-
28
- def initialize command:
29
- @command = command
30
- msg = "Failed to find #{command} from PATH."
31
-
32
- super msg
33
- end
34
- end
35
-
36
- # Actual implementation of execution command. Can be used when static method is needed.
37
- #
38
- # @note When an array is given as a command, empty strings are passed as empty arguments.
39
- #
40
- # This means that `[ "foo", "bar" ]` passes one argument to "foo" command, when
41
- # `[ "foo", "", "bar" ]` passes two arguments.
42
- #
43
- # This may or may not be what is assumed, so it can’t be fixed here. It is up to the
44
- # command to decide how to handle empty arguments.
45
- #
46
- # Returns pid of executed command if wait is false.
47
- # Returns command output if wait is true.
48
- #
49
- # fail == If true, an error is raised in case the command returns failure code.
50
- #
51
- # @param error if :show, warn()s output of the command is shown if execution failed.
52
- #
53
- # @see #execute
54
- def self.do_execute command,
55
- fail: true,
56
- wait: true,
57
- log: true,
58
- direct_output: false,
59
- env: {},
60
- clear_env: false,
61
- error: nil,
62
- log_callback: 2,
63
- rootcmd: nil
64
- command = Execute.format_command command, rootcmd: rootcmd
65
- Execute.handle_logging command, log_callback: log_callback, log: log, dry_run: @dry_run
66
- return if @dry_run || Bwrap::Execution::Execute.dry_run
67
-
68
- Execute.open_pipes direct_output
69
-
70
- # If command is an array, there can’t be arrays inside the array.
71
- # For convenience, the array is flattened here, so callers can construct commands more easily.
72
- if command.respond_to? :flatten!
73
- command.flatten!
74
- end
75
-
76
- # If command is string, splat operator (the *) does not do anything. If array, it expand the arguments.
77
- # This causes spawning work correctly, as that’s how spawn() expects to have the argu
78
- pid = spawn(env, *command, err: [ :child, :out ], out: Execute.w, unsetenv_others: clear_env)
79
- output = Execute.finish_execution(log: log, wait: wait, direct_output: direct_output)
80
- return pid unless wait
81
-
82
- # This is instant return, but allows us to have $?/$CHILD_STATUS set.
83
- Process.wait pid
84
- @last_status = $CHILD_STATUS
85
-
86
- output = Execute.process_output output: output
87
- Execute.handle_execution_fail fail: fail, error: error, output: output
88
- output
89
- ensure
90
- Execute.clean_variables
91
- end
92
-
93
- # Returns Process::Status instance of last execution.
94
- #
95
- # @note This only is able to return the status if wait is true, as otherwise caller is assumed to
96
- # handle execution flow.
97
- def self.last_status
98
- @last_status
99
- end
100
-
101
- # Execute a command.
102
- #
103
- # This method can be used by including Execution module in a class that should be able to
104
- # execute commands.
105
- #
106
- # @see .do_execute .do_execute for documentation of argument syntax
107
- private def execute *args
108
- # Mangle proper location to error message.
109
- if args.last.is_a? Hash
110
- args.last[:log_callback] = 3
111
- else
112
- args << { log_callback: 3 }
113
- end
114
- Bwrap::Execution.do_execute(*args)
115
- end
116
-
117
- # Same as ::execute, but uses log: false to avoid unnecessary output when we’re just getting a
118
- # value for internal needs.
119
- #
120
- # Defaults to fail: false, since when one just wants to get the value, there is not that much
121
- # need to unconditionally die if getting bad exit code.
122
- private def execvalue *args, fail: false, rootcmd: nil, env: {}
123
- # This logging handling is a bit of duplication from execute(), but to be extra safe, it is duplicated.
124
- # The debug message contents will always be evaluated, so can just do it like this.
125
- log_command = args[0].respond_to?(:join) && args[0].join(" ") || args[0]
126
- log_command =
127
- if log_command.frozen?
128
- log_command.dup.force_encoding("UTF-8")
129
- else
130
- log_command.force_encoding("UTF-8")
131
- end
132
- if @dry_run
133
- puts "Would execvalue “#{log_command}” at #{caller_locations(1, 1)[0]}"
134
- return
135
- end
136
- trace "Execvaluing “#{log_command}” at #{caller_locations(1, 1)[0]}"
137
- execute(*args, fail: fail, log: false, rootcmd: rootcmd, env: env)
138
- end
139
-
140
- private def exec_success?
141
- $CHILD_STATUS.success?
142
- end
143
-
144
- private def exec_failure?
145
- !exec_success?
146
- end
147
-
148
- # When running through bundler, don’t use whatever it defines as we’re running inside chroot.
149
- private def clean_execute
150
- if (Bundler&.bundler_major_version) >= 2
151
- Bundler.with_unbundled_env do
152
- yield 2
153
- end
154
- elsif Bundler&.bundler_major_version == 1
155
- Bundler.with_clean_env do
156
- yield 1
157
- end
158
- else
159
- yield nil
160
- end
161
- rescue NameError
162
- # If NameError is thrown, no Bundler is available.
163
- yield nil
164
- end
165
9
  end
10
+
11
+ require_relative "execution/execution"
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "output"
4
-
5
3
  # Methods to color CLI output.
6
4
  module Bwrap::Output::Colors
7
5
  # Outputs ANSI true color sequence.
@@ -1,10 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # force_encoding modifies string, so can’t freeze strings.
4
-
5
- require_relative "output"
6
-
7
3
  # Logging methods.
4
+ #
5
+ # @note One should require "bwrap/output" instead of this file directly, even
6
+ # if using only methods from this class.
7
+ #
8
+ # This is because Bwrap::Output module would be missing, or there could be
9
+ # a circular dependency, which is always bad, even if Ruby would break it for you.
8
10
  class Bwrap::Output::Log
9
11
  @@log_file = nil
10
12
 
@@ -15,11 +17,17 @@ class Bwrap::Output::Log
15
17
 
16
18
  # Writes given string to log.
17
19
  def self.write_to_log str
20
+ # Guard against invalid input.
21
+ return unless str.respond_to? :force_encoding
22
+
18
23
  @@log_file&.write str.dup.force_encoding("UTF-8")
19
24
  end
20
25
 
21
26
  # Writes given string to log.
22
27
  def self.puts_to_log str
28
+ # Guard against invalid input.
29
+ return unless str.respond_to? :force_encoding
30
+
23
31
  @@log_file&.puts str.dup.force_encoding("UTF-8")
24
32
  end
25
33
 
@@ -31,6 +39,10 @@ class Bwrap::Output::Log
31
39
 
32
40
  # Starts logging to given file.
33
41
  def self.log_to_file log_path
42
+ unless File.writable? log_path
43
+ warn "Given log file #{log_path} is not writable by current user."
44
+ return
45
+ end
34
46
  log_file = File.open log_path, "w"
35
47
 
36
48
  # In default mode, log messages disappears as Ruby’s own buffer gets full.
@@ -40,7 +52,7 @@ class Bwrap::Output::Log
40
52
  @@log_file = log_file
41
53
 
42
54
  at_exit do
43
- ::Bwrap::Output::Log.close_log_file
55
+ Bwrap::Output::Log.close_log_file
44
56
  end
45
57
  end
46
58
  end
@@ -0,0 +1,182 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Have variables like $CHILD_STATUS which is alias of $?.
4
+ require "English"
5
+
6
+ require "bwrap/bwrap_module"
7
+ require "bwrap/execution/labels"
8
+
9
+ require_relative "levels"
10
+ require_relative "log"
11
+
12
+ # Methods useful for output handling.
13
+ #
14
+ # There is four different log levels:
15
+ #
16
+ # @!description_list
17
+ # @term error
18
+ # @description
19
+ # Causes execution to halt either to exit with requested code or,
20
+ # if requested, raises an exception.
21
+ # @term warning
22
+ # @description Outputs given text to STDERR.
23
+ # @term verbose
24
+ # @description Outputs given text if verbose, debug or trace flag is set.
25
+ # @term debug
26
+ # @description Outputs given text if debug or trace flag is set.
27
+ # @term trace
28
+ # @description Outputs given text if trace flag is set.
29
+ #
30
+ # Output levels can be enabled with {.handle_output_options}.
31
+ #
32
+ # When using {Bwrap::Bwrap}, {Bwrap::Bwrap#parse_command_line_arguments}
33
+ # causes output levels to be set if relevant CLI arguments have been
34
+ # given. TODO: Add documentation about CLI args somewhere. Maybe README?
35
+ module Bwrap::Output
36
+ # @see #verbose?
37
+ def self.verbose?
38
+ Bwrap::Output::Levels.verbose?
39
+ end
40
+
41
+ # @see #debug?
42
+ def self.debug?
43
+ Bwrap::Output::Levels.debug?
44
+ end
45
+
46
+ # @see #trace?
47
+ def self.trace?
48
+ Bwrap::Output::Levels.trace?
49
+ end
50
+
51
+ # Takes hash of options received from Optimist and checks output related flags.
52
+ def self.handle_output_options options
53
+ Bwrap::Output::Levels.handle_output_options options
54
+ end
55
+
56
+ # Handler used by #trace to output given string.
57
+ def self.trace_output str, raw: false, log_callback: 1
58
+ return unless trace?
59
+
60
+ if raw
61
+ print str
62
+ else
63
+ out = Bwrap::Output::Levels.trace_print_formatted str, log_callback: (log_callback + 1)
64
+ end
65
+ Bwrap::Output::Log.puts_to_log out || str
66
+ end
67
+
68
+ # Handler used by #debug to output given string.
69
+ def self.debug_output str, raw: false, log_callback: 1
70
+ return unless debug?
71
+
72
+ if raw
73
+ print str
74
+ else
75
+ out = Bwrap::Output::Levels.debug_print_formatted str, log_callback: (log_callback + 1)
76
+ end
77
+ Bwrap::Output::Log.puts_to_log out || str
78
+ end
79
+
80
+ # Handler used by #verb to output given string.
81
+ def self.verb_output str, raw: false, log_callback: 1
82
+ return unless verbose?
83
+
84
+ if raw
85
+ print str
86
+ else
87
+ out = Bwrap::Output::Levels.verbose_print_formatted str, log_callback: (log_callback + 1)
88
+ end
89
+ Bwrap::Output::Log.puts_to_log out || str
90
+ end
91
+
92
+ # Handler used by #warn to output given string.
93
+ def self.warn_output str, raw: false, log_callback: 1
94
+ if raw
95
+ print str
96
+ else
97
+ out = Bwrap::Output::Levels.warning_print_formatted str, log_callback: (log_callback + 1)
98
+ end
99
+ Bwrap::Output::Log.puts_to_log out || str
100
+ end
101
+
102
+ # Aborts current process.
103
+ #
104
+ # Use this instead of Ruby’s #exit in order to filter out dummy #exit calls from the code.
105
+ def self.error_output str = nil, label: :unspecified, log_callback: 1, raise_exception: false
106
+ unless str.nil?
107
+ out = Bwrap::Output::Levels.error_print_formatted str, log_callback: (log_callback + 1)
108
+ Bwrap::Output::Log.puts_to_log out
109
+ end
110
+
111
+ exit_code = Bwrap::Execution::Labels.resolve_exit_code(label)
112
+ raise str if raise_exception
113
+
114
+ exit exit_code
115
+ end
116
+
117
+ # @return true if --verbose, --debug or --trace has been passed, false if not.
118
+ private def verbose?
119
+ Bwrap::Output::Levels.verbose?
120
+ end
121
+
122
+ # @return true if --debug or --trace has been passed, false if not.
123
+ private def debug?
124
+ Bwrap::Output::Levels.debug?
125
+ end
126
+
127
+ # @return true if --trace has been passed, false if not.
128
+ private def trace?
129
+ Bwrap::Output::Levels.trace?
130
+ end
131
+
132
+ # @!group Outputters
133
+
134
+ # Outputs given string if trace flag has been set.
135
+ #
136
+ # Output flags can be set with {.handle_output_options}.
137
+ #
138
+ # @param str String to be outputted
139
+ # @param raw [Boolean] If true, disables output formatting
140
+ private def trace str, raw: false
141
+ Bwrap::Output.trace_output(str, raw: raw, log_callback: 2)
142
+ end
143
+
144
+ # Outputs given string if debug flag has been set.
145
+ #
146
+ # Output flags can be set with {.handle_output_options}.
147
+ #
148
+ # @param str String to be outputted
149
+ # @param raw [Boolean] If true, disables output formatting
150
+ private def debug str, raw: false
151
+ Bwrap::Output.debug_output(str, raw: raw, log_callback: 2)
152
+ end
153
+
154
+ # Outputs given string if verbose flag has been set.
155
+ #
156
+ # Output flags can be set with {.handle_output_options}.
157
+ #
158
+ # @param str String to be outputted
159
+ # @param raw [Boolean] If true, disables output formatting
160
+ private def verb str, raw: false
161
+ Bwrap::Output.verb_output(str, raw: raw, log_callback: 2)
162
+ end
163
+
164
+ # Outputs given string to `$stderr`.
165
+ #
166
+ # @param str String to be outputted
167
+ # @param raw [Boolean] If true, disables output formatting
168
+ private def warn str, raw: false
169
+ Bwrap::Output.warn_output(str, raw: raw, log_callback: 2)
170
+ end
171
+
172
+ # Outputs given string to `$stderr` and halts execution.
173
+ #
174
+ # @param str String to be outputted
175
+ # @param label [Symbol] Exit label accepted by {Bwrap::Execution.resolve_exit_code}
176
+ # @param raise_exception [Boolean] if true, an exception is raised instead of just existing with exit code.
177
+ private def error str = nil, label: :unspecified, raise_exception: false
178
+ Bwrap::Output.error_output(str, label: label, log_callback: 2, raise_exception: raise_exception)
179
+ end
180
+
181
+ # @!endgroup
182
+ end