bashly 0.6.6 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +4 -2
- data/lib/bashly/commands/add.rb +42 -78
- data/lib/bashly/commands/generate.rb +53 -8
- data/lib/bashly/commands/init.rb +1 -1
- data/lib/bashly/commands/preview.rb +2 -2
- data/lib/bashly/concerns/asset_helper.rb +4 -0
- data/lib/bashly/concerns/completions.rb +5 -1
- data/lib/bashly/extensions/file.rb +13 -0
- data/lib/bashly/extensions/string.rb +1 -1
- data/lib/bashly/library/base.rb +57 -0
- data/lib/bashly/library/colors.rb +9 -0
- data/lib/bashly/library/completions.rb +28 -0
- data/lib/bashly/library/completions_function.rb +26 -0
- data/lib/bashly/library/completions_script.rb +17 -0
- data/lib/bashly/library/completions_yaml.rb +15 -0
- data/lib/bashly/library/config.rb +9 -0
- data/lib/bashly/library/sample.rb +9 -0
- data/lib/bashly/library/strings.rb +12 -0
- data/lib/bashly/library/validations.rb +9 -0
- data/lib/bashly/library/yaml.rb +9 -0
- data/lib/bashly/{models → script}/argument.rb +1 -1
- data/lib/bashly/{models → script}/base.rb +2 -1
- data/lib/bashly/{models → script}/command.rb +1 -1
- 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 +50 -48
- 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/initialize.erb +0 -5
- 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/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 +2 -1
- metadata +29 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 13bbac52a39c2f6afb768d043911861a31f8e6abc8ff1472340a13c2834d5944
|
4
|
+
data.tar.gz: 54c4fea2c664dcd0c6aace3360004d715d87b5d4ed98ffd7d3ccdc6c0a120406
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f1c273771d9048c074fb9551ba4521e9cb38c98a819f53647186822155898f767b7dd95093642e01464788378833d4dd9e408efecf304a9feb1ba09ebf2edef3
|
7
|
+
data.tar.gz: efbdad6c22cfe1b7fbb46533db42f4c14b828259efeb5ede1099e20980ad505773af36897e27f8c6c7b25538a523427e63c1a5dac7ff958d753ae3810caf5eb9
|
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/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,81 @@ 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 Library::Strings.new
|
34
36
|
end
|
35
37
|
|
36
38
|
def lib_command
|
37
|
-
|
39
|
+
add_lib Library::Sample.new
|
38
40
|
end
|
39
41
|
|
40
42
|
def config_command
|
41
|
-
|
43
|
+
add_lib Library::Config.new
|
42
44
|
end
|
43
45
|
|
44
46
|
def colors_command
|
45
|
-
|
47
|
+
add_lib Library::Colors.new
|
46
48
|
end
|
47
49
|
|
48
50
|
def yaml_command
|
49
|
-
|
51
|
+
add_lib Library::YAML.new
|
52
|
+
end
|
53
|
+
|
54
|
+
def validations_command
|
55
|
+
add_lib Library::Validations.new
|
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
|
63
|
+
when "script"
|
64
|
+
path = output || "#{Settings.target_dir}/completions.bash"
|
65
|
+
add_lib Library::CompletionsScript.new(path)
|
66
|
+
|
57
67
|
when "function"
|
58
|
-
|
68
|
+
function = output || "send_completions"
|
69
|
+
path = "#{Settings.source_dir}/lib/#{function}.sh"
|
70
|
+
add_lib Library::CompletionsFunction.new(path, function: function)
|
71
|
+
|
59
72
|
when "yaml"
|
60
|
-
|
61
|
-
|
62
|
-
|
73
|
+
path = output || "#{Settings.target_dir}/completions.yml"
|
74
|
+
add_lib Library::CompletionsYAML.new(path)
|
75
|
+
|
63
76
|
else
|
64
77
|
raise Error, "Unrecognized format: #{format}"
|
78
|
+
|
65
79
|
end
|
66
80
|
|
67
81
|
end
|
68
82
|
|
69
83
|
private
|
70
84
|
|
71
|
-
def
|
72
|
-
|
85
|
+
def add_lib(handler)
|
86
|
+
files_created = 0
|
87
|
+
handler.files.each do |file|
|
88
|
+
created = safe_write file[:path], file[:content]
|
89
|
+
files_created += 1 if created
|
90
|
+
end
|
91
|
+
message = handler.post_install_message
|
92
|
+
say "\n#{message}" if message and files_created > 0
|
73
93
|
end
|
74
94
|
|
75
|
-
def
|
95
|
+
def safe_write(path, content)
|
76
96
|
if !Dir.exist? Settings.source_dir
|
77
97
|
raise InitError, "Directory !txtgrn!#{Settings.source_dir}!txtrst! does not exist\nRun !txtpur!bashly init!txtrst! first"
|
78
98
|
end
|
79
99
|
|
80
|
-
if File.exist?
|
81
|
-
say "skipped
|
100
|
+
if File.exist? path and !args['--force']
|
101
|
+
say "!txtblu!skipped!txtrst! #{path} (exists)"
|
102
|
+
false
|
103
|
+
|
82
104
|
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"
|
105
|
+
File.deep_write path, content
|
106
|
+
say "!txtgrn!created!txtrst! #{path}"
|
107
|
+
true
|
136
108
|
|
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)\""
|
109
|
+
end
|
146
110
|
end
|
147
111
|
|
148
112
|
end
|
@@ -3,10 +3,12 @@ module Bashly
|
|
3
3
|
class Generate < Base
|
4
4
|
help "Generate the bash script and required files"
|
5
5
|
|
6
|
-
usage "bashly generate [--force --wrap FUNCTION]"
|
6
|
+
usage "bashly generate [--force --quiet --upgrade --wrap FUNCTION]"
|
7
7
|
usage "bashly generate (-h|--help)"
|
8
8
|
|
9
9
|
option "-f --force", "Overwrite existing files"
|
10
|
+
option "-q --quiet", "Disable on-screen progress report"
|
11
|
+
option "-u --upgrade", "Upgrade all added library functions"
|
10
12
|
option "-w --wrap FUNCTION", "Wrap the entire script in a function so it can also be sourced"
|
11
13
|
|
12
14
|
environment "BASHLY_SOURCE_DIR", "The path containing the bashly configuration and source files [default: src]"
|
@@ -17,14 +19,57 @@ module Bashly
|
|
17
19
|
|
18
20
|
def run
|
19
21
|
create_user_files
|
22
|
+
upgrade_libs if args['--upgrade']
|
20
23
|
create_master_script
|
21
|
-
|
24
|
+
quiet_say "run !txtpur!#{master_script_path} --help!txtrst! to test your bash script"
|
22
25
|
end
|
23
26
|
|
24
27
|
private
|
25
28
|
|
29
|
+
def quiet_say(message)
|
30
|
+
say message unless args['--quiet']
|
31
|
+
end
|
32
|
+
|
33
|
+
def upgrade_libs
|
34
|
+
generated_files.each do |file|
|
35
|
+
content = File.read file
|
36
|
+
|
37
|
+
if content =~ /\[@bashly-upgrade (.+)\]/
|
38
|
+
lib = $1
|
39
|
+
|
40
|
+
case lib
|
41
|
+
when "colors"
|
42
|
+
upgrade file, Library::Colors.new
|
43
|
+
when "config"
|
44
|
+
upgrade file, Library::Config.new
|
45
|
+
when "yaml"
|
46
|
+
upgrade file, Library::YAML.new
|
47
|
+
when "validations"
|
48
|
+
upgrade file, Library::Validations.new
|
49
|
+
when /completions (.+)/
|
50
|
+
upgrade file, Library::CompletionsFunction.new(file, function: $1)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def generated_files
|
57
|
+
Dir["#{Settings.source_dir}/**/*.*"].sort
|
58
|
+
end
|
59
|
+
|
60
|
+
def upgrade(existing_file, handler)
|
61
|
+
file = handler.files.select { |f| f[:path] == existing_file }.first
|
62
|
+
|
63
|
+
if file
|
64
|
+
File.deep_write file[:path], file[:content]
|
65
|
+
quiet_say "!txtcyn!updated!txtrst! #{file[:path]}"
|
66
|
+
else
|
67
|
+
quiet_say "!txtred!warning!txtrst! not upgrading !txtcyn!#{existing_file}!txtrst!, path mismatch"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
26
71
|
def create_user_files
|
27
|
-
|
72
|
+
quiet_say "creating user files in !txtgrn!#{Settings.source_dir}"
|
28
73
|
|
29
74
|
create_file "#{Settings.source_dir}/initialize.sh", command.render(:default_initialize_script)
|
30
75
|
|
@@ -50,21 +95,21 @@ module Bashly
|
|
50
95
|
|
51
96
|
def create_file(file, content)
|
52
97
|
if File.exist? file and !args['--force']
|
53
|
-
|
98
|
+
quiet_say "!txtblu!skipped!txtrst! #{file} (exists)"
|
54
99
|
else
|
55
100
|
File.write file, content
|
56
|
-
|
101
|
+
quiet_say "!txtgrn!created!txtrst! #{file}"
|
57
102
|
end
|
58
103
|
end
|
59
104
|
|
60
105
|
def create_master_script
|
61
106
|
File.write master_script_path, script.code
|
62
107
|
FileUtils.chmod "+x", master_script_path
|
63
|
-
|
108
|
+
quiet_say "!txtgrn!created!txtrst! #{master_script_path}"
|
64
109
|
end
|
65
110
|
|
66
111
|
def script
|
67
|
-
@script ||=
|
112
|
+
@script ||= Script::Wrapper.new(command, args['--wrap'])
|
68
113
|
end
|
69
114
|
|
70
115
|
def master_script_path
|
@@ -76,7 +121,7 @@ module Bashly
|
|
76
121
|
end
|
77
122
|
|
78
123
|
def command
|
79
|
-
@command ||=
|
124
|
+
@command ||= Script::Command.new config
|
80
125
|
end
|
81
126
|
|
82
127
|
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
|
@@ -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,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,57 @@
|
|
1
|
+
module Bashly
|
2
|
+
module Library
|
3
|
+
class Base
|
4
|
+
include AssetHelper
|
5
|
+
|
6
|
+
attr_reader :target_path, :options
|
7
|
+
|
8
|
+
def initialize(target_path = nil, options = nil)
|
9
|
+
@target_path = target_path || Settings.source_dir
|
10
|
+
@options = options || {}
|
11
|
+
end
|
12
|
+
|
13
|
+
def files
|
14
|
+
case content
|
15
|
+
when String then content_from_string content
|
16
|
+
when Hash then [content]
|
17
|
+
else content
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def post_install_message
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
|
25
|
+
def content
|
26
|
+
raise NotImplementedError, "Please implement either #content"
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def content_from_string(string)
|
32
|
+
if File.directory? asset("templates/lib/#{string}")
|
33
|
+
content_for_dir string
|
34
|
+
else
|
35
|
+
[content_for_file(string)]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def content_for_file(file)
|
40
|
+
{
|
41
|
+
path: "#{target_path}/lib/#{file}",
|
42
|
+
content: asset_content("templates/lib/#{file}")
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
46
|
+
def content_for_dir(dir)
|
47
|
+
Dir[asset("templates/lib/#{dir}/*.sh")].sort.map do |file|
|
48
|
+
{
|
49
|
+
path: "#{target_path}/lib/#{dir}/#{File.basename file}",
|
50
|
+
content: File.read(file)
|
51
|
+
}
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Bashly
|
2
|
+
module Library
|
3
|
+
class Completions < Base
|
4
|
+
def content
|
5
|
+
{ path: target_path, content: file_content }
|
6
|
+
end
|
7
|
+
|
8
|
+
def file_content
|
9
|
+
raise NotImplementedError, "Please implement #file_content"
|
10
|
+
end
|
11
|
+
|
12
|
+
protected
|
13
|
+
|
14
|
+
def completions
|
15
|
+
@completions ||= command.completion_data
|
16
|
+
end
|
17
|
+
|
18
|
+
def config
|
19
|
+
@config ||= Bashly::Config.new "#{Settings.source_dir}/bashly.yml"
|
20
|
+
end
|
21
|
+
|
22
|
+
def command
|
23
|
+
@command ||= Script::Command.new config
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Bashly
|
2
|
+
module Library
|
3
|
+
class CompletionsFunction < Completions
|
4
|
+
def file_content
|
5
|
+
[
|
6
|
+
"# [@bashly-upgrade completions #{function_name}]",
|
7
|
+
command.completion_function(function_name)
|
8
|
+
].join "\n"
|
9
|
+
end
|
10
|
+
|
11
|
+
def post_install_message
|
12
|
+
<<~EOF
|
13
|
+
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.
|
14
|
+
|
15
|
+
Your users can then run something like this to enable completions:
|
16
|
+
|
17
|
+
!txtpur!$ eval \"$(#{command.name} completions)\"
|
18
|
+
EOF
|
19
|
+
end
|
20
|
+
|
21
|
+
def function_name
|
22
|
+
options[:function]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Bashly
|
2
|
+
module Library
|
3
|
+
class CompletionsScript < Completions
|
4
|
+
def file_content
|
5
|
+
command.completion_script
|
6
|
+
end
|
7
|
+
|
8
|
+
def post_install_message
|
9
|
+
<<~EOF
|
10
|
+
In order to enable completions, run:
|
11
|
+
|
12
|
+
!txtpur!$ source #{target_path}
|
13
|
+
EOF
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Bashly
|
2
|
+
module Library
|
3
|
+
class CompletionsYAML < Completions
|
4
|
+
def file_content
|
5
|
+
completions.to_yaml
|
6
|
+
end
|
7
|
+
|
8
|
+
def post_install_message
|
9
|
+
<<~EOF
|
10
|
+
This file can be converted to a completions script using the !txtgrn!completely!txtrst! gem.
|
11
|
+
EOF
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Bashly
|
2
|
-
module
|
3
|
-
class
|
2
|
+
module Script
|
3
|
+
class Wrapper
|
4
4
|
include Renderable
|
5
5
|
|
6
6
|
attr_reader :command, :function_name
|
@@ -22,12 +22,30 @@ module Bashly
|
|
22
22
|
private
|
23
23
|
|
24
24
|
def header
|
25
|
-
@header ||=
|
25
|
+
@header ||= header!
|
26
|
+
end
|
27
|
+
|
28
|
+
def header!
|
29
|
+
if File.exist? custom_header_path
|
30
|
+
File.read custom_header_path
|
31
|
+
else
|
32
|
+
default_header
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def default_header
|
37
|
+
result = render('header')
|
38
|
+
result += render('bash3_bouncer') unless function_name
|
39
|
+
result
|
26
40
|
end
|
27
41
|
|
28
42
|
def body
|
29
43
|
@body ||= command.render('master_script')
|
30
44
|
end
|
45
|
+
|
46
|
+
def custom_header_path
|
47
|
+
@custom_header_path ||= "#{Settings.source_dir}/header.sh"
|
48
|
+
end
|
31
49
|
end
|
32
50
|
end
|
33
51
|
end
|
@@ -1,32 +1,42 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
1
|
+
## Color functions [@bashly-upgrade colors]
|
2
|
+
## This file is a part of Bashly standard library
|
3
|
+
##
|
4
|
+
## Usage:
|
5
|
+
## Use any of the functions below to color or format a portion of a string.
|
6
|
+
##
|
7
|
+
## echo "before $(red this is red) after"
|
8
|
+
## echo "before $(green_bold this is green_bold) after"
|
9
|
+
##
|
10
|
+
## Color output will be disabled if `NO_COLOR` environment variable is set
|
11
|
+
## in compliance with https://no-color.org/
|
12
|
+
##
|
13
|
+
print_in_color() {
|
14
|
+
local color="$1"
|
15
|
+
shift
|
16
|
+
if [[ -z ${NO_COLOR+x} ]]; then
|
17
|
+
printf "$color%b\e[0m\n" "$*";
|
18
|
+
else
|
19
|
+
printf "%b\n" "$*";
|
20
|
+
fi
|
21
|
+
}
|
12
22
|
|
13
|
-
red() {
|
14
|
-
green() {
|
15
|
-
yellow() {
|
16
|
-
blue() {
|
17
|
-
magenta() {
|
18
|
-
cyan() {
|
19
|
-
bold() {
|
20
|
-
underlined() {
|
21
|
-
red_bold() {
|
22
|
-
green_bold() {
|
23
|
-
yellow_bold() {
|
24
|
-
blue_bold() {
|
25
|
-
magenta_bold() {
|
26
|
-
cyan_bold() {
|
27
|
-
red_underlined() {
|
28
|
-
green_underlined() {
|
29
|
-
yellow_underlined() {
|
30
|
-
blue_underlined() {
|
31
|
-
magenta_underlined() {
|
32
|
-
cyan_underlined() {
|
23
|
+
red() { print_in_color "\e[31m" "$*"; }
|
24
|
+
green() { print_in_color "\e[32m" "$*"; }
|
25
|
+
yellow() { print_in_color "\e[33m" "$*"; }
|
26
|
+
blue() { print_in_color "\e[34m" "$*"; }
|
27
|
+
magenta() { print_in_color "\e[35m" "$*"; }
|
28
|
+
cyan() { print_in_color "\e[36m" "$*"; }
|
29
|
+
bold() { print_in_color "\e[1m" "$*"; }
|
30
|
+
underlined() { print_in_color "\e[4m" "$*"; }
|
31
|
+
red_bold() { print_in_color "\e[1;31m" "$*"; }
|
32
|
+
green_bold() { print_in_color "\e[1;32m" "$*"; }
|
33
|
+
yellow_bold() { print_in_color "\e[1;33m" "$*"; }
|
34
|
+
blue_bold() { print_in_color "\e[1;34m" "$*"; }
|
35
|
+
magenta_bold() { print_in_color "\e[1;35m" "$*"; }
|
36
|
+
cyan_bold() { print_in_color "\e[1;36m" "$*"; }
|
37
|
+
red_underlined() { print_in_color "\e[4;31m" "$*"; }
|
38
|
+
green_underlined() { print_in_color "\e[4;32m" "$*"; }
|
39
|
+
yellow_underlined() { print_in_color "\e[4;33m" "$*"; }
|
40
|
+
blue_underlined() { print_in_color "\e[4;34m" "$*"; }
|
41
|
+
magenta_underlined() { print_in_color "\e[4;35m" "$*"; }
|
42
|
+
cyan_underlined() { print_in_color "\e[4;36m" "$*"; }
|
@@ -1,27 +1,27 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
# functions as needed.
|
1
|
+
## Config functions [@bashly-upgrade config]
|
2
|
+
## This file is a part of Bashly standard library
|
3
|
+
##
|
4
|
+
## Usage:
|
5
|
+
## - In your script, set the CONFIG_FILE variable. For rxample:
|
6
|
+
## CONFIG_FILE=settings.ini.
|
7
|
+
## If it is unset, it will default to 'config.ini'.
|
8
|
+
## - Use any of the functions below to access the config file.
|
9
|
+
##
|
10
|
+
## Create a new config file.
|
11
|
+
## There is normally no need to use this function, it is used by other
|
12
|
+
## functions as needed.
|
13
|
+
##
|
15
14
|
config_init() {
|
16
15
|
CONFIG_FILE=${CONFIG_FILE:=config.ini}
|
17
16
|
[[ -f "$CONFIG_FILE" ]] || touch "$CONFIG_FILE"
|
18
17
|
}
|
19
18
|
|
20
|
-
|
21
|
-
|
19
|
+
## Get a value from the config.
|
20
|
+
## Usage: result=$(config_get hello)
|
22
21
|
config_get() {
|
23
|
-
key=$1
|
24
|
-
regex="^$key *= *(.+)$"
|
22
|
+
local key=$1
|
23
|
+
local regex="^$key *= *(.+)$"
|
24
|
+
local value=""
|
25
25
|
|
26
26
|
config_init
|
27
27
|
|
@@ -35,18 +35,19 @@ config_get() {
|
|
35
35
|
echo "$value"
|
36
36
|
}
|
37
37
|
|
38
|
-
|
39
|
-
|
38
|
+
## Add or update a key=value pair in the config.
|
39
|
+
## Usage: config_set key value
|
40
40
|
config_set() {
|
41
|
-
key=$1
|
41
|
+
local key=$1
|
42
42
|
shift
|
43
|
-
value="$*"
|
43
|
+
local value="$*"
|
44
44
|
|
45
45
|
config_init
|
46
46
|
|
47
|
-
regex="^($key) *= *.+$"
|
48
|
-
output=""
|
49
|
-
found_key=""
|
47
|
+
local regex="^($key) *= *.+$"
|
48
|
+
local output=""
|
49
|
+
local found_key=""
|
50
|
+
local newline
|
50
51
|
|
51
52
|
while IFS= read -r line || [ -n "$line" ]; do
|
52
53
|
newline=$line
|
@@ -66,18 +67,17 @@ config_set() {
|
|
66
67
|
printf "%b\n" "$output" > "$CONFIG_FILE"
|
67
68
|
}
|
68
69
|
|
69
|
-
|
70
|
-
|
70
|
+
## Delete a key from the config.
|
71
|
+
## Usage: config_del key
|
71
72
|
config_del() {
|
72
|
-
key=$1
|
73
|
+
local key=$1
|
73
74
|
|
74
|
-
regex="^($key) *="
|
75
|
-
output=""
|
75
|
+
local regex="^($key) *="
|
76
|
+
local output=""
|
76
77
|
|
77
78
|
config_init
|
78
79
|
|
79
80
|
while IFS= read -r line || [ -n "$line" ]; do
|
80
|
-
newline=$line
|
81
81
|
if [[ $line ]] && [[ ! $line =~ $regex ]]; then
|
82
82
|
output="$output$line\n"
|
83
83
|
fi
|
@@ -86,25 +86,27 @@ config_del() {
|
|
86
86
|
printf "%b\n" "$output" > "$CONFIG_FILE"
|
87
87
|
}
|
88
88
|
|
89
|
-
|
89
|
+
## Show the config file
|
90
90
|
config_show() {
|
91
91
|
config_init
|
92
92
|
cat "$CONFIG_FILE"
|
93
93
|
}
|
94
94
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
95
|
+
## Return an array of the keys in the config file.
|
96
|
+
## Usage:
|
97
|
+
##
|
98
|
+
## for k in $(config_keys); do
|
99
|
+
## echo "- $k = $(config_get "$k")";
|
100
|
+
## done
|
101
|
+
##
|
102
102
|
config_keys() {
|
103
|
-
regex="^([a-zA-Z0-9_\-\/\.]+) *="
|
103
|
+
local regex="^([a-zA-Z0-9_\-\/\.]+) *="
|
104
104
|
|
105
105
|
config_init
|
106
106
|
|
107
|
-
keys=()
|
107
|
+
local keys=()
|
108
|
+
local key
|
109
|
+
|
108
110
|
while IFS= read -r line || [ -n "$line" ]; do
|
109
111
|
if [[ $line =~ $regex ]]; then
|
110
112
|
key="${BASH_REMATCH[1]}"
|
@@ -114,13 +116,13 @@ config_keys() {
|
|
114
116
|
echo "${keys[@]}"
|
115
117
|
}
|
116
118
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
119
|
+
## Returns true if the specified key exists in the config file.
|
120
|
+
## Usage:
|
121
|
+
##
|
122
|
+
## if config_has_key "key" ; then
|
123
|
+
## echo "key exists"
|
124
|
+
## fi
|
125
|
+
##
|
124
126
|
config_has_key() {
|
125
127
|
[[ $(config_get "$1") ]]
|
126
128
|
}
|
@@ -1,13 +1,13 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
1
|
+
## Add any function here that is needed in more than one parts of your
|
2
|
+
## application, or that you otherwise wish to extract from the main function
|
3
|
+
## scripts.
|
4
|
+
##
|
5
|
+
## Note that code here should be wrapped inside bash functions, and it is
|
6
|
+
## recommended to have a separate file for each function.
|
7
|
+
##
|
8
|
+
## Subdirectories will also be scanned for *.sh, so you have no reason not
|
9
|
+
## to organize your code neatly.
|
10
|
+
##
|
11
11
|
sample_function() {
|
12
12
|
echo "it works"
|
13
13
|
}
|
@@ -1,18 +1,15 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
#
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
#
|
14
|
-
# ---
|
15
|
-
|
1
|
+
## YAML parser [@bashly-upgrade yaml]
|
2
|
+
## This file is a part of Bashly standard library
|
3
|
+
## Does not support arrays, only hashes
|
4
|
+
##
|
5
|
+
## Source: https://stackoverflow.com/a/21189044/413924
|
6
|
+
##
|
7
|
+
## Usage:
|
8
|
+
##
|
9
|
+
## yaml_load "settings.yml" # print variables
|
10
|
+
## yaml_load "settings.yml" "config_" # use prefix
|
11
|
+
## eval $(yaml_load "settings.yml") # create variables in scope
|
12
|
+
##
|
16
13
|
yaml_load() {
|
17
14
|
local prefix=$2
|
18
15
|
local s='[[:space:]]*' w='[a-zA-Z0-9_]*'
|
@@ -32,3 +32,4 @@ missing_dependency: "missing dependency: %{dependency}"
|
|
32
32
|
disallowed_flag: "%{name} must be one of: %{allowed}"
|
33
33
|
disallowed_argument: "%{name} must be one of: %{allowed}"
|
34
34
|
unsupported_bash_version: "bash version 4 or higher is required"
|
35
|
+
validation_error: "validation error in %s:\\n%s"
|
data/lib/bashly/version.rb
CHANGED
@@ -8,9 +8,9 @@ parse_requirements() {
|
|
8
8
|
<%= render(:environment_variables_filter).indent 2 %>
|
9
9
|
<%= render(:dependencies_filter).indent 2 %>
|
10
10
|
<%= render(:command_filter).indent 2 %>
|
11
|
+
<%= render(:parse_requirements_while).indent 2 %>
|
11
12
|
<%= render(:required_args_filter).indent 2 %>
|
12
13
|
<%= render(:required_flags_filter).indent 2 %>
|
13
|
-
<%= render(:parse_requirements_while).indent 2 %>
|
14
14
|
<%= render(:catch_all_filter).indent 2 %>
|
15
15
|
<%= render(:default_assignments).indent 2 %>
|
16
16
|
<%= render(:whitelist_filter).indent 2 %>
|
@@ -2,7 +2,8 @@
|
|
2
2
|
% if args.any?
|
3
3
|
% condition = "if"
|
4
4
|
% args.each do |arg|
|
5
|
-
<%= condition %> [[
|
5
|
+
<%= condition %> [[ -z ${args[<%= arg.name %>]+x} ]]; then
|
6
|
+
<%= arg.render(:validations).indent 2 %>
|
6
7
|
args[<%= arg.name %>]=$1
|
7
8
|
shift
|
8
9
|
% condition = "elif"
|
@@ -1,11 +1,7 @@
|
|
1
1
|
# :command.required_args_filter
|
2
2
|
% required_args.each do |arg|
|
3
|
-
if [[
|
4
|
-
args[<%= arg.name %>]=$1
|
5
|
-
shift
|
6
|
-
else
|
3
|
+
if [[ -z ${args[<%= arg.name %>]+x} ]]; then
|
7
4
|
printf "<%= strings[:missing_required_argument] % { arg: arg.name.upcase, usage: usage_string } %>\n"
|
8
5
|
exit 1
|
9
6
|
fi
|
10
|
-
|
11
7
|
% end
|
@@ -1,9 +1,6 @@
|
|
1
1
|
# :command.required_flags_filter
|
2
|
-
% if required_flags.any?
|
3
|
-
argstring="$*"
|
4
|
-
% end
|
5
2
|
% required_flags.each do |flag|
|
6
|
-
if [[ <%= flag.
|
3
|
+
if [[ -z ${args[<%= flag.long %>]+x} ]]; then
|
7
4
|
printf "<%= strings[:missing_required_flag] % { usage: flag.usage_string } %>\n"
|
8
5
|
exit 1
|
9
6
|
fi
|
File without changes
|
data/lib/bashly.rb
CHANGED
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.
|
4
|
+
version: 0.7.0
|
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: 2021-
|
11
|
+
date: 2021-10-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: colsole
|
@@ -88,24 +88,41 @@ files:
|
|
88
88
|
- lib/bashly/config.rb
|
89
89
|
- lib/bashly/exceptions.rb
|
90
90
|
- lib/bashly/extensions/array.rb
|
91
|
+
- lib/bashly/extensions/file.rb
|
91
92
|
- lib/bashly/extensions/string.rb
|
93
|
+
- lib/bashly/library/base.rb
|
94
|
+
- lib/bashly/library/colors.rb
|
95
|
+
- lib/bashly/library/completions.rb
|
96
|
+
- lib/bashly/library/completions_function.rb
|
97
|
+
- lib/bashly/library/completions_script.rb
|
98
|
+
- lib/bashly/library/completions_yaml.rb
|
99
|
+
- lib/bashly/library/config.rb
|
100
|
+
- lib/bashly/library/sample.rb
|
101
|
+
- lib/bashly/library/strings.rb
|
102
|
+
- lib/bashly/library/validations.rb
|
103
|
+
- lib/bashly/library/yaml.rb
|
92
104
|
- lib/bashly/message_strings.rb
|
93
|
-
- lib/bashly/
|
94
|
-
- lib/bashly/
|
95
|
-
- lib/bashly/
|
96
|
-
- lib/bashly/
|
97
|
-
- lib/bashly/
|
98
|
-
- lib/bashly/
|
105
|
+
- lib/bashly/script/argument.rb
|
106
|
+
- lib/bashly/script/base.rb
|
107
|
+
- lib/bashly/script/command.rb
|
108
|
+
- lib/bashly/script/environment_variable.rb
|
109
|
+
- lib/bashly/script/flag.rb
|
110
|
+
- lib/bashly/script/wrapper.rb
|
99
111
|
- lib/bashly/settings.rb
|
100
112
|
- lib/bashly/templates/bashly.yml
|
101
113
|
- lib/bashly/templates/lib/colors.sh
|
102
114
|
- lib/bashly/templates/lib/config.sh
|
103
115
|
- lib/bashly/templates/lib/sample_function.sh
|
116
|
+
- lib/bashly/templates/lib/validations/validate_dir_exists.sh
|
117
|
+
- lib/bashly/templates/lib/validations/validate_file_exists.sh
|
118
|
+
- lib/bashly/templates/lib/validations/validate_integer.sh
|
119
|
+
- lib/bashly/templates/lib/validations/validate_not_empty.sh
|
104
120
|
- lib/bashly/templates/lib/yaml.sh
|
105
121
|
- lib/bashly/templates/minimal.yml
|
106
122
|
- lib/bashly/templates/strings.yml
|
107
123
|
- lib/bashly/version.rb
|
108
124
|
- lib/bashly/views/argument/usage.erb
|
125
|
+
- lib/bashly/views/argument/validations.erb
|
109
126
|
- lib/bashly/views/command/catch_all_filter.erb
|
110
127
|
- lib/bashly/views/command/command_fallback.erb
|
111
128
|
- lib/bashly/views/command/command_filter.erb
|
@@ -143,8 +160,10 @@ files:
|
|
143
160
|
- lib/bashly/views/environment_variable/usage.erb
|
144
161
|
- lib/bashly/views/flag/case.erb
|
145
162
|
- lib/bashly/views/flag/usage.erb
|
146
|
-
- lib/bashly/views/
|
147
|
-
- lib/bashly/views/
|
163
|
+
- lib/bashly/views/flag/validations.erb
|
164
|
+
- lib/bashly/views/wrapper/bash3_bouncer.erb
|
165
|
+
- lib/bashly/views/wrapper/header.erb
|
166
|
+
- lib/bashly/views/wrapper/wrapper.erb
|
148
167
|
homepage: https://github.com/dannyben/bashly
|
149
168
|
licenses:
|
150
169
|
- MIT
|