bashly 0.8.1 → 0.8.2
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/lib/bashly/commands/generate.rb +40 -4
- data/lib/bashly/concerns/renderable.rb +16 -0
- data/lib/bashly/config_validator.rb +11 -0
- data/lib/bashly/script/command.rb +126 -24
- data/lib/bashly/version.rb +1 -1
- data/lib/bashly/views/command/usage_commands.erb +8 -13
- metadata +19 -6
- data/lib/bashly/concerns/command_scopes.rb +0 -83
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bc4a83c90c751c1df692c55db4f7335619c927cb86a30de4fcb7eef5115710a1
|
4
|
+
data.tar.gz: 343ede4e31e7a0833b6335a9690c9ecbe060da1983d829cfbdf197bbfe5dc640
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3b5873adb5c173a4676ae071f6d83b11975053addd8b39e50613375032d441b227d6f27c4ad860719bdf22e37f7ce8882217e5c622c607dcff048fe7dfdaab18
|
7
|
+
data.tar.gz: c01a6a3c20aee19338c3cddfbac0254d7316c5b9aa8f2423bbd6ba65746b439e1ce7e3eec2f2654087c3a6b55388fdeca645dfe786e4adcac97997f1a0f778e4
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'filewatcher'
|
2
|
+
|
1
3
|
module Bashly
|
2
4
|
module Commands
|
3
5
|
class Generate < Base
|
@@ -9,7 +11,8 @@ module Bashly
|
|
9
11
|
option "-f --force", "Overwrite existing files"
|
10
12
|
option "-q --quiet", "Disable on-screen progress report"
|
11
13
|
option "-u --upgrade", "Upgrade all added library functions"
|
12
|
-
option "-w --
|
14
|
+
option "-w --watch", "Watch the source directory for changes and regenerate on change"
|
15
|
+
option "-r --wrap FUNCTION", "Wrap the entire script in a function so it can also be sourced"
|
13
16
|
option "-e --env ENV", "Force the generation environment (see BASHLY_ENV)"
|
14
17
|
|
15
18
|
environment "BASHLY_SOURCE_DIR", "The path containing the bashly configuration and source files [default: src]"
|
@@ -27,17 +30,50 @@ module Bashly
|
|
27
30
|
|
28
31
|
example "bashly generate --force"
|
29
32
|
example "bashly generate --wrap my_function"
|
33
|
+
example "bashly g -uw"
|
34
|
+
|
35
|
+
attr_reader :watching
|
30
36
|
|
31
37
|
def run
|
38
|
+
Settings.env = args['--env'] if args['--env']
|
39
|
+
@watching = args['--watch']
|
40
|
+
|
41
|
+
generate
|
42
|
+
watch if watching
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def watch
|
48
|
+
quiet_say "!txtgrn!watching!txtrst! #{Settings.source_dir}\n"
|
49
|
+
|
50
|
+
Filewatcher.new([Settings.source_dir]).watch do
|
51
|
+
reset
|
52
|
+
generate
|
53
|
+
|
54
|
+
rescue Bashly::ConfigurationError => e
|
55
|
+
say! "!undred!#{e.class}!txtrst!\n#{e.message}"
|
56
|
+
|
57
|
+
ensure
|
58
|
+
quiet_say "!txtgrn!waiting\n"
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def generate
|
32
64
|
with_valid_config do
|
33
|
-
Settings.env = args['--env'] if args['--env']
|
34
65
|
quiet_say "creating !txtgrn!production!txtrst! version" if Settings.production?
|
35
66
|
generate_all_files
|
36
|
-
quiet_say "run !txtpur!#{master_script_path} --help!txtrst! to test your bash script"
|
67
|
+
quiet_say "run !txtpur!#{master_script_path} --help!txtrst! to test your bash script" unless watching
|
37
68
|
end
|
38
69
|
end
|
39
70
|
|
40
|
-
|
71
|
+
def reset
|
72
|
+
@config = nil
|
73
|
+
@config_validator = nil
|
74
|
+
@command = nil
|
75
|
+
@script = nil
|
76
|
+
end
|
41
77
|
|
42
78
|
def quiet_say(message)
|
43
79
|
say message unless args['--quiet']
|
@@ -18,6 +18,22 @@ module Bashly
|
|
18
18
|
"# #{id}" unless Settings.production?
|
19
19
|
end
|
20
20
|
|
21
|
+
# Reads a file from the userspace (Settings.source_dir) and returns
|
22
|
+
# its contents. If the file is not found, returns a string with a hint.
|
23
|
+
def load_user_file(file, placeholder: true)
|
24
|
+
path = "#{Settings.source_dir}/#{file}"
|
25
|
+
|
26
|
+
content = if File.exist? path
|
27
|
+
File.read(path).remove_front_matter
|
28
|
+
elsif placeholder
|
29
|
+
%q[echo "error: cannot load file"]
|
30
|
+
else
|
31
|
+
''
|
32
|
+
end
|
33
|
+
|
34
|
+
Settings.production? ? content : "#{view_marker path}\n#{content}"
|
35
|
+
end
|
36
|
+
|
21
37
|
private
|
22
38
|
|
23
39
|
def view_path(view)
|
@@ -41,6 +41,11 @@ module Bashly
|
|
41
41
|
"#{key} must be a boolean or a string"
|
42
42
|
end
|
43
43
|
|
44
|
+
def assert_expose(key, value)
|
45
|
+
return unless value
|
46
|
+
assert [true, false, nil, 'always'].include?(value), "#{key} must be a boolean, or the string 'always'"
|
47
|
+
end
|
48
|
+
|
44
49
|
def assert_arg(key, value)
|
45
50
|
assert_hash key, value, Script::Argument.option_keys
|
46
51
|
assert_string "#{key}.name", value['name']
|
@@ -117,6 +122,7 @@ module Bashly
|
|
117
122
|
|
118
123
|
assert_boolean "#{key}.private", value['private']
|
119
124
|
assert_boolean "#{key}.default", value['default']
|
125
|
+
assert_expose "#{key}.expose", value['expose']
|
120
126
|
assert_version "#{key}.version", value['version']
|
121
127
|
assert_catch_all "#{key}.catch_all", value['catch_all']
|
122
128
|
assert_string_or_array "#{key}.alias", value['alias']
|
@@ -141,11 +147,16 @@ module Bashly
|
|
141
147
|
refute repeatable_arg, "#{key}.catch_all makes no sense with repeatable arg (#{repeatable_arg})"
|
142
148
|
end
|
143
149
|
|
150
|
+
if value['expose']
|
151
|
+
assert value['commands'], "#{key}.expose makes no sense without commands"
|
152
|
+
end
|
153
|
+
|
144
154
|
if key == "root"
|
145
155
|
refute value['alias'], "#{key}.alias makes no sense"
|
146
156
|
refute value['group'], "#{key}.group makes no sense"
|
147
157
|
refute value['default'], "#{key}.default makes no sense"
|
148
158
|
refute value['private'], "#{key}.private makes no sense"
|
159
|
+
refute value['expose'], "#{key}.expose makes no sense"
|
149
160
|
else
|
150
161
|
refute value['version'], "#{key}.version makes no sense"
|
151
162
|
refute value['extensible'], "#{key}.extensible makes no sense"
|
@@ -2,14 +2,13 @@ module Bashly
|
|
2
2
|
module Script
|
3
3
|
class Command < Base
|
4
4
|
include Completions::Command
|
5
|
-
include CommandScopes
|
6
5
|
|
7
6
|
class << self
|
8
7
|
def option_keys
|
9
8
|
@option_keys ||= %i[
|
10
9
|
alias args catch_all commands completions
|
11
10
|
default dependencies environment_variables examples
|
12
|
-
extensible filename filters flags
|
11
|
+
extensible expose filename filters flags
|
13
12
|
footer group help name
|
14
13
|
private version
|
15
14
|
short
|
@@ -18,6 +17,9 @@ module Bashly
|
|
18
17
|
end
|
19
18
|
end
|
20
19
|
|
20
|
+
attr_accessor :parent_command
|
21
|
+
attr_writer :parents
|
22
|
+
|
21
23
|
# Returns the name to be used as an action.
|
22
24
|
# - If it is the root command, the action is "root"
|
23
25
|
# - Else, it is all the parents, except the first one (root) joined
|
@@ -32,6 +34,16 @@ module Bashly
|
|
32
34
|
[name] + alt
|
33
35
|
end
|
34
36
|
|
37
|
+
# Returns an array of all full names (including aliases and aliases of
|
38
|
+
# parents)
|
39
|
+
def all_full_names
|
40
|
+
if parent_command
|
41
|
+
parent_command.all_full_names.product(aliases).map { |a| a.join ' ' }
|
42
|
+
else
|
43
|
+
aliases
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
35
47
|
# Returns an array of alternative aliases if any
|
36
48
|
def alt
|
37
49
|
# DEPRECATION 0.8.0
|
@@ -57,14 +69,79 @@ module Bashly
|
|
57
69
|
@catch_all ||= CatchAll.from_config options['catch_all']
|
58
70
|
end
|
59
71
|
|
72
|
+
# Returns a full list of the Command names and aliases combined
|
73
|
+
def command_aliases
|
74
|
+
commands.map(&:aliases).flatten
|
75
|
+
end
|
76
|
+
|
77
|
+
# Returns a data structure for displaying subcommands help
|
78
|
+
def command_help_data
|
79
|
+
result = {}
|
80
|
+
|
81
|
+
public_commands.each do |command|
|
82
|
+
result[command.group_string] ||= {}
|
83
|
+
result[command.group_string][command.name] = { summary: command.summary_string }
|
84
|
+
next unless command.expose
|
85
|
+
|
86
|
+
command.public_commands.each do |subcommand|
|
87
|
+
result[command.group_string]["#{command.name} #{subcommand.name}"] = {
|
88
|
+
summary: subcommand.summary_string,
|
89
|
+
help_only: command.expose != 'always'
|
90
|
+
}
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
result
|
95
|
+
end
|
96
|
+
|
97
|
+
# Returns only the names of the Commands
|
98
|
+
def command_names
|
99
|
+
commands.map &:name
|
100
|
+
end
|
101
|
+
|
60
102
|
# Returns an array of the Commands
|
61
103
|
def commands
|
62
104
|
return [] unless options["commands"]
|
63
105
|
options["commands"].map do |options|
|
64
|
-
|
65
|
-
|
66
|
-
|
106
|
+
result = Command.new options
|
107
|
+
result.parents = parents + [name]
|
108
|
+
result.parent_command = self
|
109
|
+
result
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# Returns a flat array containing all the commands in this tree.
|
114
|
+
# This includes self + children + grandchildres + ...
|
115
|
+
def deep_commands
|
116
|
+
result = []
|
117
|
+
commands.each do |command|
|
118
|
+
result << command
|
119
|
+
if command.commands.any?
|
120
|
+
result += command.deep_commands
|
121
|
+
end
|
67
122
|
end
|
123
|
+
result
|
124
|
+
end
|
125
|
+
|
126
|
+
# If any of this command's subcommands has the default option set to
|
127
|
+
# true, this default command will be returned, nil otherwise.
|
128
|
+
def default_command
|
129
|
+
commands.find { |c| c.default }
|
130
|
+
end
|
131
|
+
|
132
|
+
# Returns an array of all the default Args
|
133
|
+
def default_args
|
134
|
+
args.select &:default
|
135
|
+
end
|
136
|
+
|
137
|
+
# Returns an array of all the default Environment Variables
|
138
|
+
def default_environment_variables
|
139
|
+
environment_variables.select &:default
|
140
|
+
end
|
141
|
+
|
142
|
+
# Returns an array of all the default Flags
|
143
|
+
def default_flags
|
144
|
+
flags.select &:default
|
68
145
|
end
|
69
146
|
|
70
147
|
# Returns an array of EnvironmentVariables
|
@@ -100,32 +177,24 @@ module Bashly
|
|
100
177
|
parents.any? ? (parents + [name]).join(' ') : name
|
101
178
|
end
|
102
179
|
|
103
|
-
#
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
path = "#{Settings.source_dir}/#{file}"
|
108
|
-
|
109
|
-
content = if File.exist? path
|
110
|
-
File.read(path).remove_front_matter
|
111
|
-
elsif placeholder
|
112
|
-
%q[echo "error: cannot load file"]
|
180
|
+
# Returns the string for the group caption
|
181
|
+
def group_string
|
182
|
+
if group
|
183
|
+
strings[:group] % { group: group }
|
113
184
|
else
|
114
|
-
|
185
|
+
strings[:commands]
|
115
186
|
end
|
116
|
-
|
117
|
-
Settings.production? ? content : "#{view_marker path}\n#{content}"
|
118
|
-
end
|
119
|
-
|
120
|
-
# Returns the Command instance of the direct parent
|
121
|
-
def parent_command
|
122
|
-
options['parent_command']
|
123
187
|
end
|
124
188
|
|
125
189
|
# Returns an array of all parents. For example, the command
|
126
190
|
# "docker container run" will have [docker, container] as its parents
|
127
191
|
def parents
|
128
|
-
|
192
|
+
@parents ||= []
|
193
|
+
end
|
194
|
+
|
195
|
+
# Returns only commands that are not private
|
196
|
+
def public_commands
|
197
|
+
commands.reject &:private
|
129
198
|
end
|
130
199
|
|
131
200
|
# Returns true if one of the args is repeatable
|
@@ -133,6 +202,21 @@ module Bashly
|
|
133
202
|
args.select(&:repeatable).any?
|
134
203
|
end
|
135
204
|
|
205
|
+
# Returns an array of all the required Arguments
|
206
|
+
def required_args
|
207
|
+
args.select &:required
|
208
|
+
end
|
209
|
+
|
210
|
+
# Returns an array of all the required EnvironmentVariables
|
211
|
+
def required_environment_variables
|
212
|
+
environment_variables.select &:required
|
213
|
+
end
|
214
|
+
|
215
|
+
# Returns an array of all the required Flags
|
216
|
+
def required_flags
|
217
|
+
flags.select &:required
|
218
|
+
end
|
219
|
+
|
136
220
|
# Returns true if this is the root command (no parents)
|
137
221
|
def root_command?
|
138
222
|
parents.empty?
|
@@ -143,6 +227,15 @@ module Bashly
|
|
143
227
|
flags.select { |f| f.short == flag }.any?
|
144
228
|
end
|
145
229
|
|
230
|
+
# Returns the summary string
|
231
|
+
def summary_string
|
232
|
+
if default
|
233
|
+
strings[:default_command_summary] % { summary: summary }
|
234
|
+
else
|
235
|
+
summary
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
146
239
|
# Returns a constructed string suitable for Usage pattern
|
147
240
|
def usage_string
|
148
241
|
result = [full_name]
|
@@ -162,6 +255,15 @@ module Bashly
|
|
162
255
|
@user_lib ||= Dir["#{Settings.full_lib_dir}/**/*.sh"].sort
|
163
256
|
end
|
164
257
|
|
258
|
+
# Returns an array of all the args with a whitelist
|
259
|
+
def whitelisted_args
|
260
|
+
args.select &:allowed
|
261
|
+
end
|
262
|
+
|
263
|
+
# Returns an array of all the flags with a whitelist arg
|
264
|
+
def whitelisted_flags
|
265
|
+
flags.select &:allowed
|
266
|
+
end
|
165
267
|
end
|
166
268
|
end
|
167
269
|
end
|
data/lib/bashly/version.rb
CHANGED
@@ -1,18 +1,13 @@
|
|
1
1
|
<%= view_marker %>
|
2
|
-
%
|
3
|
-
|
4
|
-
|
5
|
-
%
|
6
|
-
%
|
7
|
-
|
8
|
-
% summary = strings[:default_command_summary] % { summary: summary } if command.default
|
9
|
-
% if command.group
|
10
|
-
% if command.name == commands.first.name
|
11
|
-
printf "<%= strings[:group] % { group: command.group } %>\n"
|
2
|
+
% maxlen = command_help_data.values.map(&:keys).flatten.map(&:size).max
|
3
|
+
% command_help_data.each do |group, commands|
|
4
|
+
printf "<%= group %>\n"
|
5
|
+
% commands.each do |command, info|
|
6
|
+
% if info[:help_only]
|
7
|
+
[[ -n $long_usage ]] && echo " <%= command.ljust maxlen %> <%= info[:summary] %>"
|
12
8
|
% else
|
13
|
-
|
14
|
-
% end
|
9
|
+
echo " <%= command.ljust maxlen %> <%= info[:summary] %>"
|
15
10
|
% end
|
16
|
-
echo " <%= command.name.ljust maxlen %> <%= summary %>"
|
17
11
|
% end
|
18
12
|
echo
|
13
|
+
% end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bashly
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Danny Ben Shitrit
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-06-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: colsole
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 0.4.
|
33
|
+
version: 0.4.2
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 0.4.
|
40
|
+
version: 0.4.2
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: mister_bin
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0.2'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: filewatcher
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.1'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.1'
|
69
83
|
description: Generate bash command line tools using YAML configuration
|
70
84
|
email: db@dannyben.com
|
71
85
|
executables:
|
@@ -84,7 +98,6 @@ files:
|
|
84
98
|
- lib/bashly/commands/preview.rb
|
85
99
|
- lib/bashly/commands/validate.rb
|
86
100
|
- lib/bashly/concerns/asset_helper.rb
|
87
|
-
- lib/bashly/concerns/command_scopes.rb
|
88
101
|
- lib/bashly/concerns/completions.rb
|
89
102
|
- lib/bashly/concerns/renderable.rb
|
90
103
|
- lib/bashly/concerns/validation_helpers.rb
|
@@ -200,7 +213,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
200
213
|
- !ruby/object:Gem::Version
|
201
214
|
version: '0'
|
202
215
|
requirements: []
|
203
|
-
rubygems_version: 3.3.
|
216
|
+
rubygems_version: 3.3.14
|
204
217
|
signing_key:
|
205
218
|
specification_version: 4
|
206
219
|
summary: Bash Command Line Tool Generator
|
@@ -1,83 +0,0 @@
|
|
1
|
-
module Bashly
|
2
|
-
# This is a `Command` concern responsible for providing additional scopes.
|
3
|
-
module CommandScopes
|
4
|
-
# Returns an array of all full names (including aliases and aliases of
|
5
|
-
# parents)
|
6
|
-
def all_full_names
|
7
|
-
if parent_command
|
8
|
-
parent_command.all_full_names.product(aliases).map { |a| a.join ' ' }
|
9
|
-
else
|
10
|
-
aliases
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
# Returns a full list of the Command names and aliases combined
|
15
|
-
def command_aliases
|
16
|
-
commands.map(&:aliases).flatten
|
17
|
-
end
|
18
|
-
|
19
|
-
# Returns only the names of the Commands
|
20
|
-
def command_names
|
21
|
-
commands.map &:name
|
22
|
-
end
|
23
|
-
|
24
|
-
# Returns a flat array containing all the commands in this tree.
|
25
|
-
# This includes self + children + grandchildres + ...
|
26
|
-
def deep_commands
|
27
|
-
result = []
|
28
|
-
commands.each do |command|
|
29
|
-
result << command
|
30
|
-
if command.commands.any?
|
31
|
-
result += command.deep_commands
|
32
|
-
end
|
33
|
-
end
|
34
|
-
result
|
35
|
-
end
|
36
|
-
|
37
|
-
# If any of this command's subcommands has the default option set to
|
38
|
-
# true, this default command will be returned, nil otherwise.
|
39
|
-
def default_command
|
40
|
-
commands.find { |c| c.default }
|
41
|
-
end
|
42
|
-
|
43
|
-
# Returns an array of all the default Args
|
44
|
-
def default_args
|
45
|
-
args.select &:default
|
46
|
-
end
|
47
|
-
|
48
|
-
# Returns an array of all the default Environment Variables
|
49
|
-
def default_environment_variables
|
50
|
-
environment_variables.select &:default
|
51
|
-
end
|
52
|
-
|
53
|
-
# Returns an array of all the default Flags
|
54
|
-
def default_flags
|
55
|
-
flags.select &:default
|
56
|
-
end
|
57
|
-
|
58
|
-
# Returns an array of all the required Arguments
|
59
|
-
def required_args
|
60
|
-
args.select &:required
|
61
|
-
end
|
62
|
-
|
63
|
-
# Returns an array of all the required EnvironmentVariables
|
64
|
-
def required_environment_variables
|
65
|
-
environment_variables.select &:required
|
66
|
-
end
|
67
|
-
|
68
|
-
# Returns an array of all the required Flags
|
69
|
-
def required_flags
|
70
|
-
flags.select &:required
|
71
|
-
end
|
72
|
-
|
73
|
-
# Returns an array of all the args with a whitelist
|
74
|
-
def whitelisted_args
|
75
|
-
args.select &:allowed
|
76
|
-
end
|
77
|
-
|
78
|
-
# Returns an array of all the flags with a whitelist arg
|
79
|
-
def whitelisted_flags
|
80
|
-
flags.select &:allowed
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|