planter-cli 3.0.4 → 3.0.7
Sign up to get free protection for your applications and to get access to all the features.
- 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
|