cuprum-cli 0.1.0 → 0.2.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/CHANGELOG.md +43 -0
- data/README.md +10 -0
- data/lib/cuprum/cli/argument.rb +2 -2
- data/lib/cuprum/cli/command.rb +2 -4
- data/lib/cuprum/cli/commands/ci/rspec_each_command.rb +34 -8
- data/lib/cuprum/cli/commands/ci.rb +8 -0
- data/lib/cuprum/cli/commands/file/new_command.rb +42 -49
- data/lib/cuprum/cli/commands/file.rb +8 -5
- data/lib/cuprum/cli/dependencies/clock/mock.rb +28 -0
- data/lib/cuprum/cli/dependencies/clock.rb +29 -0
- data/lib/cuprum/cli/dependencies/file_system/mock.rb +150 -18
- data/lib/cuprum/cli/dependencies/file_system.rb +145 -10
- data/lib/cuprum/cli/dependencies.rb +2 -0
- data/lib/cuprum/cli/errors.rb +0 -1
- data/lib/cuprum/cli/{commands/file/generate_file.rb → files/create_file.rb} +6 -48
- data/lib/cuprum/cli/{commands/file → files/engines}/render_erb.rb +6 -6
- data/lib/cuprum/cli/files/engines.rb +76 -0
- data/lib/cuprum/cli/{errors/files → files/errors}/file_not_writeable.rb +3 -3
- data/lib/cuprum/cli/files/errors/generator_error.rb +46 -0
- data/lib/cuprum/cli/{errors/files → files/errors}/missing_parameter.rb +5 -5
- data/lib/cuprum/cli/{errors/files → files/errors}/missing_template.rb +3 -3
- data/lib/cuprum/cli/{errors/files → files/errors}/template_error.rb +3 -3
- data/lib/cuprum/cli/files/errors.rb +19 -0
- data/lib/cuprum/cli/files/generator.rb +431 -0
- data/lib/cuprum/cli/files/generators/basic_generator.rb +15 -0
- data/lib/cuprum/cli/files/generators/rspec_generator.rb +19 -0
- data/lib/cuprum/cli/files/generators/ruby_generator.rb +32 -0
- data/lib/cuprum/cli/files/generators.rb +25 -0
- data/lib/cuprum/cli/files/template.rb +62 -0
- data/lib/cuprum/cli/files/templates/basic_template.rb +39 -0
- data/lib/cuprum/cli/files/templates/file_template.rb +60 -0
- data/lib/cuprum/cli/files/templates/string_template.rb +29 -0
- data/lib/cuprum/cli/files/templates.rb +59 -0
- data/lib/cuprum/cli/files.rb +18 -0
- data/lib/cuprum/cli/integrations/async/commands/rspec_each_command.rb +32 -0
- data/lib/cuprum/cli/integrations/async/commands.rb +11 -0
- data/lib/cuprum/cli/integrations/async.rb +21 -0
- data/lib/cuprum/cli/integrations/thor/registry.rb +7 -29
- data/lib/cuprum/cli/integrations/thor/task.rb +37 -7
- data/lib/cuprum/cli/metadata.rb +54 -5
- data/lib/cuprum/cli/option.rb +10 -4
- data/lib/cuprum/cli/options/class_methods.rb +19 -1
- data/lib/cuprum/cli/registry.rb +131 -55
- data/lib/cuprum/cli/rspec/deferred/dependencies/file_system_examples.rb +1303 -1001
- data/lib/cuprum/cli/rspec/deferred/generators_examples.rb +112 -0
- data/lib/cuprum/cli/rspec/deferred/metadata_examples.rb +300 -0
- data/lib/cuprum/cli/rspec/deferred/options_examples.rb +8 -2
- data/lib/cuprum/cli/rspec/deferred/registry_examples.rb +343 -108
- data/lib/cuprum/cli/rspec/deferred/templates_examples.rb +183 -0
- data/lib/cuprum/cli/version.rb +1 -1
- data/lib/cuprum/cli.rb +1 -0
- metadata +31 -14
- data/lib/cuprum/cli/commands/file/resolve_template.rb +0 -136
- data/lib/cuprum/cli/commands/file/templates.rb +0 -71
- data/lib/cuprum/cli/errors/files/template_not_resolved.rb +0 -54
- data/lib/cuprum/cli/errors/files.rb +0 -19
- /data/lib/cuprum/cli/{commands/file → files}/templates/rspec.rb.erb +0 -0
- /data/lib/cuprum/cli/{commands/file → files}/templates/ruby.rb.erb +0 -0
|
@@ -32,7 +32,7 @@ module Cuprum::Cli::Dependencies
|
|
|
32
32
|
def initialize(files: {}, root_path: Dir.pwd)
|
|
33
33
|
super(root_path:)
|
|
34
34
|
|
|
35
|
-
@files = files
|
|
35
|
+
@files = split_files(files)
|
|
36
36
|
@tempfiles = []
|
|
37
37
|
end
|
|
38
38
|
|
|
@@ -44,7 +44,7 @@ module Cuprum::Cli::Dependencies
|
|
|
44
44
|
|
|
45
45
|
# (see Cuprum::Cli::Dependencies::FileSystem#create_directory)
|
|
46
46
|
def create_directory(path, recursive: false) # rubocop:disable Metrics/MethodLength
|
|
47
|
-
|
|
47
|
+
validate_file_path(path, as: 'path')
|
|
48
48
|
|
|
49
49
|
*dir_names, dir_name = split_path(resolve_path(path))
|
|
50
50
|
|
|
@@ -60,15 +60,69 @@ module Cuprum::Cli::Dependencies
|
|
|
60
60
|
"unable to create directory #{path} - directory is a file"
|
|
61
61
|
end
|
|
62
62
|
|
|
63
|
-
directory[dir_name]
|
|
63
|
+
directory[dir_name] ||= {}
|
|
64
64
|
|
|
65
65
|
path
|
|
66
66
|
end
|
|
67
67
|
alias make_directory create_directory
|
|
68
68
|
|
|
69
|
+
# (see Cuprum::Cli::Dependencies::FileSystem#delete_directory)
|
|
70
|
+
def delete_directory(path, force: false, recursive: false) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
|
71
|
+
validate_file_path(path, as: 'path')
|
|
72
|
+
|
|
73
|
+
*dir_names, dir_name = split_path(resolve_path(path))
|
|
74
|
+
|
|
75
|
+
dir = dir_names.reduce(files) do |dir, dir_name|
|
|
76
|
+
require_directory(action: 'delete directory', dir: dir[dir_name], path:)
|
|
77
|
+
|
|
78
|
+
dir[dir_name]
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
require_directory(action: 'delete directory', dir: dir[dir_name], path:)
|
|
82
|
+
|
|
83
|
+
is_empty =
|
|
84
|
+
(recursive && empty_directories?(dir[dir_name])) || dir[dir_name].empty?
|
|
85
|
+
|
|
86
|
+
if force || is_empty
|
|
87
|
+
dir.delete(dir_name)
|
|
88
|
+
|
|
89
|
+
return path
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
raise DirectoryNotEmptyError,
|
|
93
|
+
"unable to delete directory #{path} - directory is not empty"
|
|
94
|
+
end
|
|
95
|
+
alias remove_directory delete_directory
|
|
96
|
+
|
|
97
|
+
# (see Cuprum::Cli::Dependencies::FileSystem#delete_file)
|
|
98
|
+
def delete_file(path) # rubocop:disable Metrics/MethodLength
|
|
99
|
+
validate_file_path(path, as: 'path')
|
|
100
|
+
|
|
101
|
+
resolved = resolve_path(path)
|
|
102
|
+
|
|
103
|
+
if directory?(resolved)
|
|
104
|
+
raise FileIsADirectoryError,
|
|
105
|
+
"unable to delete file #{path} - file is a directory"
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
unless file?(resolved)
|
|
109
|
+
raise FileNotFoundError,
|
|
110
|
+
"unable to delete file #{path} - file not found"
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
*relative, file = split_path(resolved)
|
|
114
|
+
|
|
115
|
+
directory = relative.empty? ? files : files.dig(*relative)
|
|
116
|
+
|
|
117
|
+
directory.delete(file)
|
|
118
|
+
|
|
119
|
+
path
|
|
120
|
+
end
|
|
121
|
+
alias remove_file delete_file
|
|
122
|
+
|
|
69
123
|
# (see Cuprum::Cli::Dependencies::FileSystem#directory?)
|
|
70
124
|
def directory?(path)
|
|
71
|
-
|
|
125
|
+
validate_file_path(path, as: 'path')
|
|
72
126
|
|
|
73
127
|
path = resolve_path(path)
|
|
74
128
|
mock = resolve_mock(path)
|
|
@@ -78,21 +132,33 @@ module Cuprum::Cli::Dependencies
|
|
|
78
132
|
alias directory_exists? directory?
|
|
79
133
|
|
|
80
134
|
# (see Cuprum::Cli::Dependencies::FileSystem#each_file)
|
|
81
|
-
def each_file(pattern, &)
|
|
135
|
+
def each_file(pattern, &) # rubocop:disable Metrics/AbcSize
|
|
82
136
|
return enum_for(:each_file, pattern) unless block_given?
|
|
83
137
|
|
|
84
|
-
|
|
138
|
+
absolute_path = pattern.is_a?(String) && pattern.start_with?(root_path)
|
|
139
|
+
|
|
140
|
+
pattern = pattern[(root_path.length + 1)..] if absolute_path
|
|
141
|
+
|
|
142
|
+
[*expanded_dirs, *flattened_files].each do |file_path|
|
|
85
143
|
next unless matches_pattern?(file_path:, pattern:)
|
|
86
144
|
|
|
87
|
-
yield File.join(root_path, file_path)
|
|
145
|
+
yield absolute_path ? File.join(root_path, file_path) : file_path
|
|
88
146
|
end
|
|
89
147
|
|
|
90
148
|
nil
|
|
91
149
|
end
|
|
92
150
|
|
|
151
|
+
# @return [Array<String>] a list of the defined directory paths in the mock
|
|
152
|
+
# file system.
|
|
153
|
+
def expanded_dirs = expand_dirs(files:).to_a.sort
|
|
154
|
+
|
|
155
|
+
# @return [Array<String>] a list of the defined file paths in the mock file
|
|
156
|
+
# system.
|
|
157
|
+
def flattened_files = flatten_files(files:).sort
|
|
158
|
+
|
|
93
159
|
# (see Cuprum::Cli::Dependencies::FileSystem#directory?)
|
|
94
160
|
def file?(path)
|
|
95
|
-
|
|
161
|
+
validate_file_path(path, as: 'path')
|
|
96
162
|
|
|
97
163
|
path = resolve_path(path)
|
|
98
164
|
mock = resolve_mock(path)
|
|
@@ -177,6 +243,32 @@ module Cuprum::Cli::Dependencies
|
|
|
177
243
|
|
|
178
244
|
private
|
|
179
245
|
|
|
246
|
+
def empty_directories?(dir)
|
|
247
|
+
return false unless dir.is_a?(Hash)
|
|
248
|
+
|
|
249
|
+
return true if dir.empty?
|
|
250
|
+
|
|
251
|
+
dir.each_value.all? { |item| empty_directories?(item) }
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
def expand_dirs(files:, flat: Set.new, path: '')
|
|
255
|
+
files.each do |name, value|
|
|
256
|
+
qualified_path = path.empty? ? name : File.join(path, name)
|
|
257
|
+
|
|
258
|
+
next unless value.is_a?(Hash)
|
|
259
|
+
|
|
260
|
+
flat << qualified_path
|
|
261
|
+
|
|
262
|
+
qualified_path.split('/').reduce do |memo, segment|
|
|
263
|
+
"#{memo}/#{segment}".tap { |str| flat << str }
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
expand_dirs(files: value, flat:, path: qualified_path)
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
flat
|
|
270
|
+
end
|
|
271
|
+
|
|
180
272
|
def flatten_files(files:, flat: [], path: '')
|
|
181
273
|
files.each do |name, value|
|
|
182
274
|
qualified_path = path.empty? ? name : File.join(path, name)
|
|
@@ -189,10 +281,6 @@ module Cuprum::Cli::Dependencies
|
|
|
189
281
|
flat
|
|
190
282
|
end
|
|
191
283
|
|
|
192
|
-
def flattened_files
|
|
193
|
-
@flattened_files || flatten_files(files:)
|
|
194
|
-
end
|
|
195
|
-
|
|
196
284
|
def io_stream?(file_or_path)
|
|
197
285
|
super || file_or_path.is_a?(MockTempfile)
|
|
198
286
|
end
|
|
@@ -207,12 +295,19 @@ module Cuprum::Cli::Dependencies
|
|
|
207
295
|
|
|
208
296
|
return false unless entry_names.length >= prefix_count + suffix_count
|
|
209
297
|
|
|
210
|
-
entry_names[...prefix_count]
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
298
|
+
matchers = entry_names[...prefix_count].zip(prefix_strings)
|
|
299
|
+
|
|
300
|
+
if suffix_count.zero?
|
|
301
|
+
# For a globbed pattern, if there is no suffix there must still be at
|
|
302
|
+
# least one entry to match the '**' pattern.
|
|
303
|
+
matchers.push([entry_names[prefix_count], '*'])
|
|
304
|
+
else
|
|
305
|
+
matchers.concat(entry_names[-suffix_count...].zip(suffix_strings))
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
matchers.all? do |entry_name, pattern_string|
|
|
309
|
+
matches_pattern_string?(entry_name:, pattern_string:)
|
|
310
|
+
end
|
|
216
311
|
end
|
|
217
312
|
|
|
218
313
|
def matches_pattern?(file_path:, pattern:)
|
|
@@ -242,6 +337,16 @@ module Cuprum::Cli::Dependencies
|
|
|
242
337
|
end
|
|
243
338
|
end
|
|
244
339
|
|
|
340
|
+
def require_directory(action:, dir:, path:)
|
|
341
|
+
if io_stream?(dir)
|
|
342
|
+
raise DirectoryIsAFileError,
|
|
343
|
+
"unable to #{action} #{path} - directory is a file"
|
|
344
|
+
elsif dir.nil?
|
|
345
|
+
raise DirectoryNotFoundError,
|
|
346
|
+
"unable to #{action} #{path} - directory not found"
|
|
347
|
+
end
|
|
348
|
+
end
|
|
349
|
+
|
|
245
350
|
def resolve_mock(path)
|
|
246
351
|
return unless path.start_with?(root_path)
|
|
247
352
|
|
|
@@ -256,6 +361,33 @@ module Cuprum::Cli::Dependencies
|
|
|
256
361
|
dir&.[](last)
|
|
257
362
|
end
|
|
258
363
|
|
|
364
|
+
def split_files(files) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
|
365
|
+
files.each.with_object({}) do |(key, value), hsh|
|
|
366
|
+
value = split_files(value) if value.is_a?(Hash)
|
|
367
|
+
value = StringIO.new(value) if value.is_a?(String)
|
|
368
|
+
|
|
369
|
+
next hsh[key] = value unless key.include?('/')
|
|
370
|
+
|
|
371
|
+
# Normalize key, removing root path and leading slash.
|
|
372
|
+
key = key[root_path.length..] if key.start_with?(root_path)
|
|
373
|
+
key = key[1..] if key.start_with?('/')
|
|
374
|
+
|
|
375
|
+
*dir, file = key.split('/')
|
|
376
|
+
|
|
377
|
+
# Ensure that each directory is represented by a Hash.
|
|
378
|
+
dir.each do |segment|
|
|
379
|
+
hsh[segment] = {} unless hsh.key?(segment)
|
|
380
|
+
|
|
381
|
+
raise "invalid file path #{key}" unless hsh[segment].is_a?(Hash)
|
|
382
|
+
|
|
383
|
+
hsh = hsh[segment]
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
# Assign the file or directory value.
|
|
387
|
+
hsh[file] = value
|
|
388
|
+
end
|
|
389
|
+
end
|
|
390
|
+
|
|
259
391
|
def split_path(path)
|
|
260
392
|
path[(1 + root_path.length)..]
|
|
261
393
|
&.split(File::SEPARATOR) || []
|
|
@@ -17,9 +17,15 @@ module Cuprum::Cli::Dependencies
|
|
|
17
17
|
# Exception raised when attempting to access a file as a directory.
|
|
18
18
|
class DirectoryIsAFileError < FileError; end
|
|
19
19
|
|
|
20
|
+
# Exception raised when attempting to delete a non-empty directory.
|
|
21
|
+
class DirectoryNotEmptyError < FileError; end
|
|
22
|
+
|
|
20
23
|
# Exception raised when attempting to access a non-existent directory.
|
|
21
24
|
class DirectoryNotFoundError < FileError; end
|
|
22
25
|
|
|
26
|
+
# Exception raised when attempting to overwrite an existing file.
|
|
27
|
+
class FileAlreadyExistsError < FileError; end
|
|
28
|
+
|
|
23
29
|
# Exception raised when attempting to access a directory as a file.
|
|
24
30
|
class FileIsADirectoryError < FileError; end
|
|
25
31
|
|
|
@@ -35,6 +41,57 @@ module Cuprum::Cli::Dependencies
|
|
|
35
41
|
# @return [String] the path to the root directory.
|
|
36
42
|
attr_reader :root_path
|
|
37
43
|
|
|
44
|
+
# @overload copy_file(source_path, destination_path, force: false)
|
|
45
|
+
# Copies the contents of the source file to the destination path.
|
|
46
|
+
#
|
|
47
|
+
# @param source_path [String] the path of the file to copy.
|
|
48
|
+
# @param target_path [String] the path to write the file to.
|
|
49
|
+
# @param force [true, false] if true, overwrites an existing file (not a
|
|
50
|
+
# directory) at the destination path. Defaults to false.
|
|
51
|
+
#
|
|
52
|
+
# @return [Integer] the number of bytes written.
|
|
53
|
+
#
|
|
54
|
+
# @raise [FileNotFoundError] if the file to copy does not exist.
|
|
55
|
+
# @raise [FileIsADirectoryError] if the file to copy is a directory, or if
|
|
56
|
+
# there is a directory at the destination path.
|
|
57
|
+
# @raise [FileAlreadyExistsError] if there is a file at the destination
|
|
58
|
+
# path and the force: option is false.
|
|
59
|
+
#
|
|
60
|
+
# @overload copy_file(source_path, destination_path, force: false) { |source| }
|
|
61
|
+
# Reads the source file and generates a new file with modified contents.
|
|
62
|
+
#
|
|
63
|
+
# @param source_path [String] the path of the file to copy.
|
|
64
|
+
# @param target_path [String] the path to write the file to.
|
|
65
|
+
# @param force [true, false] if true, overwrites an existing file (not a
|
|
66
|
+
# directory) at the destination path. Defaults to false.
|
|
67
|
+
#
|
|
68
|
+
# @return [Integer] the number of bytes written.
|
|
69
|
+
#
|
|
70
|
+
# @yield the transformation function used to modify the contents of the
|
|
71
|
+
# file.
|
|
72
|
+
# @yieldparam source [String] the contents of the source file.
|
|
73
|
+
# @yieldreturn [String] the contents of the destination file.
|
|
74
|
+
#
|
|
75
|
+
# @raise [FileNotFoundError] if the file to copy does not exist.
|
|
76
|
+
# @raise [FileIsADirectoryError] if the file to copy is a directory, or if
|
|
77
|
+
# there is a directory at the destination path.
|
|
78
|
+
# @raise [FileAlreadyExistsError] if there is a file at the destination
|
|
79
|
+
# path and the force: option is false.
|
|
80
|
+
def copy_file(source_path, destination_path, force: false, &block)
|
|
81
|
+
validate_file_path(source_path, as: 'source_path')
|
|
82
|
+
validate_file_path(destination_path, as: 'destination_path')
|
|
83
|
+
|
|
84
|
+
if !force && file?(destination_path)
|
|
85
|
+
raise FileAlreadyExistsError,
|
|
86
|
+
"unable to write file #{destination_path} - file already exists"
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
contents = read_file(source_path)
|
|
90
|
+
contents = block.call(contents) if block
|
|
91
|
+
|
|
92
|
+
write_file(destination_path, contents)
|
|
93
|
+
end
|
|
94
|
+
|
|
38
95
|
# Creates a directory at the requested path.
|
|
39
96
|
#
|
|
40
97
|
# @param path [String] the path to the directory.
|
|
@@ -43,13 +100,13 @@ module Cuprum::Cli::Dependencies
|
|
|
43
100
|
#
|
|
44
101
|
# @return [String] the path to the created directory.
|
|
45
102
|
def create_directory(path, recursive: false)
|
|
46
|
-
|
|
103
|
+
validate_file_path(path, as: 'path')
|
|
47
104
|
|
|
48
105
|
resolved = resolve_path(path)
|
|
49
106
|
|
|
50
107
|
return path if directory?(resolved)
|
|
51
108
|
|
|
52
|
-
|
|
109
|
+
handle_create_directory_errors(path) do
|
|
53
110
|
recursive ? FileUtils.mkdir_p(resolved) : FileUtils.mkdir(resolved)
|
|
54
111
|
end
|
|
55
112
|
|
|
@@ -57,6 +114,58 @@ module Cuprum::Cli::Dependencies
|
|
|
57
114
|
end
|
|
58
115
|
alias make_directory create_directory
|
|
59
116
|
|
|
117
|
+
# Removes the directory at the requested path.
|
|
118
|
+
#
|
|
119
|
+
# Fails if the directory contains any files or child directories. The
|
|
120
|
+
# :recursive option enables removing empty child or descendent directories,
|
|
121
|
+
# while the :force option enables removing both files and directories.
|
|
122
|
+
#
|
|
123
|
+
# @param path [String] the path to the directory.
|
|
124
|
+
# @param force [true, false] if true, removes nested files and directories.
|
|
125
|
+
# @param recursive [true, false] if true, removes nested empty directories.
|
|
126
|
+
#
|
|
127
|
+
# @return [String] the path to the removed directory.
|
|
128
|
+
def delete_directory(path, force: false, recursive: false)
|
|
129
|
+
validate_file_path(path, as: 'path')
|
|
130
|
+
|
|
131
|
+
resolved = resolve_path(path)
|
|
132
|
+
|
|
133
|
+
handle_delete_directory_errors(path) do
|
|
134
|
+
if force || (recursive && empty_directories?(resolved))
|
|
135
|
+
FileUtils.remove_dir(resolved)
|
|
136
|
+
else
|
|
137
|
+
Dir.rmdir(resolved)
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
path
|
|
142
|
+
end
|
|
143
|
+
alias remove_directory delete_directory
|
|
144
|
+
|
|
145
|
+
# Removes the file at the requested path.
|
|
146
|
+
#
|
|
147
|
+
# @param path [String] the path to the file.
|
|
148
|
+
#
|
|
149
|
+
# @return [String] the path to the removed file.
|
|
150
|
+
def delete_file(path) # rubocop:disable Metrics/MethodLength
|
|
151
|
+
validate_file_path(path, as: 'path')
|
|
152
|
+
|
|
153
|
+
resolved = resolve_path(path)
|
|
154
|
+
|
|
155
|
+
if directory?(resolved)
|
|
156
|
+
raise FileIsADirectoryError,
|
|
157
|
+
"unable to delete file #{path} - file is a directory"
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
File.delete(resolved)
|
|
161
|
+
|
|
162
|
+
path
|
|
163
|
+
rescue Errno::ENOENT, Errno::EPERM
|
|
164
|
+
raise FileNotFoundError,
|
|
165
|
+
"unable to delete file #{path} - file not found"
|
|
166
|
+
end
|
|
167
|
+
alias remove_file delete_file
|
|
168
|
+
|
|
60
169
|
# Checks if the requested directory exists.
|
|
61
170
|
#
|
|
62
171
|
# @param path [String] the path to the requested directory.
|
|
@@ -64,7 +173,7 @@ module Cuprum::Cli::Dependencies
|
|
|
64
173
|
# @return [true, false] true if the directory exists and is a directory,
|
|
65
174
|
# otherwise false.
|
|
66
175
|
def directory?(path)
|
|
67
|
-
|
|
176
|
+
validate_file_path(path, as: 'path')
|
|
68
177
|
|
|
69
178
|
path = resolve_path(path)
|
|
70
179
|
|
|
@@ -90,9 +199,7 @@ module Cuprum::Cli::Dependencies
|
|
|
90
199
|
def each_file(pattern, &)
|
|
91
200
|
return enum_for(:each_file, pattern) unless block_given?
|
|
92
201
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
Dir[path].each(&)
|
|
202
|
+
Dir.glob(pattern, base: root_path, &)
|
|
96
203
|
|
|
97
204
|
nil
|
|
98
205
|
end
|
|
@@ -104,7 +211,7 @@ module Cuprum::Cli::Dependencies
|
|
|
104
211
|
# @return [true, false] true if the file exists and is a file,
|
|
105
212
|
# otherwise false.
|
|
106
213
|
def file?(path)
|
|
107
|
-
|
|
214
|
+
validate_file_path(path, as: 'path')
|
|
108
215
|
|
|
109
216
|
path = resolve_path(path)
|
|
110
217
|
|
|
@@ -180,17 +287,21 @@ module Cuprum::Cli::Dependencies
|
|
|
180
287
|
|
|
181
288
|
path = resolve_path(file_or_path)
|
|
182
289
|
|
|
183
|
-
|
|
290
|
+
handle_write_file_errors(file_or_path) { File.write(path, data) }
|
|
184
291
|
end
|
|
185
292
|
alias write write_file
|
|
186
293
|
|
|
187
294
|
private
|
|
188
295
|
|
|
296
|
+
def empty_directories?(dir)
|
|
297
|
+
Dir[File.join(dir, '**', '*')].all? { |dir| File.directory?(dir) }
|
|
298
|
+
end
|
|
299
|
+
|
|
189
300
|
def empty_file_message(as:)
|
|
190
301
|
tools.assertions.error_message_for('presence', as:)
|
|
191
302
|
end
|
|
192
303
|
|
|
193
|
-
def
|
|
304
|
+
def handle_create_directory_errors(path)
|
|
194
305
|
yield
|
|
195
306
|
rescue Errno::EEXIST
|
|
196
307
|
raise Cuprum::Cli::Dependencies::FileSystem::DirectoryIsAFileError,
|
|
@@ -198,9 +309,25 @@ module Cuprum::Cli::Dependencies
|
|
|
198
309
|
rescue Errno::ENOENT
|
|
199
310
|
raise Cuprum::Cli::Dependencies::FileSystem::DirectoryNotFoundError,
|
|
200
311
|
"unable to create directory #{path} - directory not found"
|
|
312
|
+
rescue Errno::ENOTDIR
|
|
313
|
+
raise DirectoryIsAFileError,
|
|
314
|
+
"unable to create directory #{path} - directory is a file"
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
def handle_delete_directory_errors(path)
|
|
318
|
+
yield
|
|
319
|
+
rescue Errno::ENOENT
|
|
320
|
+
raise DirectoryNotFoundError,
|
|
321
|
+
"unable to delete directory #{path} - directory not found"
|
|
322
|
+
rescue Errno::ENOTDIR
|
|
323
|
+
raise DirectoryIsAFileError,
|
|
324
|
+
"unable to delete directory #{path} - directory is a file"
|
|
325
|
+
rescue Errno::ENOTEMPTY
|
|
326
|
+
raise DirectoryNotEmptyError,
|
|
327
|
+
"unable to delete directory #{path} - directory is not empty"
|
|
201
328
|
end
|
|
202
329
|
|
|
203
|
-
def
|
|
330
|
+
def handle_write_file_errors(file_or_path)
|
|
204
331
|
yield
|
|
205
332
|
rescue Errno::EISDIR
|
|
206
333
|
raise FileIsADirectoryError,
|
|
@@ -243,5 +370,13 @@ module Cuprum::Cli::Dependencies
|
|
|
243
370
|
raise ArgumentError, invalid_file_message(as:)
|
|
244
371
|
end
|
|
245
372
|
end
|
|
373
|
+
|
|
374
|
+
def validate_file_path(path, as:)
|
|
375
|
+
tools.assertions.validate_presence(path, as:) if path.nil?
|
|
376
|
+
|
|
377
|
+
tools.assertions.validate_instance_of(path, as:, expected: String)
|
|
378
|
+
|
|
379
|
+
tools.assertions.validate_presence(path, as:)
|
|
380
|
+
end
|
|
246
381
|
end
|
|
247
382
|
end
|
|
@@ -7,6 +7,7 @@ require 'cuprum/cli'
|
|
|
7
7
|
module Cuprum::Cli
|
|
8
8
|
# Dependencies provide standard functionality to commands.
|
|
9
9
|
module Dependencies
|
|
10
|
+
autoload :Clock, 'cuprum/cli/dependencies/clock'
|
|
10
11
|
autoload :FileSystem, 'cuprum/cli/dependencies/file_system'
|
|
11
12
|
autoload :StandardIo, 'cuprum/cli/dependencies/standard_io'
|
|
12
13
|
autoload :SystemCommand, 'cuprum/cli/dependencies/system_command'
|
|
@@ -15,6 +16,7 @@ module Cuprum::Cli
|
|
|
15
16
|
def self.provider
|
|
16
17
|
@provider ||= Plumbum::ManyProvider.new(
|
|
17
18
|
values: {
|
|
19
|
+
clock: Clock.new,
|
|
18
20
|
file_system: FileSystem.new,
|
|
19
21
|
standard_io: StandardIo.new,
|
|
20
22
|
system_command: SystemCommand.new
|
data/lib/cuprum/cli/errors.rb
CHANGED
|
@@ -3,22 +3,18 @@
|
|
|
3
3
|
require 'cuprum/command'
|
|
4
4
|
require 'plumbum'
|
|
5
5
|
|
|
6
|
-
require 'cuprum/cli/commands/file'
|
|
7
|
-
require 'cuprum/cli/commands/file/render_erb'
|
|
8
6
|
require 'cuprum/cli/dependencies'
|
|
9
7
|
require 'cuprum/cli/dependencies/file_system'
|
|
10
|
-
require 'cuprum/cli/
|
|
8
|
+
require 'cuprum/cli/files'
|
|
11
9
|
require 'cuprum/cli/options'
|
|
12
10
|
|
|
13
|
-
module Cuprum::Cli::
|
|
14
|
-
# Utility command for
|
|
15
|
-
class
|
|
11
|
+
module Cuprum::Cli::Files
|
|
12
|
+
# Utility command for creating a file with specified contents.
|
|
13
|
+
class CreateFile < Cuprum::Command
|
|
16
14
|
include Plumbum::Consumer
|
|
17
15
|
prepend Plumbum::Parameters
|
|
18
16
|
include Cuprum::Cli::Dependencies::StandardIo::Helpers
|
|
19
17
|
extend Cuprum::Cli::Options::ClassMethods
|
|
20
|
-
include Cuprum::Cli::Options::Quiet
|
|
21
|
-
include Cuprum::Cli::Options::Verbose
|
|
22
18
|
|
|
23
19
|
dependency :file_system
|
|
24
20
|
dependency :standard_io
|
|
@@ -77,28 +73,10 @@ module Cuprum::Cli::Commands::File
|
|
|
77
73
|
end
|
|
78
74
|
|
|
79
75
|
def file_not_writeable_error(**)
|
|
80
|
-
Cuprum::Cli::Errors::
|
|
76
|
+
Cuprum::Cli::Files::Errors::FileNotWriteable.new(**)
|
|
81
77
|
end
|
|
82
78
|
|
|
83
|
-
def
|
|
84
|
-
file_system.read_file(template_path)
|
|
85
|
-
rescue Cuprum::Cli::Dependencies::FileSystem::FileNotFoundError
|
|
86
|
-
error = Cuprum::Cli::Errors::Files::MissingTemplate.new(
|
|
87
|
-
message: "unable to generate file #{file_path}",
|
|
88
|
-
template_path:
|
|
89
|
-
)
|
|
90
|
-
failure(error)
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
def process(file_path:, parameters:, template_path:)
|
|
94
|
-
say "Generating file #{file_path}..."
|
|
95
|
-
|
|
96
|
-
template = step { load_template(file_path:, template_path:) }
|
|
97
|
-
contents =
|
|
98
|
-
step { render_template(parameters:, template:, template_path:) }
|
|
99
|
-
|
|
100
|
-
report_file_contents(contents)
|
|
101
|
-
|
|
79
|
+
def process(contents:, file_path:)
|
|
102
80
|
step { create_directory(file_path:) }
|
|
103
81
|
|
|
104
82
|
step { write_file(contents:, file_path:) }
|
|
@@ -106,26 +84,6 @@ module Cuprum::Cli::Commands::File
|
|
|
106
84
|
file_path
|
|
107
85
|
end
|
|
108
86
|
|
|
109
|
-
def render_template(parameters:, template:, template_path:)
|
|
110
|
-
case File.extname(template_path)
|
|
111
|
-
when '.erb'
|
|
112
|
-
RenderErb.new(template_name: template_path).call(template, **parameters)
|
|
113
|
-
else
|
|
114
|
-
template
|
|
115
|
-
end
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
def report_file_contents(contents)
|
|
119
|
-
say "\n", verbose: true
|
|
120
|
-
say(
|
|
121
|
-
contents
|
|
122
|
-
.each_line
|
|
123
|
-
.map { |line| line == "\n" ? "\n" : " #{line}" }.join,
|
|
124
|
-
verbose: true
|
|
125
|
-
)
|
|
126
|
-
say "\n", verbose: true
|
|
127
|
-
end
|
|
128
|
-
|
|
129
87
|
def write_file(contents:, file_path:)
|
|
130
88
|
step { check_if_file_is_directory(file_path:) }
|
|
131
89
|
step { check_if_file_already_exists(file_path:) }
|
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
require 'cuprum/command'
|
|
4
4
|
require 'herb'
|
|
5
5
|
|
|
6
|
-
require 'cuprum/cli/
|
|
7
|
-
require 'cuprum/cli/errors/
|
|
6
|
+
require 'cuprum/cli/files/engines'
|
|
7
|
+
require 'cuprum/cli/files/errors/missing_parameter'
|
|
8
8
|
|
|
9
|
-
module Cuprum::Cli::
|
|
9
|
+
module Cuprum::Cli::Files::Engines
|
|
10
10
|
# Utility command for generating file contents from an .erb template.
|
|
11
11
|
class RenderErb < Cuprum::Command
|
|
12
12
|
class RenderingContext < BasicObject; end
|
|
@@ -29,7 +29,7 @@ module Cuprum::Cli::Commands::File
|
|
|
29
29
|
message = 'unable to render ERB template'
|
|
30
30
|
message = "#{message} #{template_name}" if template_name
|
|
31
31
|
|
|
32
|
-
Cuprum::Cli::Errors::
|
|
32
|
+
Cuprum::Cli::Files::Errors::TemplateError.new(message:, details:)
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
def empty_binding = RenderingContext.new.instance_exec { Kernel.binding }
|
|
@@ -50,7 +50,7 @@ module Cuprum::Cli::Commands::File
|
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
def missing_parameter_error(parameter_name)
|
|
53
|
-
Cuprum::Cli::Errors::
|
|
53
|
+
Cuprum::Cli::Files::Errors::MissingParameter.new(
|
|
54
54
|
message: 'unable to render ERB template',
|
|
55
55
|
parameter_name:,
|
|
56
56
|
template_name:
|
|
@@ -79,7 +79,7 @@ module Cuprum::Cli::Commands::File
|
|
|
79
79
|
end
|
|
80
80
|
|
|
81
81
|
def template_error(message)
|
|
82
|
-
Cuprum::Cli::Errors::
|
|
82
|
+
Cuprum::Cli::Files::Errors::TemplateError.new(
|
|
83
83
|
message: "unable to render ERB template - #{message}",
|
|
84
84
|
template_name:
|
|
85
85
|
)
|