bovem 3.0.5 → 4.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
- data/.gitignore +4 -3
- data/.rubocop.yml +82 -0
- data/.travis-gemfile +4 -5
- data/.travis.yml +8 -6
- data/CHANGELOG.md +12 -0
- data/Gemfile +9 -8
- data/README.md +1 -1
- data/Rakefile +22 -6
- data/bovem.gemspec +5 -5
- data/doc/Bovem.html +10 -10
- data/doc/Bovem/Application.html +670 -318
- data/doc/Bovem/Command.html +1447 -1125
- data/doc/Bovem/CommandMethods.html +4 -4
- data/doc/Bovem/CommandMethods/Children.html +173 -179
- data/doc/Bovem/CommandMethods/Help.html +9 -9
- data/doc/Bovem/Configuration.html +239 -24
- data/doc/Bovem/Console.html +267 -128
- data/doc/Bovem/ConsoleMethods.html +4 -4
- data/doc/Bovem/ConsoleMethods/Interactions.html +57 -70
- data/doc/Bovem/ConsoleMethods/Interactions/ClassMethods.html +9 -9
- data/doc/Bovem/ConsoleMethods/Logging.html +258 -298
- data/doc/Bovem/ConsoleMethods/Logging/ClassMethods.html +8 -8
- data/doc/Bovem/ConsoleMethods/Output.html +96 -118
- data/doc/Bovem/ConsoleMethods/StyleHandling.html +8 -8
- data/doc/Bovem/ConsoleMethods/StyleHandling/ClassMethods.html +26 -39
- data/doc/Bovem/Errors.html +4 -4
- data/doc/Bovem/Errors/Error.html +4 -4
- data/doc/Bovem/Errors/InvalidConfiguration.html +4 -4
- data/doc/Bovem/Errors/InvalidLogger.html +4 -4
- data/doc/Bovem/I18n.html +175 -0
- data/doc/Bovem/Logger.html +95 -83
- data/doc/Bovem/Option.html +669 -862
- data/doc/Bovem/Parser.html +10 -10
- data/doc/Bovem/ParserMethods.html +4 -4
- data/doc/Bovem/ParserMethods/General.html +4 -4
- data/doc/Bovem/ParserMethods/General/ClassMethods.html +26 -38
- data/doc/Bovem/Shell.html +169 -48
- data/doc/Bovem/ShellMethods.html +4 -4
- data/doc/Bovem/ShellMethods/Directories.html +46 -62
- data/doc/Bovem/ShellMethods/Execute.html +51 -99
- data/doc/Bovem/ShellMethods/General.html +4 -445
- data/doc/Bovem/ShellMethods/Read.html +56 -61
- data/doc/Bovem/ShellMethods/Write.html +22 -242
- data/doc/Bovem/Version.html +6 -6
- data/doc/_index.html +18 -18
- data/doc/class_list.html +6 -2
- data/doc/css/style.css +1 -0
- data/doc/file.README.html +5 -5
- data/doc/file_list.html +5 -1
- data/doc/frames.html +1 -1
- data/doc/index.html +5 -5
- data/doc/js/full_list.js +4 -1
- data/doc/method_list.html +161 -157
- data/doc/top-level-namespace.html +4 -4
- data/lib/bovem.rb +3 -4
- data/lib/bovem/application.rb +47 -39
- data/lib/bovem/command.rb +175 -193
- data/lib/bovem/configuration.rb +28 -29
- data/lib/bovem/console.rb +244 -171
- data/lib/bovem/errors.rb +1 -1
- data/lib/bovem/i18n.rb +18 -0
- data/lib/bovem/logger.rb +26 -26
- data/lib/bovem/option.rb +49 -58
- data/lib/bovem/parser.rb +174 -222
- data/lib/bovem/shell.rb +272 -320
- data/lib/bovem/version.rb +2 -2
- data/locales/en.yml +39 -38
- data/locales/it.yml +39 -38
- data/spec/bovem/application_spec.rb +6 -5
- data/spec/bovem/command_spec.rb +23 -23
- data/spec/bovem/console_spec.rb +101 -102
- data/spec/bovem/i18n_spec.rb +21 -0
- data/spec/bovem/logger_spec.rb +4 -4
- data/spec/bovem/option_spec.rb +43 -43
- data/spec/bovem/parser_spec.rb +13 -13
- data/spec/bovem/shell_spec.rb +106 -115
- data/spec/spec_helper.rb +19 -6
- metadata +14 -13
- data/doc/Bovem/Localizer.html +0 -376
- data/lib/bovem/localizer.rb +0 -27
- data/spec/coverage_helper.rb +0 -20
data/lib/bovem/shell.rb
CHANGED
@@ -9,47 +9,32 @@ module Bovem
|
|
9
9
|
module ShellMethods
|
10
10
|
# General methods.
|
11
11
|
module General
|
12
|
-
|
13
|
-
|
14
|
-
#
|
15
|
-
# @param access_error [String|Symbol] The message to show in case of access errors.
|
16
|
-
# @param not_found_error [String|Symbol] The message to show in case of a not found entry.
|
17
|
-
# @param general_error [String|Symbol] The message to show in case of other errors.
|
18
|
-
# @param entries [Array] The list of entries which failed.
|
19
|
-
# @param fatal [Boolean] If quit in case of fatal errors.
|
20
|
-
# @param show_errors [Boolean] Whether to show errors.
|
12
|
+
private
|
13
|
+
|
14
|
+
# :nodoc:
|
21
15
|
def handle_failure(e, access_error, not_found_error, general_error, entries, fatal, show_errors)
|
22
|
-
error_type,
|
16
|
+
error_type, final_entries = setup_error_handling(entries, fatal)
|
23
17
|
|
24
18
|
case e.class.to_s
|
25
|
-
|
26
|
-
|
27
|
-
|
19
|
+
when "Errno::EACCES" then @console.send(error_type, i18n.send(access_error, final_entries))
|
20
|
+
when "Errno::ENOENT" then @console.send(error_type, i18n.send(not_found_error, final_entries))
|
21
|
+
else show_general_failure(e, general_error, entries, fatal) if show_errors
|
28
22
|
end
|
29
23
|
end
|
30
24
|
|
31
|
-
#
|
32
|
-
#
|
33
|
-
# @param entries [Array] The list of entries which failed.
|
34
|
-
# @param fatal [Boolean] If quit in case of fatal errors.
|
35
|
-
# @return [Array] Variables for error handling
|
25
|
+
# :nodoc:
|
36
26
|
def setup_error_handling(entries, fatal)
|
37
|
-
[fatal ? :fatal : :error,
|
27
|
+
[fatal ? :fatal : :error, entries.length == 1 ? entries[0] : entries]
|
38
28
|
end
|
39
29
|
|
40
|
-
#
|
41
|
-
#
|
42
|
-
# @param e [Exception] The occurred exception.
|
43
|
-
# @param entries [Array] The list of entries which failed.
|
44
|
-
# @param fatal [Boolean] If quit in case of fatal errors.
|
30
|
+
# :nodoc:
|
45
31
|
def show_general_failure(e, general_error, entries, fatal)
|
46
|
-
|
47
|
-
|
48
|
-
@console.error(locale.send(general_error))
|
32
|
+
@console.error(i18n.send(general_error))
|
49
33
|
@console.with_indentation(11) do
|
50
|
-
entries.each
|
34
|
+
entries.each { |entry| @console.write(entry) }
|
51
35
|
end
|
52
|
-
|
36
|
+
|
37
|
+
@console.write(i18n.error(e.class.to_s, e), suffix: "\n", indented: 5)
|
53
38
|
Kernel.exit(-1) if fatal
|
54
39
|
end
|
55
40
|
end
|
@@ -58,55 +43,56 @@ module Bovem
|
|
58
43
|
module Read
|
59
44
|
# Tests a path against a list of test.
|
60
45
|
#
|
61
|
-
# Valid tests are every method available in http://www.ruby-doc.org/core-
|
46
|
+
# Valid tests are every method available in http://www.ruby-doc.org/core-2.3.0/FileTest.html (plus `read`, `write`, `execute`, `exec`, `dir`).
|
47
|
+
# Trailing question mark can be omitted. Unrecognized tests will make the check fail.
|
62
48
|
#
|
63
49
|
# @param path [String] The path to test.
|
64
50
|
# @param tests [Array] The list of tests to perform.
|
65
|
-
def check(path, tests)
|
51
|
+
def check(path, *tests)
|
66
52
|
path = path.ensure_string
|
67
53
|
|
68
|
-
tests.ensure_array.all?
|
54
|
+
tests.ensure_array(no_duplicates: true, compact: true, flatten: true).all? do |test|
|
69
55
|
# Adjust test name
|
70
56
|
test = test.ensure_string.strip
|
71
57
|
|
72
|
-
test =
|
58
|
+
test =
|
59
|
+
case test
|
73
60
|
when "read" then "readable"
|
74
61
|
when "write" then "writable"
|
75
62
|
when "execute", "exec" then "executable"
|
76
63
|
when "dir" then "directory"
|
77
64
|
else test
|
78
|
-
|
65
|
+
end
|
79
66
|
|
80
67
|
# Execute test
|
81
68
|
test += "?" if test !~ /\?$/
|
82
69
|
FileTest.respond_to?(test) ? FileTest.send(test, path) : nil
|
83
|
-
|
70
|
+
end
|
84
71
|
end
|
85
72
|
|
86
73
|
# Find a list of files in directories matching given regexps or patterns.
|
87
74
|
#
|
88
|
-
# You can also pass a block to perform matching. The block will receive a single argument and the path will be considered
|
75
|
+
# You can also pass a block to perform matching. The block will receive a single argument and the path will be considered if return value is not falsey.
|
89
76
|
#
|
90
77
|
# Inside the block, you can call `Find.prune` to stop searching in the current directory.
|
91
78
|
#
|
92
79
|
# @param directories [String] A list of directories where to search files.
|
93
80
|
# @param patterns [Array] A list of regexps or patterns to match files. If empty, every file is returned. Ignored if a block is provided.
|
94
|
-
# @param
|
81
|
+
# @param extension_only [Boolean] If to only search in extensions. Ignored if a block is provided.
|
95
82
|
# @param case_sensitive [Boolean] If the search is case sensitive. Only meaningful for string patterns.
|
96
83
|
# @param block [Proc] An optional block to perform matching instead of pattern matching.
|
97
|
-
def find(directories, patterns
|
84
|
+
def find(directories, patterns: [], extension_only: false, case_sensitive: false, &block)
|
98
85
|
rv = []
|
99
86
|
|
100
|
-
directories = directories.ensure_array(
|
101
|
-
patterns = normalize_patterns(patterns,
|
87
|
+
directories = directories.ensure_array(no_duplicates: true, compact: true, flatten: true) { |d| File.expand_path(d.ensure_string) }
|
88
|
+
patterns = normalize_patterns(patterns, extension_only, case_sensitive)
|
102
89
|
|
103
90
|
directories.each do |directory|
|
104
|
-
|
105
|
-
|
106
|
-
|
91
|
+
next unless check(directory, [:directory, :readable, :executable])
|
92
|
+
Find.find(directory) do |entry|
|
93
|
+
found = patterns.blank? ? true : match_pattern(entry, patterns, extension_only, &block)
|
107
94
|
|
108
|
-
|
109
|
-
end
|
95
|
+
rv << entry if found
|
110
96
|
end
|
111
97
|
end
|
112
98
|
|
@@ -114,40 +100,33 @@ module Bovem
|
|
114
100
|
end
|
115
101
|
|
116
102
|
private
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
#
|
121
|
-
|
122
|
-
|
123
|
-
def normalize_patterns(patterns, by_extension, case_sensitive)
|
124
|
-
# Adjust patterns
|
125
|
-
patterns = patterns.ensure_array(nil, true, true) {|p| p.is_a?(::Regexp) ? p : Regexp.new(Regexp.quote(p.ensure_string)) }
|
126
|
-
patterns = patterns.map {|p| /(#{p.source})$/ } if by_extension
|
127
|
-
patterns = patterns.map {|p| /#{p.source}/i } if !case_sensitive
|
128
|
-
patterns
|
103
|
+
|
104
|
+
# :nodoc:
|
105
|
+
def normalize_patterns(patterns, by_extension, case_sensitive)
|
106
|
+
# Adjust patterns
|
107
|
+
patterns = patterns.ensure_array(no_duplicates: true, compact: true, flatten: true) do |p|
|
108
|
+
p.is_a?(::Regexp) ? p : Regexp.new(Regexp.quote(p.ensure_string))
|
129
109
|
end
|
130
110
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
# @param by_extension [Boolean] If to only search in extensions. Ignored if a block is provided.
|
136
|
-
# @param block [Proc|nil] An optional block to run instead of pattern matching.
|
137
|
-
# @return [Boolean] `true` if entry matched, `false` otherwise.
|
138
|
-
def match_pattern(entry, patterns, by_extension, &block)
|
139
|
-
catch(:found) do
|
140
|
-
if block then
|
141
|
-
throw(:found, true) if block.call(entry)
|
142
|
-
else
|
143
|
-
patterns.each do |pattern|
|
144
|
-
throw(:found, true) if pattern.match(entry) && (!by_extension || !File.directory?(entry))
|
145
|
-
end
|
146
|
-
end
|
111
|
+
patterns = patterns.map { |p| /(#{p.source})$/ } if by_extension
|
112
|
+
patterns = patterns.map { |p| /#{p.source}/i } unless case_sensitive
|
113
|
+
patterns
|
114
|
+
end
|
147
115
|
|
148
|
-
|
116
|
+
# :nodoc:
|
117
|
+
def match_pattern(entry, patterns, by_extension)
|
118
|
+
catch(:found) do
|
119
|
+
if block_given?
|
120
|
+
throw(:found, true) if yield(entry)
|
121
|
+
else
|
122
|
+
patterns.each do |pattern|
|
123
|
+
throw(:found, true) if pattern.match(entry) && (!by_extension || !File.directory?(entry))
|
124
|
+
end
|
149
125
|
end
|
126
|
+
|
127
|
+
false
|
150
128
|
end
|
129
|
+
end
|
151
130
|
end
|
152
131
|
|
153
132
|
# Methods to copy or move entries.
|
@@ -158,10 +137,10 @@ module Bovem
|
|
158
137
|
# @param dst [String] The destination. **Any existing entries will be overwritten.** Any required directory will be created.
|
159
138
|
# @param run [Boolean] If `false`, it will just print a list of message that would be copied or moved.
|
160
139
|
# @param show_errors [Boolean] If show errors.
|
161
|
-
# @param
|
140
|
+
# @param fatal_errors [Boolean] If quit in case of fatal errors.
|
162
141
|
# @return [Boolean] `true` if operation succeeded, `false` otherwise.
|
163
|
-
def copy(src, dst, run
|
164
|
-
copy_or_move(src, dst, :copy, run, show_errors,
|
142
|
+
def copy(src, dst, run: true, show_errors: false, fatal_errors: true)
|
143
|
+
copy_or_move(src, dst, operation: :copy, run: run, show_errors: show_errors, fatal_errors: fatal_errors)
|
165
144
|
end
|
166
145
|
|
167
146
|
# Moves a set of files or directory to another location.
|
@@ -170,26 +149,20 @@ module Bovem
|
|
170
149
|
# @param dst [String] The destination. **Any existing entries will be overwritten.** Any required directory will be created.
|
171
150
|
# @param run [Boolean] If `false`, it will just print a list of message that would be deleted.
|
172
151
|
# @param show_errors [Boolean] If show errors.
|
173
|
-
# @param
|
152
|
+
# @param fatal_errors [Boolean] If quit in case of fatal errors.
|
174
153
|
# @return [Boolean] `true` if operation succeeded, `false` otherwise.
|
175
|
-
def move(src, dst, run
|
176
|
-
copy_or_move(src, dst, :move, run, show_errors,
|
154
|
+
def move(src, dst, run: true, show_errors: false, fatal_errors: true)
|
155
|
+
copy_or_move(src, dst, operation: :move, run: run, show_errors: show_errors, fatal_errors: fatal_errors)
|
177
156
|
end
|
178
157
|
|
179
|
-
|
180
|
-
|
181
|
-
#
|
182
|
-
# @param dst [String] The destination. **Any existing entries will be overwritten.** Any required directory will be created.
|
183
|
-
# @param operation [Symbol] The operation to perform. Valid values are `:copy` or `:move`.
|
184
|
-
# @param run [Boolean] If `false`, it will just print a list of message that would be copied or moved.
|
185
|
-
# @param show_errors [Boolean] If show errors.
|
186
|
-
# @param fatal [Boolean] If quit in case of fatal errors.
|
187
|
-
# @return [Boolean] `true` if operation succeeded, `false` otherwise.
|
158
|
+
private
|
159
|
+
|
160
|
+
# :nodoc:
|
188
161
|
def copy_or_move(src, dst, operation, run = true, show_errors = true, fatal = true)
|
189
162
|
rv = true
|
190
163
|
operation, operation_s, single, src, dst = sanitize_copy_or_move(operation, src, dst)
|
191
164
|
|
192
|
-
if !run
|
165
|
+
if !run
|
193
166
|
dry_run_copy_or_move(single, operation_s, src, dst)
|
194
167
|
else
|
195
168
|
rv = catch(:rv) do
|
@@ -203,135 +176,118 @@ module Bovem
|
|
203
176
|
rv
|
204
177
|
end
|
205
178
|
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
179
|
+
# :nodoc:
|
180
|
+
def sanitize_copy_or_move(operation, src, dst)
|
181
|
+
operation = :copy if operation != :move
|
182
|
+
single = !src.is_a?(Array)
|
183
|
+
src = single ? File.expand_path(src) : src.map { |s| File.expand_path(s) }
|
184
|
+
|
185
|
+
[operation, i18n.send(operation), single, src, File.expand_path(dst.ensure_string)]
|
186
|
+
end
|
187
|
+
|
188
|
+
# :nodoc:
|
189
|
+
def dry_run_copy_or_move(single, operation, src, dst)
|
190
|
+
if single
|
191
|
+
dry_run_copy_or_move_single(src, dst, operation)
|
192
|
+
else
|
193
|
+
dry_run_copy_or_move_multi(src, dst, operation)
|
219
194
|
end
|
195
|
+
end
|
220
196
|
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
@console.write(
|
234
|
-
else
|
235
|
-
@console.warn(locale.copy_move_multi_dry(operation))
|
236
|
-
@console.with_indentation(11) do
|
237
|
-
src.each do |s| @console.write(s) end
|
238
|
-
end
|
239
|
-
@console.write(locale.copy_move_to_multi(dst), "\n", 5)
|
197
|
+
# :nodoc:
|
198
|
+
def dry_run_copy_or_move_single(src, dst, operation)
|
199
|
+
@console.warn(i18n.copy_move_single_dry(operation))
|
200
|
+
@console.write(i18n.copy_move_from(File.expand_path(src.ensure_string)), suffix: "\n", indented: 11)
|
201
|
+
@console.write(i18n.copy_move_to(dst), suffix: "\n", indented: 11)
|
202
|
+
end
|
203
|
+
|
204
|
+
# :nodoc:
|
205
|
+
def dry_run_copy_or_move_multi(src, dst, operation)
|
206
|
+
@console.warn(i18n.copy_move_multi_dry(operation))
|
207
|
+
@console.with_indentation(11) do
|
208
|
+
src.each do |s|
|
209
|
+
@console.write(s)
|
240
210
|
end
|
241
211
|
end
|
212
|
+
@console.write(i18n.copy_move_to_multi(dst), suffix: "\n", indented: 5)
|
213
|
+
end
|
242
214
|
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
# @param dst [String] The destination. **Any existing entries will be overwritten.** Any required directory will be created.
|
248
|
-
# @param operation [String] The operation which will be executed.
|
249
|
-
# @param show_errors [Boolean] If show errors.
|
250
|
-
# @param fatal [Boolean] If quit in case of fatal errors.
|
251
|
-
# @return [String] The prepared destination.
|
252
|
-
def prepare_destination(single, src, dst, operation, show_errors, fatal)
|
253
|
-
dst_dir = single ? File.dirname(dst) : dst
|
254
|
-
has_dir = check(dst_dir, :dir)
|
255
|
-
|
256
|
-
# Create directory
|
257
|
-
has_dir = create_directories(dst_dir, 0755, true, show_errors, fatal) if !has_dir
|
258
|
-
throw(:rv, false) if !has_dir
|
259
|
-
|
260
|
-
if single && check(dst, :dir) then
|
261
|
-
@console.send(fatal ? :fatal : :error, i18n.shell.copy_move_single_to_directory(operation, src, dst))
|
262
|
-
throw(:rv, false)
|
263
|
-
end
|
215
|
+
# :nodoc:
|
216
|
+
def prepare_destination(single, src, dst, operation, show_errors, fatal)
|
217
|
+
dst_dir = single ? File.dirname(dst) : dst
|
218
|
+
has_dir = check(dst_dir, :dir)
|
264
219
|
|
265
|
-
|
266
|
-
|
220
|
+
# Create directory
|
221
|
+
has_dir = create_directories(dst_dir, mode: 0755, show_errors: show_errors, fatal_errors: fatal) unless has_dir
|
222
|
+
throw(:rv, false) unless has_dir
|
267
223
|
|
268
|
-
#
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
# @param fatal [Boolean] If quit in case of fatal errors.
|
273
|
-
def check_sources(src, operation, fatal)
|
274
|
-
# Check that every file is existing
|
275
|
-
src.ensure_array.each do |s|
|
276
|
-
if !check(s, :exists) then
|
277
|
-
@console.send(fatal ? :fatal : :error, i18n.shell.copy_move_src_not_found(operation, s))
|
278
|
-
throw(:rv, false)
|
279
|
-
end
|
280
|
-
end
|
224
|
+
# Check if the destination directory is a file in single mode
|
225
|
+
if single && check(dst, :dir)
|
226
|
+
@console.send(fatal ? :fatal : :error, i18n.copy_move_single_to_directory(operation, src, dst))
|
227
|
+
throw(:rv, false)
|
281
228
|
end
|
282
229
|
|
283
|
-
|
284
|
-
|
285
|
-
# @param src [String|Array] The entries to copy or move. If is an Array, `dst` is assumed to be a directory.
|
286
|
-
# @param dst [String] The destination. **Any existing entries will be overwritten.** Any required directory will be created.
|
287
|
-
# @param dst_dir [String] The destination directory.
|
288
|
-
# @param single [Boolean] Whether `src` is a single file or directory.
|
289
|
-
# @param operation [Symbol] The operation to perform. Valid values are `:copy` or `:move`.
|
290
|
-
# @param operation_s [String] The string representation of the operation to perform.
|
291
|
-
# @param show_errors [Boolean] If show errors.
|
292
|
-
# @param fatal [Boolean] If quit in case of fatal errors.
|
293
|
-
def execute_copy_or_move(src, dst, dst_dir, single, operation, operation_s, show_errors, fatal)
|
294
|
-
locale = i18n.shell
|
230
|
+
dst_dir
|
231
|
+
end
|
295
232
|
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
single_msg = locale.copy_move_error_single(operation_s, src, dst_dir, e.class.to_s, e)
|
304
|
-
multi_msg = locale.copy_move_error_multi(operation_s, dst)
|
305
|
-
handle_copy_move_failure(single, src, show_errors, fatal, single_msg, multi_msg, locale.error(e.class.to_s, e))
|
233
|
+
# :nodoc:
|
234
|
+
def check_sources(src, operation, fatal)
|
235
|
+
# Check that every file is existing
|
236
|
+
src.ensure_array.each do |s|
|
237
|
+
unless check(s, :exists)
|
238
|
+
@console.send(fatal ? :fatal : :error, i18n.copy_move_src_not_found(operation, s))
|
239
|
+
throw(:rv, false)
|
306
240
|
end
|
307
241
|
end
|
242
|
+
end
|
308
243
|
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
@console.with_indentation(11) do
|
325
|
-
src.each do |s| @console.write(s) end
|
326
|
-
end
|
327
|
-
@console.write(error, "\n", 5) if error
|
328
|
-
end
|
244
|
+
# :nodoc:
|
245
|
+
def execute_copy_or_move(src, dst, dst_dir, single, operation, operation_s, show_errors, fatal)
|
246
|
+
FileUtils.send(operation == :move ? :mv : :cp_r, src, dst, {noop: false, verbose: false})
|
247
|
+
rescue Errno::EACCES
|
248
|
+
handle_copy_or_move_access_error(src, dst, dst_dir, single, operation_s, show_errors, fatal)
|
249
|
+
rescue => e
|
250
|
+
handle_copy_or_move_general_erorr(src, dst, dst_dir, single, e, operation_s, show_errors, fatal)
|
251
|
+
end
|
252
|
+
|
253
|
+
# :nodoc:
|
254
|
+
def handle_copy_or_move_general_erorr(src, dst, dst_dir, single, e, operation_s, show_errors, fatal)
|
255
|
+
single_msg = i18n.copy_move_error_single(operation_s, src, dst_dir, e.class.to_s, e)
|
256
|
+
multi_msg = i18n.copy_move_error_multi(operation_s, dst)
|
257
|
+
handle_copy_or_move_failure(single, src, show_errors, fatal, single_msg, multi_msg, i18n.error(e.class.to_s, e))
|
258
|
+
end
|
329
259
|
|
260
|
+
# :nodoc:
|
261
|
+
def handle_copy_or_move_access_error(src, dst, dst_dir, single, operation_s, show_errors, fatal)
|
262
|
+
single_msg = i18n.copy_move_dst_not_writable_single(operation_s, src, dst_dir)
|
263
|
+
multi_msg = i18n.copy_move_dst_not_writable_multi(operation_s, dst)
|
264
|
+
handle_copy_or_move_failure(single, src, show_errors, fatal, single_msg, multi_msg, nil)
|
265
|
+
end
|
266
|
+
|
267
|
+
# :nodoc:
|
268
|
+
def handle_copy_or_move_failure(single, src, show_errors, fatal, single_msg, multi_msg, error)
|
269
|
+
if fatal || show_errors
|
270
|
+
if single
|
271
|
+
@console.send(fatal ? :fatal : :error, single_msg, suffix: "\n", indented: 5)
|
272
|
+
else
|
273
|
+
show_copy_move_failed_files(src, error, multi_msg)
|
330
274
|
Kernel.exit(-1) if fatal
|
331
275
|
end
|
276
|
+
end
|
332
277
|
|
333
|
-
|
278
|
+
throw(:rv, false)
|
279
|
+
end
|
280
|
+
|
281
|
+
# :nodoc:
|
282
|
+
def show_copy_move_failed_files(src, error, multi_msg)
|
283
|
+
@console.error(multi_msg)
|
284
|
+
@console.with_indentation(11) do
|
285
|
+
src.each do |s|
|
286
|
+
@console.write(s)
|
287
|
+
end
|
334
288
|
end
|
289
|
+
@console.write(error, suffix: "\n", indented: 5) if error
|
290
|
+
end
|
335
291
|
end
|
336
292
|
|
337
293
|
# Methods to run commands or delete entries.
|
@@ -344,26 +300,23 @@ module Bovem
|
|
344
300
|
# @param show_exit [Boolean] If show the exit status.
|
345
301
|
# @param show_output [Boolean] If show command output.
|
346
302
|
# @param show_command [Boolean] If show the command that will be run.
|
347
|
-
# @param
|
303
|
+
# @param fatal_errors [Boolean] If quit in case of fatal errors.
|
348
304
|
# @return [Hash] An hash with `status` and `output` keys.
|
349
|
-
def run(command, message = nil, run
|
305
|
+
def run(command, message = nil, run: true, show_exit: true, show_output: false, show_command: false, fatal_errors: true)
|
350
306
|
rv = {status: 0, output: ""}
|
351
307
|
command = command.ensure_string
|
352
|
-
locale = i18n.shell
|
353
308
|
|
354
309
|
# Show the command
|
355
310
|
@console.begin(message) if message.present?
|
356
311
|
|
357
|
-
if !run
|
358
|
-
|
359
|
-
@console.status(:ok) if show_exit
|
312
|
+
if !run # Print a message
|
313
|
+
show_dry_run(command, show_exit)
|
360
314
|
else # Run
|
361
315
|
rv = execute_command(command, show_command, show_output)
|
362
316
|
end
|
363
317
|
|
364
318
|
# Return
|
365
|
-
|
366
|
-
exit(rv[:status]) if fatal && rv[:status] != 0
|
319
|
+
handle_command_exit(rv, show_exit, fatal_errors)
|
367
320
|
rv
|
368
321
|
end
|
369
322
|
|
@@ -372,54 +325,73 @@ module Bovem
|
|
372
325
|
# @param files [Array] The list of files to remove
|
373
326
|
# @param run [Boolean] If `false`, it will just print a list of message that would be deleted.
|
374
327
|
# @param show_errors [Boolean] If show errors.
|
375
|
-
# @param
|
328
|
+
# @param fatal_errors [Boolean] If quit in case of fatal errors.
|
376
329
|
# @return [Boolean] `true` if operation succeeded, `false` otherwise.
|
377
|
-
def delete(files, run
|
330
|
+
def delete(*files, run: true, show_errors: false, fatal_errors: true)
|
378
331
|
rv = true
|
379
|
-
|
380
|
-
files = files.ensure_array(nil, true, true) {|f| File.expand_path(f.ensure_string) }
|
332
|
+
files = files.ensure_array(no_duplicates: true, compact: true, flatten: true) { |f| File.expand_path(f.ensure_string) }
|
381
333
|
|
382
|
-
if !run
|
383
|
-
|
384
|
-
@console.with_indentation(11) do
|
385
|
-
files.each do |file| @console.write(file) end
|
386
|
-
end
|
334
|
+
if !run
|
335
|
+
show_dry_delete(files)
|
387
336
|
else
|
388
|
-
rv =
|
389
|
-
begin
|
390
|
-
FileUtils.rm_r(files, {noop: false, verbose: false, secure: true})
|
391
|
-
throw(:rv, true)
|
392
|
-
rescue => e
|
393
|
-
handle_failure(e, :remove_unwritable, :remove_not_found, :remove_error, files, fatal, show_errors)
|
394
|
-
end
|
395
|
-
|
396
|
-
false
|
397
|
-
end
|
337
|
+
rv = perform_delete(files, show_errors, fatal_errors)
|
398
338
|
end
|
399
339
|
|
400
340
|
rv
|
401
341
|
end
|
402
342
|
|
403
343
|
private
|
404
|
-
# Runs a command into the shell.
|
405
|
-
#
|
406
|
-
# @param command [String] The string to run.
|
407
|
-
# @param show_command [Boolean] If show the command that will be run.
|
408
|
-
# @param show_output [Boolean] If show command output.
|
409
|
-
# @return [Hash] An hash with `status` and `output` keys.
|
410
|
-
def execute_command(command, show_command, show_output)
|
411
|
-
output = ""
|
412
|
-
|
413
|
-
@console.info(i18n.shell.run(command)) if show_command
|
414
|
-
status = ::Open4::popen4(command + " 2>&1") { |_, _, stdout, _|
|
415
|
-
stdout.each_line do |line|
|
416
|
-
output << line
|
417
|
-
Kernel.print line if show_output
|
418
|
-
end
|
419
|
-
}.exitstatus
|
420
344
|
|
421
|
-
|
345
|
+
# :nodoc:
|
346
|
+
def execute_command(command, show_command, show_output)
|
347
|
+
output = ""
|
348
|
+
|
349
|
+
@console.info(i18n.run(command)) if show_command
|
350
|
+
status = ::Open4.popen4(command + " 2>&1") do |_, _, stdout, _|
|
351
|
+
stdout.each_line do |line|
|
352
|
+
output << line
|
353
|
+
Kernel.print line if show_output
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
{status: status.exitstatus, output: output}
|
358
|
+
end
|
359
|
+
|
360
|
+
# :nodoc:
|
361
|
+
def handle_command_exit(rv, show_exit, fatal_errors)
|
362
|
+
@console.status(rv[:status] == 0 ? :ok : :fail) if show_exit
|
363
|
+
exit(rv[:status]) if fatal_errors && rv[:status] != 0
|
364
|
+
end
|
365
|
+
|
366
|
+
# :nodoc:
|
367
|
+
def show_dry_run(command, show_exit)
|
368
|
+
@console.warn(i18n.run_dry(command))
|
369
|
+
@console.status(:ok) if show_exit
|
370
|
+
end
|
371
|
+
|
372
|
+
# :nodoc:
|
373
|
+
def perform_delete(files, show_errors, fatal)
|
374
|
+
catch(:rv) do
|
375
|
+
begin
|
376
|
+
FileUtils.rm_r(files, {noop: false, verbose: false, secure: true})
|
377
|
+
throw(:rv, true)
|
378
|
+
rescue => e
|
379
|
+
handle_failure(e, :remove_unwritable, :remove_not_found, :remove_error, files, fatal, show_errors)
|
380
|
+
end
|
381
|
+
|
382
|
+
false
|
422
383
|
end
|
384
|
+
end
|
385
|
+
|
386
|
+
# :nodoc:
|
387
|
+
def show_dry_delete(files)
|
388
|
+
@console.warn(i18n.remove_dry)
|
389
|
+
@console.with_indentation(11) do
|
390
|
+
files.each do |file|
|
391
|
+
@console.write(file)
|
392
|
+
end
|
393
|
+
end
|
394
|
+
end
|
423
395
|
end
|
424
396
|
|
425
397
|
# Methods to interact with directories.
|
@@ -430,15 +402,13 @@ module Bovem
|
|
430
402
|
# @param restore [Boolean] If to restore the original working directory.
|
431
403
|
# @param show_messages [Boolean] Show informative messages about working directory changes.
|
432
404
|
# @return [Boolean] `true` if the directory was valid and the code executed, `false` otherwise.
|
433
|
-
def within_directory(directory, restore
|
434
|
-
locale = i18n.shell
|
435
|
-
|
405
|
+
def within_directory(directory, restore: true, show_messages: false)
|
436
406
|
directory = File.expand_path(directory.ensure_string)
|
437
407
|
original = Dir.pwd
|
438
408
|
|
439
|
-
rv = enter_directory(directory, show_messages,
|
409
|
+
rv = enter_directory(directory, show_messages, i18n.move_in(directory))
|
440
410
|
yield if rv && block_given?
|
441
|
-
rv = enter_directory(original, show_messages,
|
411
|
+
rv = enter_directory(original, show_messages, i18n.move_out(directory)) if rv && restore
|
442
412
|
|
443
413
|
rv
|
444
414
|
end
|
@@ -449,20 +419,20 @@ module Bovem
|
|
449
419
|
# @param mode [Fixnum] Initial permissions for the new directories.
|
450
420
|
# @param run [Boolean] If `false`, it will just print a list of directories that would be created.
|
451
421
|
# @param show_errors [Boolean] If show errors.
|
452
|
-
# @param
|
422
|
+
# @param fatal_errors [Boolean] If quit in case of fatal errors.
|
453
423
|
# @return [Boolean] `true` if operation succeeded, `false` otherwise.
|
454
|
-
def create_directories(directories, mode
|
424
|
+
def create_directories(*directories, mode: 0755, run: true, show_errors: false, fatal_errors: true)
|
455
425
|
rv = true
|
456
426
|
|
457
427
|
# Adjust directory
|
458
|
-
directories = directories.ensure_array(
|
428
|
+
directories = directories.ensure_array(no_duplicates: true, compact: true, flatten: true) { |d| File.expand_path(d.ensure_string) }
|
459
429
|
|
460
|
-
if !run
|
430
|
+
if !run # Just print
|
461
431
|
dry_run_directory_creation(directories)
|
462
432
|
else
|
463
433
|
directories.each do |directory|
|
464
|
-
rv
|
465
|
-
break
|
434
|
+
rv &&= try_create_directory(directory, mode, fatal_errors, directories, show_errors)
|
435
|
+
break unless rv
|
466
436
|
end
|
467
437
|
end
|
468
438
|
|
@@ -470,76 +440,56 @@ module Bovem
|
|
470
440
|
end
|
471
441
|
|
472
442
|
private
|
473
|
-
# Change current working directory.
|
474
|
-
#
|
475
|
-
# @param directory [String] The directory which move into.
|
476
|
-
# @param show_message [Boolean] Whether to show or not message.
|
477
|
-
# @param message [String] The message to show.
|
478
|
-
# @return [Boolean] `true` if operation succeeded, `false` otherwise.
|
479
|
-
def enter_directory(directory, show_message, message)
|
480
|
-
begin
|
481
|
-
raise ArgumentError if !check(directory, [:directory, :executable])
|
482
|
-
@console.info(message) if show_message
|
483
|
-
Dir.chdir(directory)
|
484
|
-
true
|
485
|
-
rescue
|
486
|
-
false
|
487
|
-
end
|
488
|
-
end
|
489
443
|
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
444
|
+
# :nodoc:
|
445
|
+
def enter_directory(directory, show_message, message)
|
446
|
+
raise ArgumentError unless check(directory, :directory, :executable)
|
447
|
+
@console.info(message) if show_message
|
448
|
+
Dir.chdir(directory)
|
449
|
+
true
|
450
|
+
rescue
|
451
|
+
false
|
452
|
+
end
|
453
|
+
|
454
|
+
# :nodoc:
|
455
|
+
def dry_run_directory_creation(directories)
|
456
|
+
@console.warn(i18n.mkdir_dry)
|
457
|
+
@console.with_indentation(11) do
|
458
|
+
directories.each do |directory|
|
459
|
+
@console.write(directory)
|
496
460
|
end
|
497
461
|
end
|
462
|
+
end
|
498
463
|
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
# @param mode [Fixnum] Initial permissions for the new directories.
|
503
|
-
# @param fatal [Boolean] If quit in case of fatal errors.
|
504
|
-
# @param directories [Array] The list of directories to create.
|
505
|
-
# @param show_errors [Boolean] If show errors.
|
506
|
-
# @return [Boolean] `true` if operation succeeded, `false` otherwise.
|
507
|
-
def try_create_directory(directory, mode, fatal, directories, show_errors)
|
508
|
-
rv = false
|
509
|
-
locale = i18n.shell
|
510
|
-
|
511
|
-
# Perform tests
|
512
|
-
if check(directory, :directory) then
|
513
|
-
@console.send(fatal ? :fatal : :error, locale.mkdir_existing(directory))
|
514
|
-
elsif check(directory, :exist) then
|
515
|
-
@console.send(fatal ? :fatal : :error, locale.mkdir_file(directory))
|
516
|
-
else
|
517
|
-
rv = create_directory(directory, mode, fatal, directories, show_errors)
|
518
|
-
end
|
464
|
+
# :nodoc:
|
465
|
+
def try_create_directory(directory, mode, fatal, directories, show_errors)
|
466
|
+
rv = false
|
519
467
|
|
520
|
-
|
468
|
+
# Perform tests
|
469
|
+
if check(directory, :directory)
|
470
|
+
@console.send(fatal ? :fatal : :error, i18n.mkdir_existing(directory))
|
471
|
+
elsif check(directory, :exist)
|
472
|
+
@console.send(fatal ? :fatal : :error, i18n.mkdir_file(directory))
|
473
|
+
else
|
474
|
+
rv = create_directory(directory, mode, fatal, directories, show_errors)
|
521
475
|
end
|
522
476
|
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
# @param show_errors [Boolean] If show errors.
|
530
|
-
# @return [Boolean] `true` if operation succeeded, `false` otherwise.
|
531
|
-
def create_directory(directory, mode, fatal, directories, show_errors)
|
532
|
-
rv = false
|
533
|
-
|
534
|
-
begin # Create directory
|
535
|
-
FileUtils.mkdir_p(directory, {mode: mode, noop: false, verbose: false})
|
536
|
-
rv = true
|
537
|
-
rescue => e
|
538
|
-
handle_failure(e, :mkdir_denied, nil, :mkdir_error, directories, fatal, show_errors)
|
539
|
-
end
|
477
|
+
rv
|
478
|
+
end
|
479
|
+
|
480
|
+
# :nodoc:
|
481
|
+
def create_directory(directory, mode, fatal, directories, show_errors)
|
482
|
+
rv = false
|
540
483
|
|
541
|
-
|
484
|
+
begin # Create directory
|
485
|
+
FileUtils.mkdir_p(directory, {mode: mode, noop: false, verbose: false})
|
486
|
+
rv = true
|
487
|
+
rescue => e
|
488
|
+
handle_failure(e, :mkdir_denied, nil, :mkdir_error, directories, fatal, show_errors)
|
542
489
|
end
|
490
|
+
|
491
|
+
rv
|
492
|
+
end
|
543
493
|
end
|
544
494
|
end
|
545
495
|
|
@@ -547,8 +497,9 @@ module Bovem
|
|
547
497
|
#
|
548
498
|
# @attribute console
|
549
499
|
# @return [Console] A console instance.
|
500
|
+
# @attribute [r] i18n
|
501
|
+
# @return [I18n] A i18n helper.
|
550
502
|
class Shell
|
551
|
-
include Lazier::I18n
|
552
503
|
include Bovem::ShellMethods::General
|
553
504
|
include Bovem::ShellMethods::Read
|
554
505
|
include Bovem::ShellMethods::Write
|
@@ -556,6 +507,7 @@ module Bovem
|
|
556
507
|
include Bovem::ShellMethods::Directories
|
557
508
|
|
558
509
|
attr_accessor :console
|
510
|
+
attr_reader :i18n
|
559
511
|
|
560
512
|
# Returns a unique instance for Shell.
|
561
513
|
#
|
@@ -567,7 +519,7 @@ module Bovem
|
|
567
519
|
# Initializes a new Shell.
|
568
520
|
def initialize
|
569
521
|
@console = Bovem::Console.instance
|
570
|
-
|
522
|
+
@i18n = Bovem::I18n.new(root: "bovem.shell", path: Bovem::Application::LOCALE_ROOT)
|
571
523
|
end
|
572
524
|
end
|
573
|
-
end
|
525
|
+
end
|