bwrap 1.0.0 → 1.1.0.pre.rc1
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 +7 -0
- data/lib/bwrap/args/args.rb +36 -1
- data/lib/bwrap/args/bind/library/ruby_binds.rb +45 -0
- data/lib/bwrap/args/bind/library.rb +25 -51
- data/lib/bwrap/args/bind/mime.rb +9 -2
- data/lib/bwrap/args/bind.rb +28 -16
- data/lib/bwrap/args/construct.rb +80 -42
- data/lib/bwrap/args/features/binds_base.rb +13 -0
- data/lib/bwrap/args/features/ruby_binds.rb +47 -0
- data/lib/bwrap/args/features.rb +11 -43
- data/lib/bwrap/args/library.rb +1 -3
- data/lib/bwrap/args/mount.rb +5 -5
- data/lib/bwrap/args/network.rb +43 -0
- data/lib/bwrap/bwrap.rb +9 -2
- data/lib/bwrap/config/features/base.rb +28 -0
- data/lib/bwrap/config/features/ruby.rb +86 -0
- data/lib/bwrap/config/features.rb +6 -78
- data/lib/bwrap/execution/exceptions.rb +12 -0
- data/lib/bwrap/execution/execute.rb +14 -3
- data/lib/bwrap/execution/execution.rb +2 -2
- data/lib/bwrap/execution/path.rb +3 -3
- data/lib/bwrap/output/levels.rb +33 -3
- data/lib/bwrap/output/output_impl.rb +54 -0
- data/lib/bwrap/version.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +40 -6
- metadata.gz.sig +0 -0
data/lib/bwrap/args/features.rb
CHANGED
@@ -8,6 +8,12 @@ require_relative "library"
|
|
8
8
|
#
|
9
9
|
# @see Config::Features
|
10
10
|
class Bwrap::Args::Features < Hash
|
11
|
+
# Requires are here so there is no extra trickiness with namespaces.
|
12
|
+
#
|
13
|
+
# Feature implementations are not meant to be used outside of this class anyway.
|
14
|
+
require_relative "features/binds_base"
|
15
|
+
require_relative "features/ruby_binds"
|
16
|
+
|
11
17
|
include Bwrap::Output
|
12
18
|
|
13
19
|
# Implementation for Bash feature set.
|
@@ -45,44 +51,6 @@ class Bwrap::Args::Features < Hash
|
|
45
51
|
end
|
46
52
|
end
|
47
53
|
|
48
|
-
# Implementation for Ruby feature set.
|
49
|
-
#
|
50
|
-
# @api private
|
51
|
-
class RubyBinds
|
52
|
-
# Returns mounts needed by Ruby feature set.
|
53
|
-
attr_reader :mounts
|
54
|
-
|
55
|
-
# Bind system paths so scripts works inside sandbox.
|
56
|
-
def sitedir_mounts
|
57
|
-
mounts = []
|
58
|
-
mounts << "--ro-bind" << RbConfig::CONFIG["sitedir"] << RbConfig::CONFIG["sitedir"]
|
59
|
-
mounts << "--ro-bind" << RbConfig::CONFIG["rubyhdrdir"] << RbConfig::CONFIG["rubyhdrdir"]
|
60
|
-
mounts << "--ro-bind" << RbConfig::CONFIG["rubylibdir"] << RbConfig::CONFIG["rubylibdir"]
|
61
|
-
mounts << "--ro-bind" << RbConfig::CONFIG["vendordir"] << RbConfig::CONFIG["vendordir"]
|
62
|
-
|
63
|
-
mounts
|
64
|
-
end
|
65
|
-
|
66
|
-
# Create binds for required system libraries.
|
67
|
-
#
|
68
|
-
# These are in path like /usr/lib64/ruby/2.5.0/x86_64-linux-gnu/,
|
69
|
-
# and as they are mostly shared libraries, they may have some extra
|
70
|
-
# dependencies that also need to be bound inside the sandbox.
|
71
|
-
def stdlib_mounts stdlib
|
72
|
-
library_mounts = []
|
73
|
-
library = Bwrap::Args::Library.new
|
74
|
-
stdlib.each do |lib|
|
75
|
-
path = "#{RbConfig::CONFIG["rubyarchdir"]}/#{lib}.so"
|
76
|
-
|
77
|
-
library.needed_libraries(path).each do |requisite_library|
|
78
|
-
library_mounts << "--ro-bind" << requisite_library << requisite_library
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
library_mounts
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
54
|
# `Array` of parameters passed to bwrap.
|
87
55
|
attr_writer :args
|
88
56
|
|
@@ -104,7 +72,7 @@ class Bwrap::Args::Features < Hash
|
|
104
72
|
|
105
73
|
binds = BashBinds.new
|
106
74
|
|
107
|
-
@args.
|
75
|
+
@args.add :feature_binds, binds.bash_mounts
|
108
76
|
end
|
109
77
|
|
110
78
|
private def nscd_binds
|
@@ -112,7 +80,7 @@ class Bwrap::Args::Features < Hash
|
|
112
80
|
|
113
81
|
binds = NscdBinds.new
|
114
82
|
|
115
|
-
@args.
|
83
|
+
@args.add :feature_binds, binds.custom_binds
|
116
84
|
end
|
117
85
|
|
118
86
|
# @note This does not allow development headers needed for compilation for now.
|
@@ -120,9 +88,9 @@ class Bwrap::Args::Features < Hash
|
|
120
88
|
private def ruby_binds
|
121
89
|
return unless @config.features.ruby.enabled?
|
122
90
|
|
123
|
-
binds = RubyBinds.new
|
91
|
+
binds = RubyBinds.new @config
|
124
92
|
|
125
|
-
@args.
|
126
|
-
@args.
|
93
|
+
@args.add :feature_binds, binds.sitedir_mounts
|
94
|
+
@args.add :feature_binds, binds.stdlib_mounts(@config.features.ruby.stdlib)
|
127
95
|
end
|
128
96
|
end
|
data/lib/bwrap/args/library.rb
CHANGED
@@ -66,8 +66,6 @@ class Bwrap::Args::Library
|
|
66
66
|
@needed_libraries
|
67
67
|
end
|
68
68
|
|
69
|
-
# Used by {Bwrap::Args::Bind#libs_command_requires}.
|
70
|
-
#
|
71
69
|
# @param binary_paths [String, Array] one or more paths to be resolved
|
72
70
|
def needed_libraries binary_paths
|
73
71
|
trace "Finding libraries #{binary_paths} requires"
|
@@ -105,7 +103,7 @@ class Bwrap::Args::Library
|
|
105
103
|
libraries = libraries_line.split ","
|
106
104
|
|
107
105
|
(@needed_libraries & libraries).each do |library|
|
108
|
-
|
106
|
+
debug "Binding #{library} as dependency of #{binary_path}"
|
109
107
|
end
|
110
108
|
|
111
109
|
@needed_libraries |= libraries
|
data/lib/bwrap/args/mount.rb
CHANGED
@@ -9,25 +9,25 @@ module Bwrap::Args::Mount
|
|
9
9
|
return unless @config.root
|
10
10
|
|
11
11
|
debug "Binding #{@config.root} as /"
|
12
|
-
@args.
|
13
|
-
@args.
|
12
|
+
@args.add :root_mount, "--bind", @config.root, "/"
|
13
|
+
@args.add :root_mount, "--chdir", "/"
|
14
14
|
end
|
15
15
|
|
16
16
|
# Arguments for mounting devtmpfs to /dev.
|
17
17
|
private def dev_mount
|
18
18
|
debug "Mounting new devtmpfs to /dev"
|
19
|
-
@args.
|
19
|
+
@args.add :dev_mounts, "--dev", "/dev"
|
20
20
|
end
|
21
21
|
|
22
22
|
# Arguments for mounting procfs to /proc.
|
23
23
|
private def proc_mount
|
24
24
|
debug "Mounting new procfs to /proc"
|
25
|
-
@args.
|
25
|
+
@args.add :proc_mount, "--proc", "/proc"
|
26
26
|
end
|
27
27
|
|
28
28
|
# Arguments for mounting tmpfs to /tmp.
|
29
29
|
private def tmp_as_tmpfs
|
30
30
|
debug "Mounting tmpfs to /tmp"
|
31
|
-
@args.
|
31
|
+
@args.add :tmp_mount, "--tmpfs", "/tmp"
|
32
32
|
end
|
33
33
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bwrap/output"
|
4
|
+
require_relative "args"
|
5
|
+
|
6
|
+
# Network related binds.
|
7
|
+
class Bwrap::Args::Network
|
8
|
+
include Bwrap::Output
|
9
|
+
|
10
|
+
# Instance of {Config}.
|
11
|
+
attr_writer :config
|
12
|
+
|
13
|
+
# @param args [Bwrap::Args::Args] Arguments to be passed to bwrap.
|
14
|
+
def initialize args
|
15
|
+
@args = args
|
16
|
+
end
|
17
|
+
|
18
|
+
# Arguments to set hostname to whatever is configured.
|
19
|
+
def hostname
|
20
|
+
return unless @config.hostname
|
21
|
+
|
22
|
+
debug "Setting hostname to #{@config.hostname}"
|
23
|
+
@args.add :hostname, %W{ --hostname #{@config.hostname} }
|
24
|
+
end
|
25
|
+
|
26
|
+
# Arguments to read-only bind /etc/resolv.conf.
|
27
|
+
def resolv_conf
|
28
|
+
# We can’t really bind symlinks, so let’s resolve real path to resolv.conf, in case it is symlinked.
|
29
|
+
source_resolv_conf = Pathname.new "/etc/resolv.conf"
|
30
|
+
source_resolv_conf = source_resolv_conf.realpath
|
31
|
+
|
32
|
+
debug "Binding #{source_resolv_conf} as /etc/resolv.conf"
|
33
|
+
@args.add :resolv_conf, %W{ --ro-bind #{source_resolv_conf} /etc/resolv.conf }
|
34
|
+
end
|
35
|
+
|
36
|
+
# Arguments to allow network connection inside sandbox.
|
37
|
+
def share_net
|
38
|
+
return unless @config.share_net
|
39
|
+
|
40
|
+
verb "Sharing network"
|
41
|
+
@args.add :network, %w{ --share-net }
|
42
|
+
end
|
43
|
+
end
|
data/lib/bwrap/bwrap.rb
CHANGED
@@ -55,7 +55,9 @@ class Bwrap::Bwrap
|
|
55
55
|
construct = Bwrap::Args::Construct.new
|
56
56
|
construct.command = command
|
57
57
|
construct.config = @config
|
58
|
-
|
58
|
+
|
59
|
+
construct.calculate
|
60
|
+
bwrap_args = construct.bwrap_arguments
|
59
61
|
|
60
62
|
exec_command = [ "bwrap" ]
|
61
63
|
exec_command += bwrap_args
|
@@ -89,7 +91,9 @@ class Bwrap::Bwrap
|
|
89
91
|
construct = Bwrap::Args::Construct.new
|
90
92
|
construct.command = command
|
91
93
|
construct.config = config
|
92
|
-
|
94
|
+
|
95
|
+
construct.calculate
|
96
|
+
bwrap_args = construct.bwrap_arguments
|
93
97
|
|
94
98
|
exec_command = [ "bwrap" ]
|
95
99
|
exec_command += bwrap_args
|
@@ -134,6 +138,9 @@ class Bwrap::Bwrap
|
|
134
138
|
opt :trace,
|
135
139
|
"Show trace output (noisiest, probably not useful for most of time)",
|
136
140
|
short: :none
|
141
|
+
opt [ :quiet, :silent ],
|
142
|
+
"Hides notice messages. Warnings and errors are still shown.",
|
143
|
+
short: :none
|
137
144
|
opt :version,
|
138
145
|
"Print version and exit",
|
139
146
|
short: "V"
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @abstract
|
4
|
+
#
|
5
|
+
# Base of all features.
|
6
|
+
class Bwrap::Config::Features::Base
|
7
|
+
# @param features [Bwrap::Config::Features] Instance of features object in {Config}
|
8
|
+
def initialize features
|
9
|
+
@features = features
|
10
|
+
end
|
11
|
+
|
12
|
+
# Checks if the feature has been enabled.
|
13
|
+
#
|
14
|
+
# @return [Boolean] whether feature is enabled
|
15
|
+
def enabled?
|
16
|
+
@enabled
|
17
|
+
end
|
18
|
+
|
19
|
+
# Enable the feature.
|
20
|
+
def enable
|
21
|
+
@enabled = true
|
22
|
+
end
|
23
|
+
|
24
|
+
# Disable the feature.
|
25
|
+
def disable
|
26
|
+
@enabled = false
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bwrap/execution"
|
4
|
+
|
5
|
+
# Defines Ruby feature set.
|
6
|
+
#
|
7
|
+
# Implies {Nscd} feature.
|
8
|
+
class Bwrap::Config::Features::Ruby < Bwrap::Config::Features::Base
|
9
|
+
include Bwrap::Execution
|
10
|
+
|
11
|
+
def initialize features
|
12
|
+
super features
|
13
|
+
|
14
|
+
@gem_env_paths = true
|
15
|
+
@stdlib = []
|
16
|
+
end
|
17
|
+
|
18
|
+
# @return true if bindirs from “gem environment” should be added to sandbox.
|
19
|
+
def gem_env_paths?
|
20
|
+
@gem_env_paths
|
21
|
+
end
|
22
|
+
|
23
|
+
# Enable Ruby feature set.
|
24
|
+
#
|
25
|
+
# Among others, binds `RbConfig::CONFIG["sitedir"]` so scripts works.
|
26
|
+
#
|
27
|
+
# @note This does not allow development headers needed for compilation for now.
|
28
|
+
# I’ll look at it after I have an use for it.
|
29
|
+
#
|
30
|
+
# @note Also enables {Nscd} feature.
|
31
|
+
def enable
|
32
|
+
super
|
33
|
+
|
34
|
+
@features.nscd.enable
|
35
|
+
end
|
36
|
+
|
37
|
+
# @return [Pathname|nil] path to Ruby interpreter.
|
38
|
+
def interpreter
|
39
|
+
@features.mime&.executable_path
|
40
|
+
end
|
41
|
+
|
42
|
+
# @return [Hash(String, String)] RbConfig::CONFIG from interpreter returned by {#interpreter}
|
43
|
+
def ruby_config
|
44
|
+
unless interpreter
|
45
|
+
raise "Interpreter is not set, so ruby_config() can’t be called yet."
|
46
|
+
end
|
47
|
+
|
48
|
+
return @ruby_config if @ruby_config
|
49
|
+
|
50
|
+
script = %q{RbConfig::CONFIG.each { |k, v| puts "#{k}=#{v}" }}
|
51
|
+
config_string = execvalue %W{ #{interpreter} -e #{script} }
|
52
|
+
|
53
|
+
ruby_config = {}
|
54
|
+
config_string.split("\n").each do |line|
|
55
|
+
key, value = line.split "=", 2
|
56
|
+
ruby_config[key] = value
|
57
|
+
end
|
58
|
+
|
59
|
+
@ruby_config = ruby_config
|
60
|
+
end
|
61
|
+
|
62
|
+
# Extra libraries to be loaded from script’s interpreter’s `RbConfig::CONFIG["rubyarchdir"]`.
|
63
|
+
#
|
64
|
+
# @note Existence of library paths are checked here, and not in {#stdlib=},
|
65
|
+
# to avoid error about missing interpreter, as it is set in {Bwrap::Bwrap#run},
|
66
|
+
# and config is meant to be created beforehand.
|
67
|
+
#
|
68
|
+
# @note This is only required to be called if extra dependencies are necessary.
|
69
|
+
# For example, psych.so requires libyaml.so.
|
70
|
+
#
|
71
|
+
# @return [Array] list of needed libraries.
|
72
|
+
def stdlib
|
73
|
+
# Just a little check to have error earlier.
|
74
|
+
@stdlib.each do |lib|
|
75
|
+
unless File.exist? "#{ruby_config["rubyarchdir"]}/#{lib}.so"
|
76
|
+
raise "Library “#{lib}” passed to Bwrap::Config::Ruby.stdlib= does not exist."
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
@stdlib
|
81
|
+
end
|
82
|
+
|
83
|
+
def stdlib= libs
|
84
|
+
@stdlib = libs
|
85
|
+
end
|
86
|
+
end
|
@@ -3,32 +3,14 @@
|
|
3
3
|
class Bwrap::Config
|
4
4
|
# Methods to enable or disable feature sets to control various aspects of sandboxing.
|
5
5
|
class Features
|
6
|
-
#
|
6
|
+
# Requires are here so there is no extra trickiness with namespaces.
|
7
7
|
#
|
8
|
-
#
|
9
|
-
|
10
|
-
|
11
|
-
def initialize features
|
12
|
-
@features = features
|
13
|
-
end
|
8
|
+
# Feature implementations are not meant to be used outside of this class anyway.
|
9
|
+
require_relative "features/base"
|
10
|
+
require_relative "features/ruby"
|
14
11
|
|
15
|
-
|
16
|
-
|
17
|
-
# @return [Boolean] whether feature is enabled
|
18
|
-
def enabled?
|
19
|
-
@enabled
|
20
|
-
end
|
21
|
-
|
22
|
-
# Enable the feature.
|
23
|
-
def enable
|
24
|
-
@enabled = true
|
25
|
-
end
|
26
|
-
|
27
|
-
# Disable the feature.
|
28
|
-
def disable
|
29
|
-
@enabled = false
|
30
|
-
end
|
31
|
-
end
|
12
|
+
# Instance of {Bwrap::Args::Bind::Mime}.
|
13
|
+
attr_accessor :mime
|
32
14
|
|
33
15
|
# Defines Bash feature set.
|
34
16
|
class Bash < Base
|
@@ -44,60 +26,6 @@ class Bwrap::Config
|
|
44
26
|
# Nya.
|
45
27
|
end
|
46
28
|
|
47
|
-
# Defines Ruby feature set.
|
48
|
-
#
|
49
|
-
# Implies {Nscd} feature.
|
50
|
-
class Ruby < Base
|
51
|
-
# Extra libraries to be loaded from `RbConfig::CONFIG["rubyarchdir"]`.
|
52
|
-
#
|
53
|
-
# @note This is only required to be called if extra dependencies are necessary.
|
54
|
-
# For example, psych.so requires libyaml.so.
|
55
|
-
#
|
56
|
-
# @return [Array] list of needed libraries.
|
57
|
-
#
|
58
|
-
# @overload stdlib
|
59
|
-
# @overload stdlib=(libs)
|
60
|
-
attr_reader :stdlib
|
61
|
-
|
62
|
-
def initialize features
|
63
|
-
super features
|
64
|
-
|
65
|
-
@gem_env_paths = true
|
66
|
-
@stdlib = []
|
67
|
-
end
|
68
|
-
|
69
|
-
# @return true if bindirs from “gem environment” should be added to sandbox.
|
70
|
-
def gem_env_paths?
|
71
|
-
@gem_env_paths
|
72
|
-
end
|
73
|
-
|
74
|
-
# Enable Ruby feature set.
|
75
|
-
#
|
76
|
-
# Among others, binds `RbConfig::CONFIG["sitedir"]` so scripts works.
|
77
|
-
#
|
78
|
-
# @note This does not allow development headers needed for compilation for now.
|
79
|
-
# I’ll look at it after I have an use for it.
|
80
|
-
#
|
81
|
-
# @note Also enables {Nscd} feature.
|
82
|
-
def enable
|
83
|
-
super
|
84
|
-
|
85
|
-
@features.nscd.enable
|
86
|
-
end
|
87
|
-
|
88
|
-
# @see #stdlib
|
89
|
-
def stdlib= libs
|
90
|
-
# Just a little check to have error earlier.
|
91
|
-
libs.each do |lib|
|
92
|
-
unless File.exist? "#{RbConfig::CONFIG["rubyarchdir"]}/#{lib}.so"
|
93
|
-
raise "Library “#{lib}” passed to Bwrap::Config::Ruby.stdlib= does not exist."
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
@stdlib = libs
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
29
|
# @return [Bash] Instance of feature class for Bash
|
102
30
|
def bash
|
103
31
|
@bash ||= Bash.new self
|
@@ -7,6 +7,18 @@ module Bwrap::Execution
|
|
7
7
|
|
8
8
|
# Signifies that command execution has failed.
|
9
9
|
class ExecutionFailed < CommandError
|
10
|
+
# The command that was executed.
|
11
|
+
attr_reader :command
|
12
|
+
|
13
|
+
# Output of the command.
|
14
|
+
attr_reader :output
|
15
|
+
|
16
|
+
def initialize msg, command:, output:
|
17
|
+
@command = command
|
18
|
+
@output = output
|
19
|
+
|
20
|
+
super msg
|
21
|
+
end
|
10
22
|
end
|
11
23
|
|
12
24
|
# Thrown if given command was not found.
|
@@ -63,13 +63,17 @@ class Bwrap::Execution::Execute
|
|
63
63
|
end
|
64
64
|
|
65
65
|
# Checks whether execution failed and acts accordingly.
|
66
|
-
def self.handle_execution_fail fail:, error:, output:
|
67
|
-
return unless fail and
|
66
|
+
def self.handle_execution_fail fail:, error:, output:, command:
|
67
|
+
return unless fail and !execution_success?
|
68
68
|
|
69
69
|
if error == :show and !output.empty?
|
70
70
|
Bwrap::Output.warn_output "Command failed with output:\n“#{output}”"
|
71
71
|
end
|
72
|
-
|
72
|
+
|
73
|
+
exception = Bwrap::Execution::ExecutionFailed.new "Command execution failed",
|
74
|
+
command: command,
|
75
|
+
output: output
|
76
|
+
raise exception, caller
|
73
77
|
end
|
74
78
|
|
75
79
|
# @note It makes sense for caller to just return if wait has been set and not check output.
|
@@ -101,6 +105,13 @@ class Bwrap::Execution::Execute
|
|
101
105
|
"to add “self.prepend_rootcmd(command, rootcmd:)” method."
|
102
106
|
end
|
103
107
|
|
108
|
+
# A wrapper to get status of an execution.
|
109
|
+
#
|
110
|
+
# Mainly here so test implementation is easier.
|
111
|
+
private_class_method def self.execution_success?
|
112
|
+
$CHILD_STATUS.success?
|
113
|
+
end
|
114
|
+
|
104
115
|
# Used by `#handle_logging`.
|
105
116
|
private_class_method def self.calculate_log_command command
|
106
117
|
return command.dup unless command.respond_to?(:join)
|
@@ -61,7 +61,7 @@ module Bwrap::Execution
|
|
61
61
|
end
|
62
62
|
|
63
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
|
64
|
+
# This causes spawning work correctly, as that’s how spawn() expects to have the arguments.
|
65
65
|
pid = spawn(env, *command, err: [ :child, :out ], out: Execute.w, unsetenv_others: clear_env)
|
66
66
|
output = Execute.finish_execution(log: log, wait: wait, direct_output: direct_output)
|
67
67
|
return pid unless wait
|
@@ -71,7 +71,7 @@ module Bwrap::Execution
|
|
71
71
|
@last_status = $CHILD_STATUS
|
72
72
|
|
73
73
|
output = Execute.process_output output: output
|
74
|
-
Execute.handle_execution_fail fail: fail, error: error, output: output
|
74
|
+
Execute.handle_execution_fail fail: fail, error: error, output: output, command: command
|
75
75
|
output
|
76
76
|
ensure
|
77
77
|
Execute.clean_variables
|
data/lib/bwrap/execution/path.rb
CHANGED
@@ -20,7 +20,7 @@ module Bwrap::Execution::Path
|
|
20
20
|
#
|
21
21
|
# @yield Command appended to each path in PATH environment variable
|
22
22
|
# @yieldparam path [String] Full path to executable
|
23
|
-
def self.each_env_path command, env_path_var: ENV
|
23
|
+
def self.each_env_path command, env_path_var: ENV.fetch("PATH", nil)
|
24
24
|
exts = ENV["PATHEXT"] ? ENV["PATHEXT"].split(";") : [ "" ]
|
25
25
|
|
26
26
|
env_path_var.split(File::PATH_SEPARATOR).each do |env_path|
|
@@ -39,7 +39,7 @@ module Bwrap::Execution::Path
|
|
39
39
|
# @param command [String] executable to be resolved
|
40
40
|
# @param env_path_var [String] PATH environment variable as string.
|
41
41
|
# Defaults to `ENV["PATH"]`
|
42
|
-
private def command_available? command, env_path_var: ENV
|
42
|
+
private def command_available? command, env_path_var: ENV.fetch("PATH", nil)
|
43
43
|
# Special handling for absolute paths.
|
44
44
|
path = Pathname.new command
|
45
45
|
if path.absolute?
|
@@ -60,7 +60,7 @@ module Bwrap::Execution::Path
|
|
60
60
|
# Returns path to given executable.
|
61
61
|
#
|
62
62
|
# @param (see #command_available?)
|
63
|
-
private def which command, fail: true, env_path_var: ENV
|
63
|
+
private def which command, fail: true, env_path_var: ENV.fetch("PATH", nil)
|
64
64
|
# Special handling for absolute paths.
|
65
65
|
path = Pathname.new command
|
66
66
|
if path.absolute?
|
data/lib/bwrap/output/levels.rb
CHANGED
@@ -8,7 +8,8 @@ class Bwrap::Output::Levels
|
|
8
8
|
|
9
9
|
@@_verbose = false
|
10
10
|
@@_debug = false
|
11
|
-
@@_trace = ENV
|
11
|
+
@@_trace = ENV.fetch("BWRAP_TRACE", nil) && true || false
|
12
|
+
@@_quiet = false
|
12
13
|
|
13
14
|
# @see Bwrap::Output#verbose?
|
14
15
|
def self.verbose?
|
@@ -25,8 +26,18 @@ class Bwrap::Output::Levels
|
|
25
26
|
@@_trace
|
26
27
|
end
|
27
28
|
|
29
|
+
# @see Bwrap::Output##quiet?
|
30
|
+
def self.quiet?
|
31
|
+
@@_quiet
|
32
|
+
end
|
33
|
+
|
28
34
|
# Takes hash of options received from Optimist and checks output related flags.
|
29
35
|
def self.handle_output_options options
|
36
|
+
if options[:quiet] or options[:silent]
|
37
|
+
quiet!
|
38
|
+
return
|
39
|
+
end
|
40
|
+
|
30
41
|
# Set output level flags to true or false, if it was given.
|
31
42
|
unless options[:trace].nil?
|
32
43
|
@@_verbose = options[:trace]
|
@@ -64,6 +75,18 @@ class Bwrap::Output::Levels
|
|
64
75
|
out
|
65
76
|
end
|
66
77
|
|
78
|
+
# Formats given string and outputs it.
|
79
|
+
#
|
80
|
+
# @return formatted string
|
81
|
+
def self.info_print_formatted str, log_callback: 1
|
82
|
+
# TODO: Maybe have different color for NOTICE than for INFO?
|
83
|
+
out = "#{Bwrap::Output::Colors.color(130, 230, 130, bold: true)}[NOTICE]#{Bwrap::Output::Colors.stopcolor} #{str}"
|
84
|
+
out = append_caller out, log_callback: (log_callback + 1)
|
85
|
+
puts out
|
86
|
+
|
87
|
+
out
|
88
|
+
end
|
89
|
+
|
67
90
|
# Formats given string and outputs it.
|
68
91
|
#
|
69
92
|
# @return formatted string
|
@@ -98,9 +121,16 @@ class Bwrap::Output::Levels
|
|
98
121
|
# Appends caller information to given output.
|
99
122
|
#
|
100
123
|
# Used by *_print_formatted methods.
|
101
|
-
def self.append_caller out, log_callback: 1
|
124
|
+
private_class_method def self.append_caller out, log_callback: 1
|
102
125
|
out = "#{out} (called at #{caller_locations(log_callback, 1)[0]})" if @@_trace
|
103
126
|
out
|
104
127
|
end
|
105
|
-
|
128
|
+
|
129
|
+
# Sets variables so that no extra output is shown.
|
130
|
+
private_class_method def self.quiet!
|
131
|
+
@@_verbose = false
|
132
|
+
@@_debug = false
|
133
|
+
@@_trace = false
|
134
|
+
@@_quiet = true
|
135
|
+
end
|
106
136
|
end
|
@@ -32,6 +32,8 @@ require_relative "log"
|
|
32
32
|
# When using {Bwrap::Bwrap}, {Bwrap::Bwrap#parse_command_line_arguments}
|
33
33
|
# causes output levels to be set if relevant CLI arguments have been
|
34
34
|
# given. TODO: Add documentation about CLI args somewhere. Maybe README?
|
35
|
+
#
|
36
|
+
# TODO: Add new method info() which can then be silenced using --quiet or --silent.
|
35
37
|
module Bwrap::Output
|
36
38
|
# @see #verbose?
|
37
39
|
def self.verbose?
|
@@ -43,6 +45,12 @@ module Bwrap::Output
|
|
43
45
|
Bwrap::Output::Levels.debug?
|
44
46
|
end
|
45
47
|
|
48
|
+
# @see #quiet?
|
49
|
+
# @see #info
|
50
|
+
def self.quiet?
|
51
|
+
Bwrap::Output::Levels.quiet?
|
52
|
+
end
|
53
|
+
|
46
54
|
# @see #trace?
|
47
55
|
def self.trace?
|
48
56
|
Bwrap::Output::Levels.trace?
|
@@ -89,6 +97,18 @@ module Bwrap::Output
|
|
89
97
|
Bwrap::Output::Log.puts_to_log out || str
|
90
98
|
end
|
91
99
|
|
100
|
+
# Handler used by #info to output given string.
|
101
|
+
def self.info_output str, raw: false, log_callback: 1
|
102
|
+
return if quiet?
|
103
|
+
|
104
|
+
if raw
|
105
|
+
print str
|
106
|
+
else
|
107
|
+
out = Bwrap::Output::Levels.info_print_formatted str, log_callback: (log_callback + 1)
|
108
|
+
end
|
109
|
+
Bwrap::Output::Log.puts_to_log out || str
|
110
|
+
end
|
111
|
+
|
92
112
|
# Handler used by #warn to output given string.
|
93
113
|
def self.warn_output str, raw: false, log_callback: 1
|
94
114
|
if raw
|
@@ -114,6 +134,13 @@ module Bwrap::Output
|
|
114
134
|
exit exit_code
|
115
135
|
end
|
116
136
|
|
137
|
+
# @see #info
|
138
|
+
#
|
139
|
+
# @return true if --quiet or --silent has been passed, false if not.
|
140
|
+
private def quiet?
|
141
|
+
Bwrap::Output::Levels.quiet?
|
142
|
+
end
|
143
|
+
|
117
144
|
# @return true if --verbose, --debug or --trace has been passed, false if not.
|
118
145
|
private def verbose?
|
119
146
|
Bwrap::Output::Levels.verbose?
|
@@ -161,6 +188,33 @@ module Bwrap::Output
|
|
161
188
|
Bwrap::Output.verb_output(str, raw: raw, log_callback: 2)
|
162
189
|
end
|
163
190
|
|
191
|
+
# Outputs given string if info flag has been set.
|
192
|
+
#
|
193
|
+
# This is meant for notices, and the log will be labeled with
|
194
|
+
# [NOTICE].
|
195
|
+
#
|
196
|
+
# Output flags can be set with {.handle_output_options}.
|
197
|
+
#
|
198
|
+
# == Implementation hint
|
199
|
+
#
|
200
|
+
# Usually implementing --quiet and/or --silent flag
|
201
|
+
# to control these messages (and all other output) may make
|
202
|
+
# sense.
|
203
|
+
#
|
204
|
+
# That way it would be possible to have some important
|
205
|
+
# informational messages that should be shown, but for script
|
206
|
+
# usage, those could be muted.
|
207
|
+
#
|
208
|
+
# Warning messages are meant to be shown always. Error messages
|
209
|
+
# will always be printed, as execution is halted after the
|
210
|
+
# error message has been printed.
|
211
|
+
#
|
212
|
+
# @param str String to be outputted
|
213
|
+
# @param raw [Boolean] If true, disables output formatting
|
214
|
+
private def info str, raw: false
|
215
|
+
Bwrap::Output.info_output(str, raw: raw, log_callback: 2)
|
216
|
+
end
|
217
|
+
|
164
218
|
# Outputs given string to `$stderr`.
|
165
219
|
#
|
166
220
|
# @param str String to be outputted
|