bashly 0.6.6 → 0.7.0
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/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
|