bashly 0.8.0 → 0.8.3
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/completions.rb +60 -35
- data/lib/bashly/concerns/renderable.rb +19 -6
- data/lib/bashly/concerns/validation_helpers.rb +9 -3
- data/lib/bashly/config_validator.rb +19 -2
- data/lib/bashly/extensions/array.rb +2 -2
- data/lib/bashly/extensions/string.rb +2 -2
- data/lib/bashly/script/command.rb +127 -19
- data/lib/bashly/script/flag.rb +4 -2
- data/lib/bashly/templates/strings.yml +1 -0
- data/lib/bashly/version.rb +1 -1
- data/lib/bashly/views/README.md +6 -0
- data/lib/bashly/views/argument/usage.gtx +15 -0
- data/lib/bashly/views/argument/validations.gtx +11 -0
- data/lib/bashly/views/command/catch_all_filter.gtx +10 -0
- data/lib/bashly/views/command/command_fallback.gtx +42 -0
- data/lib/bashly/views/command/command_filter.gtx +29 -0
- data/lib/bashly/views/command/command_functions.gtx +5 -0
- data/lib/bashly/views/command/default_assignments.gtx +13 -0
- data/lib/bashly/views/command/default_initialize_script.gtx +7 -0
- data/lib/bashly/views/command/default_root_script.gtx +4 -0
- data/lib/bashly/views/command/default_script.gtx +5 -0
- data/lib/bashly/views/command/dependencies_filter.gtx +10 -0
- data/lib/bashly/views/command/environment_variables_filter.gtx +18 -0
- data/lib/bashly/views/command/fixed_flags_filter.gtx +20 -0
- data/lib/bashly/views/command/footer.gtx +5 -0
- data/lib/bashly/views/command/function.gtx +6 -0
- data/lib/bashly/views/command/initialize.gtx +12 -0
- data/lib/bashly/views/command/inspect_args.gtx +21 -0
- data/lib/bashly/views/command/long_usage.gtx +13 -0
- data/lib/bashly/views/command/master_script.gtx +17 -0
- data/lib/bashly/views/command/normalize_input.gtx +25 -0
- data/lib/bashly/views/command/parse_requirements.gtx +26 -0
- data/lib/bashly/views/command/parse_requirements_case.gtx +11 -0
- data/lib/bashly/views/command/parse_requirements_case_catch_all.gtx +23 -0
- data/lib/bashly/views/command/parse_requirements_case_repeatable.gtx +24 -0
- data/lib/bashly/views/command/parse_requirements_case_simple.gtx +25 -0
- data/lib/bashly/views/command/parse_requirements_while.gtx +33 -0
- data/lib/bashly/views/command/required_args_filter.gtx +13 -0
- data/lib/bashly/views/command/required_flags_filter.gtx +12 -0
- data/lib/bashly/views/command/root_command.gtx +6 -0
- data/lib/bashly/views/command/run.gtx +28 -0
- data/lib/bashly/views/command/usage.gtx +50 -0
- data/lib/bashly/views/command/usage_args.gtx +20 -0
- data/lib/bashly/views/command/usage_commands.gtx +18 -0
- data/lib/bashly/views/command/usage_environment_variables.gtx +10 -0
- data/lib/bashly/views/command/usage_examples.gtx +10 -0
- data/lib/bashly/views/command/usage_fixed_flags.gtx +13 -0
- data/lib/bashly/views/command/usage_flags.gtx +7 -0
- data/lib/bashly/views/command/user_filter.gtx +13 -0
- data/lib/bashly/views/command/user_lib.gtx +11 -0
- data/lib/bashly/views/command/version_command.gtx +6 -0
- data/lib/bashly/views/command/whitelist_filter.gtx +41 -0
- data/lib/bashly/views/environment_variable/usage.gtx +11 -0
- data/lib/bashly/views/flag/case.gtx +6 -0
- data/lib/bashly/views/flag/case_arg.gtx +25 -0
- data/lib/bashly/views/flag/case_no_arg.gtx +11 -0
- data/lib/bashly/views/flag/conflicts.gtx +22 -0
- data/lib/bashly/views/flag/usage.gtx +15 -0
- data/lib/bashly/views/flag/validations.gtx +11 -0
- data/lib/bashly/views/wrapper/bash3_bouncer.gtx +7 -0
- data/lib/bashly/views/wrapper/header.gtx +5 -0
- data/lib/bashly/views/wrapper/wrapper.gtx +8 -0
- metadata +91 -62
- data/lib/bashly/concerns/command_scopes.rb +0 -68
- data/lib/bashly/views/argument/usage.erb +0 -10
- data/lib/bashly/views/argument/validations.erb +0 -8
- data/lib/bashly/views/command/catch_all_filter.erb +0 -7
- data/lib/bashly/views/command/command_fallback.erb +0 -45
- data/lib/bashly/views/command/command_filter.erb +0 -22
- data/lib/bashly/views/command/command_functions.erb +0 -4
- data/lib/bashly/views/command/default_assignments.erb +0 -7
- data/lib/bashly/views/command/default_initialize_script.erb +0 -6
- data/lib/bashly/views/command/default_root_script.erb +0 -3
- data/lib/bashly/views/command/default_script.erb +0 -4
- data/lib/bashly/views/command/dependencies_filter.erb +0 -9
- data/lib/bashly/views/command/environment_variables_filter.erb +0 -14
- data/lib/bashly/views/command/fixed_flags_filter.erb +0 -24
- data/lib/bashly/views/command/footer.erb +0 -3
- data/lib/bashly/views/command/function.erb +0 -4
- data/lib/bashly/views/command/initialize.erb +0 -8
- data/lib/bashly/views/command/inspect_args.erb +0 -19
- data/lib/bashly/views/command/master_script.erb +0 -14
- data/lib/bashly/views/command/normalize_input.erb +0 -24
- data/lib/bashly/views/command/parse_requirements.erb +0 -22
- data/lib/bashly/views/command/parse_requirements_case.erb +0 -8
- data/lib/bashly/views/command/parse_requirements_case_catch_all.erb +0 -18
- data/lib/bashly/views/command/parse_requirements_case_repeatable.erb +0 -18
- data/lib/bashly/views/command/parse_requirements_case_simple.erb +0 -18
- data/lib/bashly/views/command/parse_requirements_while.erb +0 -26
- data/lib/bashly/views/command/required_args_filter.erb +0 -7
- data/lib/bashly/views/command/required_flags_filter.erb +0 -7
- data/lib/bashly/views/command/root_command.erb +0 -4
- data/lib/bashly/views/command/run.erb +0 -23
- data/lib/bashly/views/command/usage.erb +0 -50
- data/lib/bashly/views/command/usage_args.erb +0 -14
- data/lib/bashly/views/command/usage_commands.erb +0 -18
- data/lib/bashly/views/command/usage_environment_variables.erb +0 -6
- data/lib/bashly/views/command/usage_examples.erb +0 -7
- data/lib/bashly/views/command/usage_fixed_flags.erb +0 -17
- data/lib/bashly/views/command/usage_flags.erb +0 -4
- data/lib/bashly/views/command/user_filter.erb +0 -11
- data/lib/bashly/views/command/user_lib.erb +0 -6
- data/lib/bashly/views/command/version_command.erb +0 -4
- data/lib/bashly/views/command/whitelist_filter.erb +0 -33
- data/lib/bashly/views/environment_variable/usage.erb +0 -7
- data/lib/bashly/views/flag/case.erb +0 -4
- data/lib/bashly/views/flag/case_arg.erb +0 -19
- data/lib/bashly/views/flag/case_no_arg.erb +0 -8
- data/lib/bashly/views/flag/conflicts.erb +0 -18
- data/lib/bashly/views/flag/usage.erb +0 -10
- data/lib/bashly/views/flag/validations.erb +0 -8
- data/lib/bashly/views/wrapper/bash3_bouncer.erb +0 -5
- data/lib/bashly/views/wrapper/header.erb +0 -4
- data/lib/bashly/views/wrapper/wrapper.erb +0 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f3cd1ba341eabd9f1c3acead91ff8c56878db7eb07f3ef6e8f29ceb057cbce04
|
|
4
|
+
data.tar.gz: 9c8fdd62e401cf1d693d76163e61d93779fcbda67406e301f06d9be554ccbe96
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e690eda52685f2b34ae5773b79b48ede2972d8e328dcc193c90d4a60b22a768ccaa1444e52652f0b11513cced19a02eff295ac011ca414d254d4d9e3b8aacf4a
|
|
7
|
+
data.tar.gz: 5b7bf250ea4cdc8d194dee285a6a61748e5d649b455d1b3836a35df1c511b6781d84ac966903a445bd84bcb471604e15c016bbd88f643afe7f030c8df65e6563
|
|
@@ -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']
|
|
@@ -1,51 +1,76 @@
|
|
|
1
1
|
require 'completely'
|
|
2
2
|
|
|
3
3
|
module Bashly
|
|
4
|
-
# This is a `Command` concern responsible for providing bash
|
|
4
|
+
# This is a `Command` and `Flag` concern responsible for providing bash
|
|
5
|
+
# completion data
|
|
5
6
|
module Completions
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
result.merge! command.completion_data(with_version: false)
|
|
11
|
-
end
|
|
7
|
+
module Flag
|
|
8
|
+
def completion_data(command_full_name)
|
|
9
|
+
result = {}
|
|
10
|
+
comps = allowed || completions
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
if comps
|
|
13
|
+
aliases.each do |name|
|
|
14
|
+
result["#{command_full_name}*#{name}"] = comps
|
|
15
|
+
end
|
|
16
|
+
end
|
|
15
17
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
+
result
|
|
19
|
+
end
|
|
18
20
|
end
|
|
19
21
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
module Command
|
|
23
|
+
def completion_data(with_version: true)
|
|
24
|
+
result = {}
|
|
23
25
|
|
|
24
|
-
|
|
26
|
+
all_full_names.each do |name|
|
|
27
|
+
result[name] = completion_words(with_version: with_version)
|
|
28
|
+
flags.each do |flag|
|
|
29
|
+
result.merge! flag.completion_data(name)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
commands.each do |command|
|
|
34
|
+
result.merge! command.completion_data(with_version: false)
|
|
35
|
+
end
|
|
25
36
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
end
|
|
37
|
+
result
|
|
38
|
+
end
|
|
29
39
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
40
|
+
def completion_script
|
|
41
|
+
completion_generator.script
|
|
42
|
+
end
|
|
33
43
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
44
|
+
def completion_function(name = nil)
|
|
45
|
+
completion_generator.wrapper_function(name)
|
|
46
|
+
end
|
|
37
47
|
|
|
38
|
-
|
|
39
|
-
trivial_flags = %w[--help -h]
|
|
40
|
-
trivial_flags += %w[--version -v] if with_version
|
|
41
|
-
all = (
|
|
42
|
-
command_names + trivial_flags +
|
|
43
|
-
completion_flag_names + completion_allowed_args
|
|
44
|
-
)
|
|
48
|
+
private
|
|
45
49
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
50
|
+
def completion_generator
|
|
51
|
+
Completely::Completions.new(completion_data)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def completion_flag_names
|
|
55
|
+
flags.map(&:name) + flags.map(&:short)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def completion_allowed_args
|
|
59
|
+
args.map(&:allowed).flatten
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def completion_words(with_version: false)
|
|
63
|
+
trivial_flags = %w[--help -h]
|
|
64
|
+
trivial_flags += %w[--version -v] if with_version
|
|
65
|
+
all = (
|
|
66
|
+
command_aliases + trivial_flags +
|
|
67
|
+
completion_flag_names + completion_allowed_args
|
|
68
|
+
)
|
|
49
69
|
|
|
70
|
+
all += completions if completions
|
|
71
|
+
all.compact.uniq.sort
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
end
|
|
50
75
|
end
|
|
51
|
-
end
|
|
76
|
+
end
|
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
require '
|
|
1
|
+
require 'gtx'
|
|
2
2
|
|
|
3
3
|
module Bashly
|
|
4
4
|
module Renderable
|
|
5
5
|
def render(view)
|
|
6
|
-
|
|
7
|
-
erb = ERB.new(template, trim_mode: '%-')
|
|
8
|
-
erb.filename = "#{views_subfolder}.#{view}"
|
|
9
|
-
erb.result binding
|
|
6
|
+
GTX.render_file view_path(view), context: binding, filename: "#{views_subfolder}.#{view}"
|
|
10
7
|
end
|
|
11
8
|
|
|
12
9
|
def strings
|
|
@@ -18,10 +15,26 @@ module Bashly
|
|
|
18
15
|
"# #{id}" unless Settings.production?
|
|
19
16
|
end
|
|
20
17
|
|
|
18
|
+
# Reads a file from the userspace (Settings.source_dir) and returns
|
|
19
|
+
# its contents. If the file is not found, returns a string with a hint.
|
|
20
|
+
def load_user_file(file, placeholder: true)
|
|
21
|
+
path = "#{Settings.source_dir}/#{file}"
|
|
22
|
+
|
|
23
|
+
content = if File.exist? path
|
|
24
|
+
File.read(path).remove_front_matter
|
|
25
|
+
elsif placeholder
|
|
26
|
+
%q[echo "error: cannot load file"]
|
|
27
|
+
else
|
|
28
|
+
''
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
Settings.production? ? content : "#{view_marker path}\n#{content}"
|
|
32
|
+
end
|
|
33
|
+
|
|
21
34
|
private
|
|
22
35
|
|
|
23
36
|
def view_path(view)
|
|
24
|
-
"#{self_views_path}/#{view}.
|
|
37
|
+
"#{self_views_path}/#{view}.gtx"
|
|
25
38
|
end
|
|
26
39
|
|
|
27
40
|
def self_views_path
|
|
@@ -52,10 +52,16 @@ module Bashly
|
|
|
52
52
|
end
|
|
53
53
|
end
|
|
54
54
|
|
|
55
|
-
def assert_uniq(key, value,
|
|
55
|
+
def assert_uniq(key, value, array_keys)
|
|
56
56
|
return unless value
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
array_keys = [array_keys] unless array_keys.is_a? Array
|
|
58
|
+
list = []
|
|
59
|
+
array_keys.each do |array_key|
|
|
60
|
+
list += value.map { |c| c[array_key] }.compact.flatten
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
nonuniqs = list.nonuniq
|
|
64
|
+
assert nonuniqs.empty?, "#{key} contains non-unique elements (#{nonuniqs.join ', '}) in #{array_keys.join ' or '}"
|
|
59
65
|
end
|
|
60
66
|
|
|
61
67
|
def assert_string_or_array(key, value)
|
|
@@ -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']
|
|
@@ -61,6 +66,8 @@ module Bashly
|
|
|
61
66
|
assert_hash key, value, Script::Flag.option_keys
|
|
62
67
|
assert value['short'] || value['long'], "#{key} must have at least one of long or short name"
|
|
63
68
|
|
|
69
|
+
refute value['allowed'] && value['completions'], "#{key} cannot have both allowed and completions"
|
|
70
|
+
|
|
64
71
|
assert_optional_string "#{key}.long", value['long']
|
|
65
72
|
assert_optional_string "#{key}.short", value['short']
|
|
66
73
|
assert_optional_string "#{key}.help", value['help']
|
|
@@ -72,6 +79,7 @@ module Bashly
|
|
|
72
79
|
assert_boolean "#{key}.required", value['required']
|
|
73
80
|
assert_array "#{key}.allowed", value['allowed'], of: :string
|
|
74
81
|
assert_array "#{key}.conflicts", value['conflicts'], of: :string
|
|
82
|
+
assert_array "#{key}.completions", value['completions'], of: :string
|
|
75
83
|
|
|
76
84
|
assert value['long'].match(/^--[a-zA-Z0-9_\-]+$/), "#{key}.long must be in the form of '--name'" if value['long']
|
|
77
85
|
assert value['short'].match(/^-[a-zA-Z0-9]$/), "#{key}.short must be in the form of '-n'" if value['short']
|
|
@@ -86,6 +94,10 @@ module Bashly
|
|
|
86
94
|
if value['allowed']
|
|
87
95
|
assert value['arg'], "#{key}.allowed does not make sense without arg"
|
|
88
96
|
end
|
|
97
|
+
|
|
98
|
+
if value['completions']
|
|
99
|
+
assert value['arg'], "#{key}.completions does not make sense without arg"
|
|
100
|
+
end
|
|
89
101
|
end
|
|
90
102
|
|
|
91
103
|
def assert_env_var(key, value)
|
|
@@ -110,6 +122,7 @@ module Bashly
|
|
|
110
122
|
|
|
111
123
|
assert_boolean "#{key}.private", value['private']
|
|
112
124
|
assert_boolean "#{key}.default", value['default']
|
|
125
|
+
assert_expose "#{key}.expose", value['expose']
|
|
113
126
|
assert_version "#{key}.version", value['version']
|
|
114
127
|
assert_catch_all "#{key}.catch_all", value['catch_all']
|
|
115
128
|
assert_string_or_array "#{key}.alias", value['alias']
|
|
@@ -124,8 +137,7 @@ module Bashly
|
|
|
124
137
|
assert_array "#{key}.environment_variables", value['environment_variables'], of: :env_var
|
|
125
138
|
assert_array "#{key}.examples", value['examples'], of: :string
|
|
126
139
|
|
|
127
|
-
assert_uniq "#{key}.commands", value['commands'], 'name'
|
|
128
|
-
assert_uniq "#{key}.commands", value['commands'], 'alias'
|
|
140
|
+
assert_uniq "#{key}.commands", value['commands'], ['name', 'alias']
|
|
129
141
|
assert_uniq "#{key}.flags", value['flags'], 'long'
|
|
130
142
|
assert_uniq "#{key}.flags", value['flags'], 'short'
|
|
131
143
|
assert_uniq "#{key}.args", value['args'], 'name'
|
|
@@ -135,11 +147,16 @@ module Bashly
|
|
|
135
147
|
refute repeatable_arg, "#{key}.catch_all makes no sense with repeatable arg (#{repeatable_arg})"
|
|
136
148
|
end
|
|
137
149
|
|
|
150
|
+
if value['expose']
|
|
151
|
+
assert value['commands'], "#{key}.expose makes no sense without commands"
|
|
152
|
+
end
|
|
153
|
+
|
|
138
154
|
if key == "root"
|
|
139
155
|
refute value['alias'], "#{key}.alias makes no sense"
|
|
140
156
|
refute value['group'], "#{key}.group makes no sense"
|
|
141
157
|
refute value['default'], "#{key}.default makes no sense"
|
|
142
158
|
refute value['private'], "#{key}.private makes no sense"
|
|
159
|
+
refute value['expose'], "#{key}.expose makes no sense"
|
|
143
160
|
else
|
|
144
161
|
refute value['version'], "#{key}.version makes no sense"
|
|
145
162
|
refute value['extensible'], "#{key}.extensible makes no sense"
|
|
@@ -5,7 +5,7 @@ class String
|
|
|
5
5
|
|
|
6
6
|
def indent(offset)
|
|
7
7
|
return self unless offset > 0
|
|
8
|
-
|
|
8
|
+
lines.indent(offset).join
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
def to_underscore
|
|
@@ -24,7 +24,7 @@ class String
|
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
def lint
|
|
27
|
-
gsub(/\s+\n/m, "\n\n").lines.reject { |l| l =~ /^\s*##/ }.join
|
|
27
|
+
gsub(/\s+\n/m, "\n\n").lines.reject { |l| l =~ /^\s*##/ }.join
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
def remove_front_matter
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
module Bashly
|
|
2
2
|
module Script
|
|
3
3
|
class Command < Base
|
|
4
|
-
include Completions
|
|
5
|
-
include CommandScopes
|
|
4
|
+
include Completions::Command
|
|
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,15 +69,81 @@ 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
|
-
|
|
106
|
+
result = Command.new options
|
|
107
|
+
result.parents = parents + [name]
|
|
108
|
+
result.parent_command = self
|
|
109
|
+
result
|
|
66
110
|
end
|
|
67
111
|
end
|
|
68
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
|
|
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
|
|
145
|
+
end
|
|
146
|
+
|
|
69
147
|
# Returns an array of EnvironmentVariables
|
|
70
148
|
def environment_variables
|
|
71
149
|
return [] unless options["environment_variables"]
|
|
@@ -99,27 +177,24 @@ module Bashly
|
|
|
99
177
|
parents.any? ? (parents + [name]).join(' ') : name
|
|
100
178
|
end
|
|
101
179
|
|
|
102
|
-
#
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
path = "#{Settings.source_dir}/#{file}"
|
|
107
|
-
|
|
108
|
-
content = if File.exist? path
|
|
109
|
-
File.read(path).remove_front_matter
|
|
110
|
-
elsif placeholder
|
|
111
|
-
%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 }
|
|
112
184
|
else
|
|
113
|
-
|
|
185
|
+
strings[:commands]
|
|
114
186
|
end
|
|
115
|
-
|
|
116
|
-
Settings.production? ? content : "#{view_marker path}\n#{content}"
|
|
117
187
|
end
|
|
118
188
|
|
|
119
189
|
# Returns an array of all parents. For example, the command
|
|
120
190
|
# "docker container run" will have [docker, container] as its parents
|
|
121
191
|
def parents
|
|
122
|
-
|
|
192
|
+
@parents ||= []
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
# Returns only commands that are not private
|
|
196
|
+
def public_commands
|
|
197
|
+
commands.reject &:private
|
|
123
198
|
end
|
|
124
199
|
|
|
125
200
|
# Returns true if one of the args is repeatable
|
|
@@ -127,6 +202,21 @@ module Bashly
|
|
|
127
202
|
args.select(&:repeatable).any?
|
|
128
203
|
end
|
|
129
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
|
+
|
|
130
220
|
# Returns true if this is the root command (no parents)
|
|
131
221
|
def root_command?
|
|
132
222
|
parents.empty?
|
|
@@ -137,6 +227,15 @@ module Bashly
|
|
|
137
227
|
flags.select { |f| f.short == flag }.any?
|
|
138
228
|
end
|
|
139
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
|
+
|
|
140
239
|
# Returns a constructed string suitable for Usage pattern
|
|
141
240
|
def usage_string
|
|
142
241
|
result = [full_name]
|
|
@@ -156,6 +255,15 @@ module Bashly
|
|
|
156
255
|
@user_lib ||= Dir["#{Settings.full_lib_dir}/**/*.sh"].sort
|
|
157
256
|
end
|
|
158
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
|
|
159
267
|
end
|
|
160
268
|
end
|
|
161
269
|
end
|
data/lib/bashly/script/flag.rb
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
module Bashly
|
|
2
2
|
module Script
|
|
3
3
|
class Flag < Base
|
|
4
|
+
include Completions::Flag
|
|
5
|
+
|
|
4
6
|
class << self
|
|
5
7
|
def option_keys
|
|
6
8
|
@option_keys ||= %i[
|
|
7
|
-
allowed arg conflicts default help long repeatable
|
|
8
|
-
short validate
|
|
9
|
+
allowed arg completions conflicts default help long repeatable
|
|
10
|
+
required short validate
|
|
9
11
|
]
|
|
10
12
|
end
|
|
11
13
|
end
|
|
@@ -26,6 +26,7 @@ version_flag_text: Show version number
|
|
|
26
26
|
flag_requires_an_argument: "%{name} requires an argument: %{usage}"
|
|
27
27
|
invalid_argument: "invalid argument: %s"
|
|
28
28
|
invalid_flag: "invalid option: %s"
|
|
29
|
+
invalid_command: "invalid command: %s"
|
|
29
30
|
conflicting_flags: "conflicting options: %s cannot be used with %s"
|
|
30
31
|
missing_required_argument: "missing required argument: %{arg}\\nusage: %{usage}"
|
|
31
32
|
missing_required_flag: "missing required flag: %{usage}"
|
data/lib/bashly/version.rb
CHANGED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
= view_marker
|
|
2
|
+
|
|
3
|
+
> echo " {{ label }}"
|
|
4
|
+
> printf "{{ help.wrap(76).indent(4).sanitize_for_print }}\n"
|
|
5
|
+
|
|
6
|
+
if allowed
|
|
7
|
+
> printf " {{ strings[:allowed] % { values: allowed.join(', ') } }}\n"
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
if default
|
|
11
|
+
> printf " {{ strings[:default] % { value: default } }}\n"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
> echo
|
|
15
|
+
>
|