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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +26 -0
- data/lib/bwrap/args/args.rb +5 -1
- data/lib/bwrap/args/bind/library.rb +188 -0
- data/lib/bwrap/args/bind/mime.rb +58 -0
- data/lib/bwrap/args/bind.rb +27 -89
- data/lib/bwrap/args/construct.rb +3 -2
- data/lib/bwrap/args/environment.rb +59 -1
- data/lib/bwrap/args/features.rb +65 -3
- data/lib/bwrap/args/library.rb +17 -10
- data/lib/bwrap/args/machine_id.rb +6 -3
- data/lib/bwrap/args/mount.rb +1 -0
- data/lib/bwrap/bwrap.rb +151 -0
- data/lib/bwrap/bwrap_module.rb +26 -0
- data/lib/bwrap/config/features.rb +116 -0
- data/lib/bwrap/config.rb +96 -92
- data/lib/bwrap/execution/exceptions.rb +24 -0
- data/lib/bwrap/execution/execute.rb +4 -1
- data/lib/bwrap/execution/execution.rb +147 -3
- data/lib/bwrap/execution/labels.rb +8 -1
- data/lib/bwrap/execution/path.rb +30 -10
- data/lib/bwrap/execution.rb +6 -160
- data/lib/bwrap/output/colors.rb +0 -2
- data/lib/bwrap/output/log.rb +17 -5
- data/lib/bwrap/output/output_impl.rb +182 -0
- data/lib/bwrap/output.rb +8 -152
- data/lib/bwrap/version.rb +1 -2
- data/lib/bwrap.rb +1 -79
- data.tar.gz.sig +0 -0
- metadata +11 -19
- metadata.gz.sig +0 -0
- data/lib/bwrap/output/output.rb +0 -8
@@ -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
|
-
#
|
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
|
-
|
8
|
-
|
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
|
-
|
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
|
#
|
data/lib/bwrap/execution/path.rb
CHANGED
@@ -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
|
-
#
|
8
|
+
# Utilities to handle environment path operations.
|
9
|
+
#
|
10
|
+
# @api private
|
8
11
|
class Environment
|
9
|
-
|
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
|
-
|
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
|
24
|
-
|
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
|
-
|
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
|
data/lib/bwrap/execution.rb
CHANGED
@@ -1,165 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
require "bwrap/output"
|
5
|
-
require_relative "execution/execute"
|
6
|
-
require_relative "execution/path"
|
3
|
+
require_relative "bwrap_module"
|
7
4
|
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
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"
|
data/lib/bwrap/output/colors.rb
CHANGED
data/lib/bwrap/output/log.rb
CHANGED
@@ -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
|
-
|
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
|