bashly 0.6.7 → 0.7.1
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/README.md +4 -2
- data/lib/bashly/cli.rb +1 -0
- data/lib/bashly/commands/add.rb +35 -82
- data/lib/bashly/commands/generate.rb +55 -9
- data/lib/bashly/commands/init.rb +1 -1
- data/lib/bashly/commands/preview.rb +2 -2
- data/lib/bashly/commands/validate.rb +19 -0
- data/lib/bashly/concerns/asset_helper.rb +4 -0
- data/lib/bashly/concerns/completions.rb +5 -1
- data/lib/bashly/config_validator.rb +135 -0
- data/lib/bashly/extensions/file.rb +13 -0
- data/lib/bashly/extensions/string.rb +5 -1
- data/lib/bashly/libraries/base.rb +19 -0
- data/lib/bashly/libraries/completions.rb +14 -0
- data/lib/bashly/libraries/completions_function.rb +38 -0
- data/lib/bashly/libraries/completions_script.rb +29 -0
- data/lib/bashly/libraries/completions_yaml.rb +27 -0
- data/lib/bashly/libraries.yml +39 -0
- data/lib/bashly/library.rb +63 -0
- data/lib/bashly/refinements/compose_refinements.rb +45 -0
- data/lib/bashly/{models → script}/argument.rb +1 -1
- data/lib/bashly/{models → script}/base.rb +4 -2
- data/lib/bashly/{models → script}/command.rb +11 -22
- data/lib/bashly/{models → script}/environment_variable.rb +1 -1
- data/lib/bashly/{models → script}/flag.rb +1 -1
- data/lib/bashly/{models/script.rb → script/wrapper.rb} +21 -3
- data/lib/bashly/templates/lib/colors.sh +41 -31
- data/lib/bashly/templates/lib/config.sh +34 -35
- data/lib/bashly/templates/lib/sample_function.sh +10 -10
- data/lib/bashly/templates/lib/validations/validate_dir_exists.sh +4 -0
- data/lib/bashly/templates/lib/validations/validate_file_exists.sh +4 -0
- data/lib/bashly/templates/lib/validations/validate_integer.sh +4 -0
- data/lib/bashly/templates/lib/validations/validate_not_empty.sh +4 -0
- data/lib/bashly/templates/lib/yaml.sh +12 -15
- data/lib/bashly/templates/strings.yml +1 -0
- data/lib/bashly/version.rb +1 -1
- data/lib/bashly/views/argument/validations.erb +8 -0
- data/lib/bashly/views/command/command_filter.erb +1 -1
- data/lib/bashly/views/command/default_assignments.erb +2 -2
- data/lib/bashly/views/command/default_initialize_script.erb +6 -6
- data/lib/bashly/views/command/environment_variables_filter.erb +1 -1
- data/lib/bashly/views/command/fixed_flags_filter.erb +1 -1
- data/lib/bashly/views/command/initialize.erb +1 -6
- data/lib/bashly/views/command/parse_requirements.erb +1 -1
- data/lib/bashly/views/command/parse_requirements_case.erb +2 -1
- data/lib/bashly/views/command/required_args_filter.erb +1 -5
- data/lib/bashly/views/command/required_flags_filter.erb +1 -4
- data/lib/bashly/views/command/run.erb +4 -4
- data/lib/bashly/views/command/usage_commands.erb +1 -1
- data/lib/bashly/views/flag/case.erb +2 -1
- data/lib/bashly/views/flag/validations.erb +8 -0
- data/lib/bashly/views/wrapper/bash3_bouncer.erb +5 -0
- data/lib/bashly/views/{script → wrapper}/header.erb +1 -0
- data/lib/bashly/views/{script → wrapper}/wrapper.erb +0 -0
- data/lib/bashly.rb +3 -1
- metadata +28 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 53a5744ae1746cdd47de191ea91539ab7336aca894f583384ef0b170c03a746e
|
4
|
+
data.tar.gz: 0e1e9bc417d3947bcce84c3c6f44df87521dfeeae2329cc736a53816cb66cba3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 72154aafdc3c3787b4d23a2935192a92c21b94b830d7fb01c22057ed839d30120d8a31a8962b7b075110551d034b2c971b92010e55c88a17d4e9041ecb309ad7
|
7
|
+
data.tar.gz: a02638101b685d5e9de575fe4537991c558c462dc030355b5e8ab6ffe4f32b8018c510afb516f51c02d4412a20c21a3703b5dc5872a0f377baa343345f045605
|
data/README.md
CHANGED
@@ -40,7 +40,7 @@ a [docker image](https://hub.docker.com/r/dannyben/bashly).
|
|
40
40
|
file for you ([example](https://github.com/DannyBen/bashly/tree/master/examples/minimal#bashlyyml)).
|
41
41
|
2. Bashly then automatically generates a bash script (when you run
|
42
42
|
`bashly generate`) that can parse and validate user input, provide help
|
43
|
-
messages, and run your code for each command
|
43
|
+
messages, and run your code for each command.
|
44
44
|
3. Your code for each command is kept in a separate file, and can be merged
|
45
45
|
again if you change it ([example](https://github.com/DannyBen/bashly/blob/master/examples/minimal/src/root_command.sh)).
|
46
46
|
|
@@ -67,11 +67,13 @@ Bashly is responsible for:
|
|
67
67
|
## Contributing / Support
|
68
68
|
|
69
69
|
If you experience any issue, have a question or a suggestion, or if you wish
|
70
|
-
to contribute, feel free to [open an issue][issues]
|
70
|
+
to contribute, feel free to [open an issue][issues] or
|
71
|
+
[start a discussion][discussions].
|
71
72
|
|
72
73
|
|
73
74
|
|
74
75
|
[issues]: https://github.com/DannyBen/bashly/issues
|
76
|
+
[discussions]: https://github.com/DannyBen/bashly/discussions
|
75
77
|
[docs]: https://bashly.dannyb.co/
|
76
78
|
[examples]: https://github.com/DannyBen/bashly/tree/master/examples#bashly-examples
|
77
79
|
|
data/lib/bashly/cli.rb
CHANGED
data/lib/bashly/commands/add.rb
CHANGED
@@ -8,7 +8,8 @@ module Bashly
|
|
8
8
|
usage "bashly add config [--force]"
|
9
9
|
usage "bashly add colors [--force]"
|
10
10
|
usage "bashly add yaml [--force]"
|
11
|
-
usage "bashly add
|
11
|
+
usage "bashly add validations [--force]"
|
12
|
+
usage "bashly add comp FORMAT [OUTPUT --force]"
|
12
13
|
usage "bashly add (-h|--help)"
|
13
14
|
|
14
15
|
option "-f --force", "Overwrite existing files"
|
@@ -21,6 +22,7 @@ module Bashly
|
|
21
22
|
command "config", "Add standard functions for handling INI files to the lib directory."
|
22
23
|
command "colors", "Add standard functions for printing colorful and formatted text to the lib directory."
|
23
24
|
command "yaml", "Add standard functions for reading YAML files to the lib directory."
|
25
|
+
command "validations", "Add argument validation functions to the lib directory."
|
24
26
|
command "comp", "Generate a bash completions script or function."
|
25
27
|
|
26
28
|
example "bashly add strings --force"
|
@@ -30,119 +32,70 @@ module Bashly
|
|
30
32
|
environment "BASHLY_SOURCE_DIR", "The path containing the bashly configuration and source files [default: src]"
|
31
33
|
|
32
34
|
def strings_command
|
33
|
-
|
35
|
+
add_lib 'strings'
|
34
36
|
end
|
35
37
|
|
36
38
|
def lib_command
|
37
|
-
|
39
|
+
add_lib 'lib'
|
38
40
|
end
|
39
41
|
|
40
42
|
def config_command
|
41
|
-
|
43
|
+
add_lib 'config'
|
42
44
|
end
|
43
45
|
|
44
46
|
def colors_command
|
45
|
-
|
47
|
+
add_lib 'colors'
|
46
48
|
end
|
47
49
|
|
48
50
|
def yaml_command
|
49
|
-
|
51
|
+
add_lib 'yaml'
|
52
|
+
end
|
53
|
+
|
54
|
+
def validations_command
|
55
|
+
add_lib 'validations'
|
50
56
|
end
|
51
57
|
|
52
58
|
def comp_command
|
53
59
|
format = args['FORMAT']
|
54
60
|
output = args['OUTPUT']
|
55
|
-
|
61
|
+
|
56
62
|
case format
|
57
|
-
when "
|
58
|
-
|
59
|
-
when "yaml"
|
60
|
-
|
61
|
-
when "script"
|
62
|
-
save_comp_script output
|
63
|
-
else
|
64
|
-
raise Error, "Unrecognized format: #{format}"
|
63
|
+
when "script" then add_lib 'completions_script', output
|
64
|
+
when "function" then add_lib 'completions', output
|
65
|
+
when "yaml" then add_lib 'completions_yaml', output
|
66
|
+
else raise Error, "Unrecognized format: #{format}"
|
65
67
|
end
|
66
68
|
|
67
69
|
end
|
68
70
|
|
69
71
|
private
|
70
72
|
|
71
|
-
def
|
72
|
-
|
73
|
+
def add_lib(name, *args)
|
74
|
+
library = Bashly::Library.new name, *args
|
75
|
+
files_created = 0
|
76
|
+
library.files.each do |file|
|
77
|
+
created = safe_write file[:path], file[:content]
|
78
|
+
files_created += 1 if created
|
79
|
+
end
|
80
|
+
message = library.post_install_message
|
81
|
+
say "\n#{message}" if message and files_created > 0
|
73
82
|
end
|
74
83
|
|
75
|
-
def
|
84
|
+
def safe_write(path, content)
|
76
85
|
if !Dir.exist? Settings.source_dir
|
77
86
|
raise InitError, "Directory !txtgrn!#{Settings.source_dir}!txtrst! does not exist\nRun !txtpur!bashly init!txtrst! first"
|
78
87
|
end
|
79
88
|
|
80
|
-
if File.exist?
|
81
|
-
say "skipped
|
89
|
+
if File.exist? path and !args['--force']
|
90
|
+
say "!txtblu!skipped!txtrst! #{path} (exists)"
|
91
|
+
false
|
92
|
+
|
82
93
|
else
|
83
|
-
|
84
|
-
say "created
|
85
|
-
|
86
|
-
end
|
87
|
-
|
88
|
-
def deep_copy(source, target)
|
89
|
-
target_dir = File.dirname target
|
90
|
-
FileUtils.mkdir_p target_dir unless Dir.exist? target_dir
|
91
|
-
FileUtils.cp source, target
|
92
|
-
end
|
93
|
-
|
94
|
-
def config
|
95
|
-
@config ||= Config.new "#{Settings.source_dir}/bashly.yml"
|
96
|
-
end
|
97
|
-
|
98
|
-
def command
|
99
|
-
@command ||= Models::Command.new config
|
100
|
-
end
|
101
|
-
|
102
|
-
def completions
|
103
|
-
@completions ||= command.completion_data
|
104
|
-
end
|
105
|
-
|
106
|
-
def completions_script
|
107
|
-
@completions_script ||= command.completion_script
|
108
|
-
end
|
109
|
-
|
110
|
-
def completions_function
|
111
|
-
@completions_function ||= command.completion_function
|
112
|
-
end
|
113
|
-
|
114
|
-
def save_comp_yaml(filename = nil)
|
115
|
-
filename ||= "#{Settings.target_dir}/completions.yml"
|
116
|
-
File.write filename, completions.to_yaml
|
117
|
-
say "created !txtgrn!#{filename}"
|
118
|
-
say ""
|
119
|
-
say "This file can be converted to a completions script using the !txtgrn!completely!txtrst! gem."
|
120
|
-
end
|
121
|
-
|
122
|
-
def save_comp_script(filename = nil)
|
123
|
-
filename ||= "#{Settings.target_dir}/completions.bash"
|
124
|
-
File.write filename, completions_script
|
125
|
-
say "created !txtgrn!#{filename}"
|
126
|
-
say ""
|
127
|
-
say "In order to enable completions, run:"
|
128
|
-
say ""
|
129
|
-
say " !txtpur!$ source #{filename}"
|
130
|
-
end
|
131
|
-
|
132
|
-
def save_comp_function(name = nil)
|
133
|
-
name ||= "send_completions"
|
134
|
-
target_dir = "#{Settings.source_dir}/lib"
|
135
|
-
filename = "#{target_dir}/#{name}.sh"
|
94
|
+
File.deep_write path, content
|
95
|
+
say "!txtgrn!created!txtrst! #{path}"
|
96
|
+
true
|
136
97
|
|
137
|
-
|
138
|
-
File.write filename, completions_function
|
139
|
-
|
140
|
-
say "created !txtgrn!#{filename}"
|
141
|
-
say ""
|
142
|
-
say "In order to use it in your script, create a command or a flag (for example: !txtgrn!#{command.name} completions!txtrst! or !txtgrn!#{command.name} --completions!txtrst!) that calls the !txtgrn!#{name}!txtrst! function."
|
143
|
-
say "Your users can then run something like this to enable completions:"
|
144
|
-
say ""
|
145
|
-
say " !txtpur!$ eval \"$(#{command.name} completions)\""
|
98
|
+
end
|
146
99
|
end
|
147
100
|
|
148
101
|
end
|
@@ -1,30 +1,76 @@
|
|
1
1
|
module Bashly
|
2
2
|
module Commands
|
3
3
|
class Generate < Base
|
4
|
+
using ComposeRefinements
|
5
|
+
|
4
6
|
help "Generate the bash script and required files"
|
5
7
|
|
6
|
-
usage "bashly generate [--force --wrap FUNCTION]"
|
8
|
+
usage "bashly generate [--force --quiet --upgrade --wrap FUNCTION]"
|
7
9
|
usage "bashly generate (-h|--help)"
|
8
10
|
|
9
11
|
option "-f --force", "Overwrite existing files"
|
12
|
+
option "-q --quiet", "Disable on-screen progress report"
|
13
|
+
option "-u --upgrade", "Upgrade all added library functions"
|
10
14
|
option "-w --wrap FUNCTION", "Wrap the entire script in a function so it can also be sourced"
|
11
15
|
|
12
16
|
environment "BASHLY_SOURCE_DIR", "The path containing the bashly configuration and source files [default: src]"
|
13
17
|
environment "BASHLY_TARGET_DIR", "The path to use for creating the bash script [default: .]"
|
18
|
+
environment "BASHLY_STRICT", "When not empty, enable bash strict mode (set -euo pipefail)"
|
14
19
|
|
15
20
|
example "bashly generate --force"
|
16
21
|
example "bashly generate --wrap my_function"
|
17
22
|
|
18
23
|
def run
|
19
24
|
create_user_files
|
25
|
+
upgrade_libs if args['--upgrade']
|
20
26
|
create_master_script
|
21
|
-
|
27
|
+
quiet_say "run !txtpur!#{master_script_path} --help!txtrst! to test your bash script"
|
22
28
|
end
|
23
29
|
|
24
30
|
private
|
25
31
|
|
32
|
+
def quiet_say(message)
|
33
|
+
say message unless args['--quiet']
|
34
|
+
end
|
35
|
+
|
36
|
+
def upgrade_libs
|
37
|
+
generated_files.each do |file|
|
38
|
+
content = File.read file
|
39
|
+
|
40
|
+
if content =~ /\[@bashly-upgrade (.+)\]/
|
41
|
+
args = $1.split ' '
|
42
|
+
library_name = args.shift
|
43
|
+
upgrade file, library_name, *args
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def generated_files
|
49
|
+
Dir["#{Settings.source_dir}/**/*.*"].sort
|
50
|
+
end
|
51
|
+
|
52
|
+
def upgrade(existing_file, library_name, *args)
|
53
|
+
if Library.exist? library_name
|
54
|
+
upgrade! existing_file, library_name, *args
|
55
|
+
else
|
56
|
+
quiet_say "!txtred!warning!txtrst! not upgrading !txtcyn!#{existing_file}!txtrst!, unknown library '#{library_name}'"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def upgrade!(existing_file, library_name, *args)
|
61
|
+
library = Bashly::Library.new library_name, *args
|
62
|
+
file = library.find_file existing_file
|
63
|
+
|
64
|
+
if file
|
65
|
+
File.deep_write file[:path], file[:content]
|
66
|
+
quiet_say "!txtcyn!updated!txtrst! #{file[:path]}"
|
67
|
+
else
|
68
|
+
quiet_say "!txtred!warning!txtrst! not upgrading !txtcyn!#{existing_file}!txtrst!, path mismatch"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
26
72
|
def create_user_files
|
27
|
-
|
73
|
+
quiet_say "creating user files in !txtgrn!#{Settings.source_dir}"
|
28
74
|
|
29
75
|
create_file "#{Settings.source_dir}/initialize.sh", command.render(:default_initialize_script)
|
30
76
|
|
@@ -50,21 +96,21 @@ module Bashly
|
|
50
96
|
|
51
97
|
def create_file(file, content)
|
52
98
|
if File.exist? file and !args['--force']
|
53
|
-
|
99
|
+
quiet_say "!txtblu!skipped!txtrst! #{file} (exists)"
|
54
100
|
else
|
55
101
|
File.write file, content
|
56
|
-
|
102
|
+
quiet_say "!txtgrn!created!txtrst! #{file}"
|
57
103
|
end
|
58
104
|
end
|
59
105
|
|
60
106
|
def create_master_script
|
61
107
|
File.write master_script_path, script.code
|
62
108
|
FileUtils.chmod "+x", master_script_path
|
63
|
-
|
109
|
+
quiet_say "!txtgrn!created!txtrst! #{master_script_path}"
|
64
110
|
end
|
65
111
|
|
66
112
|
def script
|
67
|
-
@script ||=
|
113
|
+
@script ||= Script::Wrapper.new(command, args['--wrap'])
|
68
114
|
end
|
69
115
|
|
70
116
|
def master_script_path
|
@@ -72,11 +118,11 @@ module Bashly
|
|
72
118
|
end
|
73
119
|
|
74
120
|
def config
|
75
|
-
@config ||= Config.new
|
121
|
+
@config ||= Config.new("#{Settings.source_dir}/bashly.yml").compose
|
76
122
|
end
|
77
123
|
|
78
124
|
def command
|
79
|
-
@command ||=
|
125
|
+
@command ||= Script::Command.new config
|
80
126
|
end
|
81
127
|
|
82
128
|
end
|
data/lib/bashly/commands/init.rb
CHANGED
@@ -17,7 +17,7 @@ module Bashly
|
|
17
17
|
end
|
18
18
|
Dir.mkdir target_dir unless Dir.exist? target_dir
|
19
19
|
File.write "#{target_dir}/bashly.yml", yaml_content
|
20
|
-
say "created
|
20
|
+
say "!txtgrn!created!txtrst! #{target_dir}/bashly.yml"
|
21
21
|
say "run !txtpur!bashly generate!txtrst! to create the bash script"
|
22
22
|
end
|
23
23
|
|
@@ -10,8 +10,8 @@ module Bashly
|
|
10
10
|
|
11
11
|
def run
|
12
12
|
config = Config.new "#{Settings.source_dir}/bashly.yml"
|
13
|
-
command =
|
14
|
-
script =
|
13
|
+
command = Script::Command.new(config)
|
14
|
+
script = Script::Wrapper.new command
|
15
15
|
puts script.code
|
16
16
|
end
|
17
17
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Bashly
|
2
|
+
module Commands
|
3
|
+
class Validate < Base
|
4
|
+
help "Scan the configuration file for errors"
|
5
|
+
|
6
|
+
usage "bashly validate"
|
7
|
+
usage "bashly validate (-h|--help)"
|
8
|
+
|
9
|
+
environment "BASHLY_SOURCE_DIR", "The path containing the bashly configuration and source files [default: src]"
|
10
|
+
|
11
|
+
def run
|
12
|
+
config = Config.new "#{Settings.source_dir}/bashly.yml"
|
13
|
+
validator = ConfigValidator.new config
|
14
|
+
validator.validate
|
15
|
+
say "!txtgrn!OK"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -31,12 +31,16 @@ module Bashly
|
|
31
31
|
flags.map(&:name) + flags.map(&:short)
|
32
32
|
end
|
33
33
|
|
34
|
+
def completion_allowed_args
|
35
|
+
flags.map(&:allowed).flatten + args.map(&:allowed).flatten
|
36
|
+
end
|
37
|
+
|
34
38
|
def completion_words(with_version: false)
|
35
39
|
trivial_flags = %w[--help -h]
|
36
40
|
trivial_flags += %w[--version -v] if with_version
|
37
41
|
all = (
|
38
42
|
command_names + trivial_flags +
|
39
|
-
completion_flag_names
|
43
|
+
completion_flag_names + completion_allowed_args
|
40
44
|
)
|
41
45
|
|
42
46
|
all += completions if completions
|
@@ -0,0 +1,135 @@
|
|
1
|
+
module Bashly
|
2
|
+
class ConfigValidator
|
3
|
+
attr_reader :data
|
4
|
+
|
5
|
+
def initialize(data)
|
6
|
+
@data = data
|
7
|
+
end
|
8
|
+
|
9
|
+
def validate
|
10
|
+
assert_command "root", data
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def assert(valid, message)
|
16
|
+
raise ConfigurationError, message unless valid
|
17
|
+
end
|
18
|
+
|
19
|
+
def refute(invalid, message)
|
20
|
+
assert !invalid, message
|
21
|
+
end
|
22
|
+
|
23
|
+
def assert_string(key, value)
|
24
|
+
assert value.is_a?(String), "#{key} must be a string"
|
25
|
+
end
|
26
|
+
|
27
|
+
def assert_optional_string(key, value)
|
28
|
+
assert_string key, value if value
|
29
|
+
end
|
30
|
+
|
31
|
+
def assert_boolean(key, value)
|
32
|
+
assert [true, false, nil].include?(value), "#{key} must be a boolean"
|
33
|
+
end
|
34
|
+
|
35
|
+
def assert_array(key, value, of: nil)
|
36
|
+
return unless value
|
37
|
+
assert value.is_a?(Array), "#{key} must be an array"
|
38
|
+
if of
|
39
|
+
value.each_with_index do |val, i|
|
40
|
+
send "assert_#{of}".to_sym, "#{key}[#{i}]", val
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def assert_hash(key, value)
|
46
|
+
assert value.is_a?(Hash), "#{key} must be a hash"
|
47
|
+
end
|
48
|
+
|
49
|
+
def assert_version(key, value)
|
50
|
+
return unless value
|
51
|
+
assert [String, Integer, Float].include?(value.class),
|
52
|
+
"#{key} must be a string or a number"
|
53
|
+
end
|
54
|
+
|
55
|
+
def assert_catch_all(key, value)
|
56
|
+
return unless value
|
57
|
+
assert [TrueClass, String, Hash].include?(value.class),
|
58
|
+
"#{key} must be a boolean, a string or a hash"
|
59
|
+
|
60
|
+
assert_catch_all_hash key, value if value.is_a? Hash
|
61
|
+
end
|
62
|
+
|
63
|
+
def assert_catch_all_hash(key, value)
|
64
|
+
assert_string "#{key}.label", value['label']
|
65
|
+
assert_optional_string "#{key}.help", value['help']
|
66
|
+
assert_boolean "#{key}.required", value['required']
|
67
|
+
end
|
68
|
+
|
69
|
+
def assert_extensible(key, value)
|
70
|
+
return unless value
|
71
|
+
assert [TrueClass, String].include?(value.class),
|
72
|
+
"#{key} must be a boolean or a string"
|
73
|
+
end
|
74
|
+
|
75
|
+
def assert_arg(key, value)
|
76
|
+
assert_hash key, value
|
77
|
+
assert_string "#{key}.name", value['name']
|
78
|
+
assert_optional_string "#{key}.help", value['help']
|
79
|
+
assert_optional_string "#{key}.default", value['default']
|
80
|
+
assert_optional_string "#{key}.validate", value['validate']
|
81
|
+
assert_boolean "#{key}.required", value['required']
|
82
|
+
|
83
|
+
assert_array "#{key}.allowed", value['allowed'], of: :string
|
84
|
+
end
|
85
|
+
|
86
|
+
def assert_flag(key, value)
|
87
|
+
assert_hash key, value
|
88
|
+
assert value['short'] || value['long'], "#{key} must have at least one of long or short name"
|
89
|
+
|
90
|
+
assert_optional_string "#{key}.long", value['long']
|
91
|
+
assert_optional_string "#{key}.short", value['short']
|
92
|
+
assert_optional_string "#{key}.help", value['help']
|
93
|
+
assert_optional_string "#{key}.arg", value['arg']
|
94
|
+
assert_optional_string "#{key}.default", value['default']
|
95
|
+
assert_optional_string "#{key}.validate", value['validate']
|
96
|
+
|
97
|
+
assert_boolean "#{key}.required", value['required']
|
98
|
+
assert_array "#{key}.allowed", value['allowed'], of: :string
|
99
|
+
end
|
100
|
+
|
101
|
+
def assert_env_var(key, value)
|
102
|
+
assert_hash key, value
|
103
|
+
assert_string "#{key}.name", value['name']
|
104
|
+
assert_optional_string "#{key}.help", value['help']
|
105
|
+
assert_optional_string "#{key}.default", value['default']
|
106
|
+
assert_boolean "#{key}.required", value['required']
|
107
|
+
end
|
108
|
+
|
109
|
+
def assert_command(key, value)
|
110
|
+
assert_hash key, value
|
111
|
+
|
112
|
+
refute value['commands'] && value['args'], "#{key} cannot have both commands and args"
|
113
|
+
refute value['commands'] && value['flags'], "#{key} cannot have both commands and flags"
|
114
|
+
|
115
|
+
assert_string "#{key}.name", value['name']
|
116
|
+
assert_optional_string "#{key}.short", value['short']
|
117
|
+
assert_optional_string "#{key}.help", value['help']
|
118
|
+
assert_optional_string "#{key}.footer", value['footer']
|
119
|
+
assert_optional_string "#{key}.group", value['group']
|
120
|
+
|
121
|
+
assert_boolean "#{key}.default", value['default']
|
122
|
+
assert_version "#{key}.version", value['version']
|
123
|
+
assert_catch_all "#{key}.catch_all", value['catch_all']
|
124
|
+
assert_extensible "#{key}.extensible", value['extensible']
|
125
|
+
|
126
|
+
assert_array "#{key}.args", value['args'], of: :arg
|
127
|
+
assert_array "#{key}.flags", value['flags'] , of: :flag
|
128
|
+
assert_array "#{key}.commands", value['commands'], of: :command
|
129
|
+
assert_array "#{key}.completions", value['completions'], of: :string
|
130
|
+
assert_array "#{key}.dependencies", value['dependencies'], of: :string
|
131
|
+
assert_array "#{key}.environment_variables", value['environment_variables'], of: :env_var
|
132
|
+
assert_array "#{key}.examples", value['examples'], of: :string
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "fileutils"
|
2
|
+
|
3
|
+
class File
|
4
|
+
def self.deep_write(file, content)
|
5
|
+
dir = File.dirname file
|
6
|
+
FileUtils.mkdir_p dir unless Dir.exist? dir
|
7
|
+
File.write file, content
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.append(path, content)
|
11
|
+
File.open(path, "a") { |f| f << content }
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Bashly
|
2
|
+
module Libraries
|
3
|
+
class Base
|
4
|
+
attr_reader :args
|
5
|
+
|
6
|
+
def initialize(*args)
|
7
|
+
@args = args
|
8
|
+
end
|
9
|
+
|
10
|
+
def files
|
11
|
+
raise NotImplementedError, "Please implement #files"
|
12
|
+
end
|
13
|
+
|
14
|
+
def post_install_message
|
15
|
+
nil
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Bashly
|
2
|
+
module Libraries
|
3
|
+
class CompletionsFunction < Completions
|
4
|
+
def files
|
5
|
+
[
|
6
|
+
{
|
7
|
+
path: "#{Settings.source_dir}/lib/#{function_name}.sh",
|
8
|
+
content: completions_function_code(function_name)
|
9
|
+
}
|
10
|
+
]
|
11
|
+
end
|
12
|
+
|
13
|
+
def post_install_message
|
14
|
+
<<~EOF
|
15
|
+
In order to enable completions in your script, create a command or a flag (for example: !txtgrn!#{command.name} completions!txtrst! or !txtgrn!#{command.name} --completions!txtrst!) that calls the !txtgrn!#{function_name}!txtrst! function.
|
16
|
+
|
17
|
+
Your users can then run something like this to enable completions:
|
18
|
+
|
19
|
+
!txtpur!$ eval \"$(#{command.name} completions)\"
|
20
|
+
EOF
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def function_name
|
26
|
+
@function_name ||= args[0] || 'send_completions'
|
27
|
+
end
|
28
|
+
|
29
|
+
def completions_function_code(function_name)
|
30
|
+
[
|
31
|
+
"## [@bashly-upgrade completions #{function_name}]",
|
32
|
+
command.completion_function(function_name)
|
33
|
+
].join "\n"
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Bashly
|
2
|
+
module Libraries
|
3
|
+
class CompletionsScript < Completions
|
4
|
+
def files
|
5
|
+
[
|
6
|
+
{
|
7
|
+
path: target_path,
|
8
|
+
content: command.completion_script
|
9
|
+
}
|
10
|
+
]
|
11
|
+
end
|
12
|
+
|
13
|
+
def post_install_message
|
14
|
+
<<~EOF
|
15
|
+
In order to enable completions, run:
|
16
|
+
|
17
|
+
!txtpur!$ source #{target_path}
|
18
|
+
EOF
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def target_path
|
24
|
+
@target_path ||= args[0] || "#{Settings.target_dir}/completions.bash"
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|