planter-cli 3.0.4 → 3.0.7
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/.irbrc +2 -1
- data/.rubocop.yml +4 -3
- data/.rubocop_todo.yml +63 -0
- data/.yardopts +3 -2
- data/CHANGELOG.md +28 -0
- data/Guardfile +1 -1
- data/README.md +132 -46
- data/Rakefile +0 -3
- data/bin/plant +5 -4
- data/lib/planter/array.rb +15 -1
- data/lib/planter/color.rb +8 -4
- data/lib/planter/config.rb +185 -0
- data/lib/planter/fileentry.rb +9 -3
- data/lib/planter/filelist.rb +28 -2
- data/lib/planter/numeric.rb +39 -0
- data/lib/planter/plant.rb +24 -17
- data/lib/planter/prompt.rb +43 -11
- data/lib/planter/script.rb +3 -3
- data/lib/planter/string.rb +153 -74
- data/lib/planter/tag.rb +43 -1
- data/lib/planter/version.rb +1 -1
- data/lib/planter.rb +39 -108
- data/lib/tty-spinner/lib/tty/spinner/multi.rb +3 -3
- data/planter-cli.gemspec +3 -1
- data/spec/cli_spec.rb +12 -2
- data/spec/planter/filelist_spec.rb +2 -2
- data/spec/planter/prompt_spec.rb +71 -0
- data/spec/planter/script_spec.rb +5 -4
- data/spec/planter/string_spec.rb +26 -0
- data/spec/spec_helper.rb +3 -2
- data/spec/templates/test/_planter.yml +2 -0
- data/spec/templates/test/_scripts/plant.sh +3 -0
- data/src/_README.md +132 -46
- metadata +11 -4
@@ -0,0 +1,185 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Planter
|
4
|
+
## Configuration class
|
5
|
+
class Config < Hash
|
6
|
+
attr_reader :template
|
7
|
+
|
8
|
+
##
|
9
|
+
## Initialize a new Config object for a template
|
10
|
+
##
|
11
|
+
def initialize
|
12
|
+
super()
|
13
|
+
|
14
|
+
@config = initial_config
|
15
|
+
@template = Planter.template
|
16
|
+
|
17
|
+
load_template
|
18
|
+
|
19
|
+
die('No configuration found', :config) unless @config
|
20
|
+
|
21
|
+
generate_accessors
|
22
|
+
end
|
23
|
+
|
24
|
+
## String representation of the configuration
|
25
|
+
def to_s
|
26
|
+
@config.to_s
|
27
|
+
end
|
28
|
+
|
29
|
+
## Get a config key
|
30
|
+
##
|
31
|
+
## @param key [String,Symbol] key
|
32
|
+
##
|
33
|
+
## @return [String] value
|
34
|
+
##
|
35
|
+
def [](key)
|
36
|
+
@config[key]
|
37
|
+
end
|
38
|
+
|
39
|
+
##
|
40
|
+
## Set a config option
|
41
|
+
##
|
42
|
+
## @param key [String,Symbol] key
|
43
|
+
## @param value [String] value
|
44
|
+
##
|
45
|
+
def []=(key, value)
|
46
|
+
@config[key.to_sym] = value
|
47
|
+
generate_accessors
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
## Default configuration
|
53
|
+
##
|
54
|
+
## @return [Hash] default configuration
|
55
|
+
##
|
56
|
+
## @api private
|
57
|
+
##
|
58
|
+
def initial_config
|
59
|
+
{
|
60
|
+
defaults: false,
|
61
|
+
git_init: false,
|
62
|
+
files: { '_planter.yml' => 'ignore' },
|
63
|
+
color: true,
|
64
|
+
preserve_tags: nil,
|
65
|
+
variables: nil,
|
66
|
+
replacements: nil,
|
67
|
+
repo: false,
|
68
|
+
patterns: nil,
|
69
|
+
debug: false,
|
70
|
+
script: nil
|
71
|
+
}
|
72
|
+
end
|
73
|
+
|
74
|
+
## Generate accessors for configuration
|
75
|
+
##
|
76
|
+
## @api private
|
77
|
+
##
|
78
|
+
def generate_accessors
|
79
|
+
@config.each do |k, v|
|
80
|
+
define_singleton_method(k) { v } unless respond_to?(k)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
##
|
85
|
+
## Build a configuration from template name
|
86
|
+
##
|
87
|
+
## @return [Hash] Configuration object
|
88
|
+
##
|
89
|
+
## @api private
|
90
|
+
##
|
91
|
+
def load_template
|
92
|
+
Planter.variables ||= {}
|
93
|
+
FileUtils.mkdir_p(Planter.base_dir) unless File.directory?(Planter.base_dir)
|
94
|
+
base_config = File.join(Planter.base_dir, 'planter.yml')
|
95
|
+
|
96
|
+
if File.exist?(base_config)
|
97
|
+
@config = @config.deep_merge(YAML.load(IO.read(base_config)).symbolize_keys)
|
98
|
+
else
|
99
|
+
default_base_config = {
|
100
|
+
defaults: false,
|
101
|
+
git_init: false,
|
102
|
+
files: { '_planter.yml' => 'ignore' },
|
103
|
+
color: true,
|
104
|
+
preserve_tags: true
|
105
|
+
}
|
106
|
+
begin
|
107
|
+
File.open(base_config, 'w') { |f| f.puts(YAML.dump(default_base_config.stringify_keys)) }
|
108
|
+
rescue Errno::ENOENT
|
109
|
+
Planter.notify("Unable to create #{base_config}", :error)
|
110
|
+
end
|
111
|
+
@config = @config.deep_merge(default_base_config).symbolize_keys
|
112
|
+
Planter.notify("New configuration written to #{base_config}, edit as needed.", :warn)
|
113
|
+
end
|
114
|
+
|
115
|
+
base_dir = File.join(Planter.base_dir, 'templates', @template)
|
116
|
+
unless File.directory?(base_dir)
|
117
|
+
notify("Template #{@template} does not exist", :error)
|
118
|
+
res = Prompt.yn('Create template directory', default_response: false)
|
119
|
+
|
120
|
+
die('Canceled') unless res
|
121
|
+
|
122
|
+
FileUtils.mkdir_p(base_dir)
|
123
|
+
end
|
124
|
+
|
125
|
+
load_template_config
|
126
|
+
|
127
|
+
config_array_to_hash(:files) if @config[:files].is_a?(Array)
|
128
|
+
config_array_to_hash(:replacements) if @config[:replacements].is_a?(Array)
|
129
|
+
rescue Psych::SyntaxError => e
|
130
|
+
die("Parse error in configuration file:\n#{e.message}", :config)
|
131
|
+
end
|
132
|
+
|
133
|
+
##
|
134
|
+
## Load a template-specific configuration
|
135
|
+
##
|
136
|
+
## @return [Hash] updated config object
|
137
|
+
##
|
138
|
+
## @api private
|
139
|
+
##
|
140
|
+
def load_template_config
|
141
|
+
base_dir = File.join(Planter.base_dir, 'templates', @template)
|
142
|
+
config = File.join(base_dir, '_planter.yml')
|
143
|
+
|
144
|
+
unless File.exist?(config)
|
145
|
+
default_config = {
|
146
|
+
variables: [
|
147
|
+
key: 'var_key',
|
148
|
+
prompt: 'CLI Prompt',
|
149
|
+
type: '[string, float, integer, number, date]',
|
150
|
+
value: '(optional, force value, can include variables. Empty to prompt. For date type: today, now, etc.)',
|
151
|
+
default: '(optional default value, leave empty or remove key for no default)',
|
152
|
+
min: '(optional, for number type set a minimum value)',
|
153
|
+
max: '(optional, for number type set a maximum value)'
|
154
|
+
],
|
155
|
+
git_init: false,
|
156
|
+
files: {
|
157
|
+
'*.tmp' => 'ignore',
|
158
|
+
'*.bak' => 'ignore',
|
159
|
+
'.DS_Store' => 'ignore'
|
160
|
+
}
|
161
|
+
}
|
162
|
+
FileUtils.mkdir_p(base_dir)
|
163
|
+
File.open(config, 'w') { |f| f.puts(YAML.dump(default_config.stringify_keys)) }
|
164
|
+
Planter.notify("New configuration written to #{config}, please edit.", :warn)
|
165
|
+
Process.exit 0
|
166
|
+
end
|
167
|
+
@config = @config.deep_merge(YAML.load(IO.read(config)).symbolize_keys)
|
168
|
+
end
|
169
|
+
|
170
|
+
##
|
171
|
+
## Convert an errant array to a hash
|
172
|
+
##
|
173
|
+
## @param key [Symbol] The key in @config to convert
|
174
|
+
##
|
175
|
+
## @api private
|
176
|
+
##
|
177
|
+
def config_array_to_hash(key)
|
178
|
+
files = {}
|
179
|
+
@config[key].each do |k|
|
180
|
+
files[k.keys.first] = k.values.first
|
181
|
+
end
|
182
|
+
@config[key] = files
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
data/lib/planter/fileentry.rb
CHANGED
@@ -6,8 +6,14 @@ module Planter
|
|
6
6
|
# Operation to execute on the file
|
7
7
|
attr_accessor :operation
|
8
8
|
|
9
|
-
# File path
|
10
|
-
attr_reader :file
|
9
|
+
# File path
|
10
|
+
attr_reader :file
|
11
|
+
|
12
|
+
# Target path
|
13
|
+
attr_reader :target
|
14
|
+
|
15
|
+
# Tags
|
16
|
+
attr_reader :tags
|
11
17
|
|
12
18
|
##
|
13
19
|
## Initialize a FileEntry object
|
@@ -19,7 +25,7 @@ module Planter
|
|
19
25
|
## @return [FileEntry] a Hash of parameters
|
20
26
|
##
|
21
27
|
def initialize(file, target, operation)
|
22
|
-
return
|
28
|
+
return unless File.exist?(file)
|
23
29
|
|
24
30
|
@file = file
|
25
31
|
@target = target
|
data/lib/planter/filelist.rb
CHANGED
@@ -50,6 +50,10 @@ module Planter
|
|
50
50
|
##
|
51
51
|
## @param entry [FileEntry] The file entry
|
52
52
|
##
|
53
|
+
## @return [Boolean] success
|
54
|
+
##
|
55
|
+
## @api private
|
56
|
+
##
|
53
57
|
def handle_operator(entry)
|
54
58
|
case entry.operation
|
55
59
|
when :ignore
|
@@ -65,8 +69,17 @@ module Planter
|
|
65
69
|
apply_tags(entry)
|
66
70
|
end
|
67
71
|
|
72
|
+
#
|
73
|
+
# Apply tags to the target file from the source file
|
74
|
+
#
|
75
|
+
# @param [FileEntry] entry
|
76
|
+
#
|
77
|
+
# @return [Boolean] success
|
78
|
+
#
|
79
|
+
# @api private
|
80
|
+
#
|
68
81
|
def apply_tags(entry)
|
69
|
-
return unless Planter.config
|
82
|
+
return unless Planter.config.preserve_tags
|
70
83
|
|
71
84
|
Tag.copy(entry.file, entry.target) if File.exist?(entry.target)
|
72
85
|
end
|
@@ -76,6 +89,8 @@ module Planter
|
|
76
89
|
##
|
77
90
|
## @return [Boolean] success
|
78
91
|
##
|
92
|
+
## @api private
|
93
|
+
##
|
79
94
|
def prepare_copy
|
80
95
|
@files.each do |entry|
|
81
96
|
if entry.matches_pattern?
|
@@ -90,6 +105,10 @@ module Planter
|
|
90
105
|
##
|
91
106
|
## @param entry [FileEntry] The file entry
|
92
107
|
##
|
108
|
+
## @return [Boolean] success
|
109
|
+
##
|
110
|
+
## @api private
|
111
|
+
##
|
93
112
|
def propogate_operation(entry)
|
94
113
|
@files.each do |file|
|
95
114
|
file.operation = entry.operation if file.file =~ /^#{entry.file}/
|
@@ -104,6 +123,8 @@ module Planter
|
|
104
123
|
##
|
105
124
|
## @return [Boolean] success
|
106
125
|
##
|
126
|
+
## @api private
|
127
|
+
##
|
107
128
|
def merge(entry)
|
108
129
|
return copy_file(entry) if File.directory?(entry.file)
|
109
130
|
|
@@ -157,7 +178,12 @@ module Planter
|
|
157
178
|
##
|
158
179
|
## @return [Boolean] success
|
159
180
|
##
|
181
|
+
## @api private
|
182
|
+
##
|
160
183
|
def copy_file(file, overwrite: false)
|
184
|
+
# If the target file already exists and overwrite is true,
|
185
|
+
# or Planter.overwrite is true, then delete the target file
|
186
|
+
FileUtils.rm_rf(file.target) if (overwrite || Planter.overwrite) && File.exist?(file.target)
|
161
187
|
# Check if the target file already exists
|
162
188
|
# If it does and overwrite is true, or Planter.overwrite is true,
|
163
189
|
# or if the file doesn't exist, then copy the file
|
@@ -165,7 +191,7 @@ module Planter
|
|
165
191
|
# Make sure the target directory exists
|
166
192
|
FileUtils.mkdir_p(File.dirname(file.target))
|
167
193
|
# Copy the file if it isn't a directory
|
168
|
-
FileUtils.
|
194
|
+
FileUtils.cp_r(file.file, file.target) unless File.directory?(file.file)
|
169
195
|
# Log a message to the console
|
170
196
|
Planter.notify("[Copied] #{file.file} => #{file.target}", :debug, above_spinner: true)
|
171
197
|
# Return true to indicate success
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Planter
|
4
|
+
# Integer extensions
|
5
|
+
class ::Integer
|
6
|
+
# Clean value (dummy method)
|
7
|
+
def clean_value
|
8
|
+
self
|
9
|
+
end
|
10
|
+
|
11
|
+
# Has selector (dummy method)
|
12
|
+
def selector?
|
13
|
+
true
|
14
|
+
end
|
15
|
+
|
16
|
+
# Highlight character
|
17
|
+
def highlight_character(default: nil)
|
18
|
+
"(#{self})".highlight_character(default: default)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Float extensions
|
23
|
+
class ::Float
|
24
|
+
# Clean value (dummy method)
|
25
|
+
def clean_value
|
26
|
+
self
|
27
|
+
end
|
28
|
+
|
29
|
+
# Has selector (dummy method)
|
30
|
+
def selector?
|
31
|
+
true
|
32
|
+
end
|
33
|
+
|
34
|
+
# Highlight character
|
35
|
+
def highlight_character(default: nil)
|
36
|
+
"(#{self})".highlight_character(default: default)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/planter/plant.rb
CHANGED
@@ -3,6 +3,8 @@
|
|
3
3
|
module Planter
|
4
4
|
# Primary class
|
5
5
|
class Plant
|
6
|
+
attr_reader :config
|
7
|
+
|
6
8
|
##
|
7
9
|
## Initialize a new Plant object
|
8
10
|
##
|
@@ -11,20 +13,24 @@ module Planter
|
|
11
13
|
##
|
12
14
|
def initialize(template = nil, variables = nil)
|
13
15
|
Planter.variables = variables if variables.is_a?(Hash)
|
14
|
-
Planter.config = template if template
|
16
|
+
# Planter.config = template if template
|
17
|
+
template ||= Planter.template
|
18
|
+
die('No template specified', :config) unless template
|
19
|
+
|
20
|
+
@config = Planter::Config.new
|
15
21
|
|
16
|
-
@basedir = File.join(Planter.base_dir, 'templates',
|
22
|
+
@basedir = File.join(Planter.base_dir, 'templates', @config.template)
|
17
23
|
@target = Planter.target || Dir.pwd
|
18
24
|
|
19
|
-
@git =
|
25
|
+
@git = @config.git_init || false
|
20
26
|
@debug = Planter.debug
|
21
|
-
@repo =
|
27
|
+
@repo = @config.repo || false
|
22
28
|
|
23
29
|
# Coerce any existing variables (like from the command line) to the types
|
24
30
|
# defined in configuration
|
25
31
|
coerced = {}
|
26
32
|
Planter.variables.each do |k, v|
|
27
|
-
cfg_var =
|
33
|
+
cfg_var = @config.variables.select { |var| k = var[:key] }
|
28
34
|
next unless cfg_var.count.positive?
|
29
35
|
|
30
36
|
var = cfg_var.first
|
@@ -34,7 +40,7 @@ module Planter
|
|
34
40
|
coerced.each { |k, v| Planter.variables[k] = v }
|
35
41
|
|
36
42
|
# Ask user for any variables not already defined
|
37
|
-
|
43
|
+
@config.variables.each do |var|
|
38
44
|
key = var[:key].to_var
|
39
45
|
next if Planter.variables.keys.include?(key)
|
40
46
|
|
@@ -46,7 +52,8 @@ module Planter
|
|
46
52
|
value: var[:value],
|
47
53
|
min: var[:min],
|
48
54
|
max: var[:max],
|
49
|
-
choices: var[:choices] || nil
|
55
|
+
choices: var[:choices] || nil,
|
56
|
+
date_format: var[:date_format] || nil
|
50
57
|
)
|
51
58
|
answer = q.ask
|
52
59
|
if answer.nil?
|
@@ -55,7 +62,7 @@ module Planter
|
|
55
62
|
answer = var[:default]
|
56
63
|
end
|
57
64
|
|
58
|
-
Planter.variables[key] = answer
|
65
|
+
Planter.variables[key] = answer.apply_all
|
59
66
|
end
|
60
67
|
|
61
68
|
git_pull if @repo
|
@@ -94,26 +101,26 @@ module Planter
|
|
94
101
|
def git_pull
|
95
102
|
Planter.spinner.update(title: 'Pulling git repo')
|
96
103
|
|
97
|
-
|
104
|
+
die('`git` executable not found', :git) unless TTY::Which.exist?('git')
|
98
105
|
|
99
106
|
pwd = Dir.pwd
|
100
107
|
@repo = expand_repo(@repo)
|
101
108
|
|
102
109
|
if File.exist?(repo_dir)
|
103
110
|
Dir.chdir(repo_dir)
|
104
|
-
|
111
|
+
die("Directory #{repo_dir} exists but is not git repo", :git) unless File.exist?('.git')
|
105
112
|
|
106
113
|
res = `git pull`
|
107
|
-
|
114
|
+
die("Error pulling #{@repo}:\n#{res}", :git) unless $?.success?
|
108
115
|
else
|
109
116
|
Dir.chdir(@basedir)
|
110
117
|
res = `git clone "#{@repo}" "#{repo_dir}"`
|
111
|
-
|
118
|
+
die("Error cloning #{@repo}:\n#{res}", :git) unless $?.success?
|
112
119
|
end
|
113
120
|
Dir.chdir(pwd)
|
114
121
|
@basedir = repo_dir
|
115
122
|
rescue StandardError => e
|
116
|
-
|
123
|
+
die("Error pulling #{@repo}:\n#{e.message}", :git)
|
117
124
|
end
|
118
125
|
|
119
126
|
##
|
@@ -139,7 +146,7 @@ module Planter
|
|
139
146
|
end
|
140
147
|
|
141
148
|
if @git
|
142
|
-
|
149
|
+
die('`git` executable not found', :git) unless TTY::Which.exist?('git')
|
143
150
|
|
144
151
|
Planter.spinner.update(title: 'Initializing git repo')
|
145
152
|
res = add_git
|
@@ -149,10 +156,10 @@ module Planter
|
|
149
156
|
end
|
150
157
|
end
|
151
158
|
|
152
|
-
if
|
159
|
+
if @config.script
|
153
160
|
Planter.spinner.update(title: 'Running script')
|
154
161
|
|
155
|
-
scripts =
|
162
|
+
scripts = @config.script
|
156
163
|
scripts = [scripts] if scripts.is_a?(String)
|
157
164
|
scripts.each do |script|
|
158
165
|
s = Planter::Script.new(@basedir, Dir.pwd, script)
|
@@ -184,7 +191,7 @@ module Planter
|
|
184
191
|
|
185
192
|
content = IO.read(file)
|
186
193
|
|
187
|
-
new_content = content.
|
194
|
+
new_content = content.apply_all
|
188
195
|
|
189
196
|
new_content.gsub!(%r{^.{.4}/?merge *.{,4}\n}, '') if new_content =~ /^.{.4}merge *\n/
|
190
197
|
|
data/lib/planter/prompt.rb
CHANGED
@@ -21,9 +21,10 @@ module Planter
|
|
21
21
|
@min = question[:min]&.to_f || 1.0
|
22
22
|
@max = question[:max]&.to_f || 10.0
|
23
23
|
@prompt = question[:prompt] || nil
|
24
|
-
@default = question[:default]
|
24
|
+
@default = question[:default]&.to_s&.apply_all || nil
|
25
25
|
@value = question[:value]
|
26
26
|
@choices = question[:choices] || []
|
27
|
+
@date_format = question[:date_format] || nil
|
27
28
|
@gum = false # TTY::Which.exist?('gum')
|
28
29
|
end
|
29
30
|
|
@@ -35,7 +36,7 @@ module Planter
|
|
35
36
|
def ask
|
36
37
|
return nil if @prompt.nil?
|
37
38
|
|
38
|
-
return @value.to_s.
|
39
|
+
return @value.to_s.apply_all.coerce(@type) if @value && @type != :date
|
39
40
|
|
40
41
|
res = case @type
|
41
42
|
when :choice
|
@@ -58,9 +59,9 @@ module Planter
|
|
58
59
|
read_line
|
59
60
|
end
|
60
61
|
Planter.notify("{dw}#{prompt} => {dy}#{res}{x}", :debug, newline: false)
|
61
|
-
res
|
62
|
+
res.to_s.apply_all
|
62
63
|
rescue TTY::Reader::InputInterrupt
|
63
|
-
|
64
|
+
die('Canceled')
|
64
65
|
end
|
65
66
|
|
66
67
|
private
|
@@ -72,8 +73,10 @@ module Planter
|
|
72
73
|
##
|
73
74
|
## @return [Number] numeric response
|
74
75
|
##
|
76
|
+
## @api private
|
77
|
+
##
|
75
78
|
def read_number(integer: false)
|
76
|
-
default = @default ? " {
|
79
|
+
default = @default ? " {xw}[{xbw}#{@default}{xw}]" : ''
|
77
80
|
Planter.notify("{by}#{@prompt} {xc}({bw}#{@min}{xc}-{bw}#{@max}{xc})#{default}")
|
78
81
|
|
79
82
|
res = @gum ? read_number_gum : read_line_tty
|
@@ -91,19 +94,26 @@ module Planter
|
|
91
94
|
##
|
92
95
|
## @return [String] date string
|
93
96
|
##
|
97
|
+
## @api private
|
98
|
+
##
|
94
99
|
def date_default
|
95
100
|
default = @value || @default
|
96
101
|
return nil unless default
|
97
102
|
|
103
|
+
if default =~ /'.*?'/
|
104
|
+
@date_format = default.match(/'(.*?)'/)[1].strip
|
105
|
+
default = default.gsub(/'.*?'/, '').strip
|
106
|
+
end
|
107
|
+
|
98
108
|
case default
|
99
109
|
when /^(no|ti)/
|
100
|
-
Time.now.strftime('%Y-%m-%d %H:%M')
|
110
|
+
Time.now.strftime(@date_format || '%Y-%m-%d %H:%M')
|
101
111
|
when /^(to|da)/
|
102
|
-
Time.now.strftime('%Y-%m-%d')
|
112
|
+
Time.now.strftime(@date_format || '%Y-%m-%d')
|
103
113
|
when /^%/
|
104
|
-
Time.now.strftime(
|
114
|
+
Time.now.strftime(default)
|
105
115
|
else
|
106
|
-
Chronic.parse(default).strftime('%Y-%m-%d')
|
116
|
+
Chronic.parse(default).strftime(@date_format || '%Y-%m-%d')
|
107
117
|
end
|
108
118
|
end
|
109
119
|
|
@@ -114,6 +124,8 @@ module Planter
|
|
114
124
|
##
|
115
125
|
## @return [Date] Parsed Date object
|
116
126
|
##
|
127
|
+
## @api private
|
128
|
+
##
|
117
129
|
def read_date(prompt: nil)
|
118
130
|
prompt ||= @prompt
|
119
131
|
default = date_default
|
@@ -123,7 +135,7 @@ module Planter
|
|
123
135
|
line = @gum ? read_line_gum : read_line_tty
|
124
136
|
return default unless line
|
125
137
|
|
126
|
-
Chronic.parse(line).strftime('%Y-%m-%d')
|
138
|
+
Chronic.parse(line).strftime(@date_format || '%Y-%m-%d')
|
127
139
|
end
|
128
140
|
|
129
141
|
##
|
@@ -135,7 +147,11 @@ module Planter
|
|
135
147
|
##
|
136
148
|
## @return [String] the single-line response
|
137
149
|
##
|
150
|
+
## @api private
|
151
|
+
##
|
138
152
|
def read_line(prompt: nil)
|
153
|
+
return @default if Planter.accept_defaults || ENV['PLANTER_DEBUG']
|
154
|
+
|
139
155
|
prompt ||= @prompt
|
140
156
|
default = @default ? " {bw}[#{@default}]" : ''
|
141
157
|
Planter.notify("{by}#{prompt}#{default}", newline: false)
|
@@ -156,6 +172,8 @@ module Planter
|
|
156
172
|
##
|
157
173
|
## @return [String] the multi-line response
|
158
174
|
##
|
175
|
+
## @api private
|
176
|
+
##
|
159
177
|
def read_lines(prompt: nil)
|
160
178
|
prompt ||= @prompt
|
161
179
|
save = @gum ? 'Ctrl-J for newline, Enter' : 'Ctrl-D'
|
@@ -172,6 +190,8 @@ module Planter
|
|
172
190
|
##
|
173
191
|
## @return [String] String response
|
174
192
|
##
|
193
|
+
## @api private
|
194
|
+
##
|
175
195
|
def read_number_gum
|
176
196
|
trap('SIGINT') { exit! }
|
177
197
|
res = `gum input --placeholder "#{@min}-#{@max}"`.strip
|
@@ -185,6 +205,8 @@ module Planter
|
|
185
205
|
##
|
186
206
|
## @return [String] String response
|
187
207
|
##
|
208
|
+
## @api private
|
209
|
+
##
|
188
210
|
def read_line_tty
|
189
211
|
trap('SIGINT') { exit! }
|
190
212
|
reader = TTY::Reader.new
|
@@ -199,6 +221,8 @@ module Planter
|
|
199
221
|
##
|
200
222
|
## @return [String] String response
|
201
223
|
##
|
224
|
+
## @api private
|
225
|
+
##
|
202
226
|
def read_line_gum
|
203
227
|
trap('SIGINT') { exit! }
|
204
228
|
res = `gum input --placeholder "(blank to use default)"`.strip
|
@@ -212,6 +236,8 @@ module Planter
|
|
212
236
|
##
|
213
237
|
## @return [string] multiline input
|
214
238
|
##
|
239
|
+
## @api private
|
240
|
+
##
|
215
241
|
def read_mutliline_tty
|
216
242
|
trap('SIGINT') { exit! }
|
217
243
|
reader = TTY::Reader.new
|
@@ -224,6 +250,8 @@ module Planter
|
|
224
250
|
##
|
225
251
|
## @return [string] multiline input
|
226
252
|
##
|
253
|
+
## @api private
|
254
|
+
##
|
227
255
|
def read_multiline_gum(prompt)
|
228
256
|
trap('SIGINT') { exit! }
|
229
257
|
width = TTY::Screen.cols > 80 ? 80 : TTY::Screen.cols
|
@@ -234,7 +262,7 @@ module Planter
|
|
234
262
|
##
|
235
263
|
## Choose from an array of multiple choices. Letter surrounded in
|
236
264
|
## parenthesis becomes character for response. Only one letter should be
|
237
|
-
## specified and must be unique.
|
265
|
+
## specified per choice and must be unique.
|
238
266
|
##
|
239
267
|
## @param choices [Array] The choices
|
240
268
|
## @param prompt [String] The prompt
|
@@ -260,6 +288,8 @@ module Planter
|
|
260
288
|
values = choices.to_values.map(&:clean_value)
|
261
289
|
end
|
262
290
|
|
291
|
+
die('Choice(s) without selector, please edit config') unless keys.all?(&:selector?)
|
292
|
+
|
263
293
|
default = case default_response.to_s
|
264
294
|
when /^\d+$/
|
265
295
|
values[default.to_i]
|
@@ -307,6 +337,8 @@ module Planter
|
|
307
337
|
|
308
338
|
res = res.empty? ? default : res
|
309
339
|
|
340
|
+
return choice(choices, prompt, default_response: default_response) if res.nil? || res.empty?
|
341
|
+
|
310
342
|
if res.to_i.positive?
|
311
343
|
values[res.to_i - 1]
|
312
344
|
elsif res =~ /^[a-z]/ && keys&.option_index(res)
|
data/lib/planter/script.rb
CHANGED
@@ -14,12 +14,12 @@ module Planter
|
|
14
14
|
##
|
15
15
|
def initialize(template_dir, output_dir, script)
|
16
16
|
found = find_script(template_dir, script)
|
17
|
-
|
17
|
+
die("Script #{script} not found", :script) unless found
|
18
18
|
|
19
19
|
@script = found
|
20
20
|
make_executable
|
21
21
|
|
22
|
-
|
22
|
+
die("Output directory #{output_dir} not found", :script) unless File.directory?(output_dir)
|
23
23
|
|
24
24
|
@template_directory = template_dir
|
25
25
|
@directory = output_dir
|
@@ -63,7 +63,7 @@ module Planter
|
|
63
63
|
stdout, stderr, status = Open3.capture3(@script, @template_directory, @directory)
|
64
64
|
Planter.notify("STDOUT:\n#{stdout}", :debug) unless stdout.empty?
|
65
65
|
Planter.notify("STDERR:\n#{stderr}", :debug) unless stderr.empty?
|
66
|
-
|
66
|
+
die("Error running #{@script}", :script) unless status.success?
|
67
67
|
|
68
68
|
true
|
69
69
|
end
|