bashly 0.2.2 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +21 -10
- data/lib/bashly/commands/generate.rb +3 -2
- data/lib/bashly/concerns/renderable.rb +2 -0
- data/lib/bashly/extensions/string.rb +16 -9
- data/lib/bashly/models/argument.rb +0 -9
- data/lib/bashly/models/base.rb +12 -1
- data/lib/bashly/models/command.rb +45 -11
- data/lib/bashly/models/flag.rb +0 -9
- data/lib/bashly/templates/lib/config.sh +1 -2
- data/lib/bashly/templates/strings.yml +2 -2
- data/lib/bashly/version.rb +1 -1
- data/lib/bashly/views/argument/usage.erb +1 -1
- data/lib/bashly/views/command/command_filter.erb +3 -3
- data/lib/bashly/views/command/command_functions.erb +2 -2
- data/lib/bashly/views/command/default_script.erb +1 -1
- data/lib/bashly/views/command/fixed_flags_filter.erb +2 -2
- data/lib/bashly/views/command/function.erb +2 -2
- data/lib/bashly/views/command/parse_args.erb +5 -1
- data/lib/bashly/views/command/run.erb +4 -4
- data/lib/bashly/views/command/usage.erb +23 -3
- data/lib/bashly/views/command/usage_environment_variables.erb +1 -1
- data/lib/bashly/views/command/usage_examples.erb +2 -1
- data/lib/bashly/views/command/usage_fixed_flags.erb +4 -2
- data/lib/bashly/views/flag/usage.erb +1 -1
- metadata +2 -3
- data/lib/bashly/views/command/parse_args_secondary.erb +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d40ad6e14ab17c88a939cea3be81f4b72fe8383021478d94c93328c4842fb395
|
4
|
+
data.tar.gz: 4cb84c229411360da7633dd4ad4a15bb53bfdf49fba81e82aecbf88ec3422d72
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cb14645de6f614ce24393820591f6917bd92a7c41c48f14456b789183648c8031653c0304f8e59a2c43fecd7a4f0ed0e9ab4cf6a5092f0e5bd742de157af7b0c
|
7
|
+
data.tar.gz: b1b9fca567512ade4957a9b484d853b871f2c2edbefb267fc0c8fdbea8e5c2b1c5792cc011e04b60d07dc9e09b62996e18c826fd67902d28549e505bce8c30ce
|
data/README.md
CHANGED
@@ -119,36 +119,42 @@ Configuration Reference
|
|
119
119
|
|
120
120
|
### Command options
|
121
121
|
|
122
|
-
|
123
|
-
|
124
|
-
any subcommand you define using `commands`.
|
122
|
+
Unless otherwise specified, these definitiona can be used for both the root
|
123
|
+
command and subcommands (under the `commands` definition).
|
125
124
|
|
126
125
|
```yaml
|
127
126
|
# The name of the script or subcommand
|
128
127
|
name: myscript
|
129
128
|
|
129
|
+
# An additional, optional name - usually used to denote a one letter
|
130
|
+
# variation of the command name
|
131
|
+
# Applicable only in subcommands
|
132
|
+
short: m
|
133
|
+
|
130
134
|
# The header text to display when using --help
|
131
135
|
# This can have multiple lines. In this case, the first line will be used as
|
132
136
|
# summary wherever appropriate.
|
133
137
|
help: a sample script generated with bashly
|
134
138
|
|
135
139
|
# The string to display when using --version
|
140
|
+
# Applicable only in the main command
|
136
141
|
version: 0.1.0
|
137
142
|
|
138
143
|
# Specify an array of examples to show when using --help
|
144
|
+
# Each example can have multiple lines.
|
139
145
|
examples:
|
140
146
|
- myscript download
|
141
147
|
- myscript download --force
|
142
148
|
|
143
149
|
# Specify an array of environment variables needed by your script
|
144
150
|
# This is used purely for displaying in the help text (when using --help)
|
151
|
+
# The help for each variable can have multiple lines.
|
145
152
|
environment_variable:
|
146
153
|
VARIABLE_NAME: Variable help text
|
147
154
|
|
148
155
|
# Specify the array of subcommands to generate.
|
149
156
|
# Each subcommand will have its own args and flags.
|
150
|
-
# If this is provided,
|
151
|
-
# script.
|
157
|
+
# If this is provided, you cannot provide flags or args for the main script.
|
152
158
|
commands:
|
153
159
|
- ...
|
154
160
|
|
@@ -185,8 +191,7 @@ bash function.
|
|
185
191
|
name: user
|
186
192
|
|
187
193
|
# The message to display when using --help.
|
188
|
-
# This can have multiple lines
|
189
|
-
# than ~70 characters, to avoid text wrapping in narrower terminals.
|
194
|
+
# This can have multiple lines.
|
190
195
|
help: Username to use for logging in
|
191
196
|
|
192
197
|
# Specify if this argument is required.
|
@@ -216,8 +221,7 @@ long: --output
|
|
216
221
|
short: -o
|
217
222
|
|
218
223
|
# The text to display when using --help
|
219
|
-
# This can have multiple lines
|
220
|
-
# than ~70 characters, to avoid text wrapping in narrower terminals.
|
224
|
+
# This can have multiple lines.
|
221
225
|
help: Specify the output directory
|
222
226
|
|
223
227
|
# If the flag requires an argument, specify its name here.
|
@@ -227,6 +231,13 @@ arg: directory
|
|
227
231
|
required: true
|
228
232
|
```
|
229
233
|
|
234
|
+
|
235
|
+
Real World Examples
|
236
|
+
--------------------------------------------------
|
237
|
+
|
238
|
+
- [Rush][rush] - a Personal Package Manager
|
239
|
+
|
240
|
+
|
230
241
|
Contributing / Support
|
231
242
|
--------------------------------------------------
|
232
243
|
|
@@ -234,4 +245,4 @@ If you experience any issue, have a question or a suggestion, or if you wish
|
|
234
245
|
to contribute, feel free to [open an issue][issues].
|
235
246
|
|
236
247
|
[issues]: https://github.com/DannyBen/bashly/issues
|
237
|
-
|
248
|
+
[rush]: https://github.com/DannyBen/rush-cli
|
@@ -36,8 +36,9 @@ module Bashly
|
|
36
36
|
end
|
37
37
|
|
38
38
|
def create_all_command_files
|
39
|
-
command.
|
40
|
-
|
39
|
+
command.deep_commands.each do |subcommand|
|
40
|
+
next if subcommand.commands.any?
|
41
|
+
file = "#{Settings.source_dir}/#{subcommand.filename}"
|
41
42
|
content = subcommand.render :default_script
|
42
43
|
create_file file, content
|
43
44
|
end
|
@@ -1,20 +1,27 @@
|
|
1
|
-
require 'erb'
|
2
|
-
require 'ostruct'
|
3
|
-
|
4
1
|
class String
|
2
|
+
def escape_newlines
|
3
|
+
gsub "\n", "\\n"
|
4
|
+
end
|
5
|
+
|
5
6
|
def indent(offset)
|
6
7
|
return self unless offset > 0
|
7
8
|
split("\n").indent(offset).join("\n")
|
8
9
|
end
|
9
10
|
|
10
|
-
def to_underscore
|
11
|
-
gsub
|
12
|
-
gsub!(' ', '_')
|
13
|
-
downcase!
|
11
|
+
def to_underscore
|
12
|
+
gsub(/(.)([A-Z])/,'\1_\2').gsub(' ', '_').downcase
|
14
13
|
end
|
15
14
|
|
16
|
-
def
|
17
|
-
|
15
|
+
def wrap(length = 80)
|
16
|
+
strip!
|
17
|
+
split("\n").collect! do |line|
|
18
|
+
if line.length > length
|
19
|
+
line.gsub!(/([^\s]{#{length}})([^\s$])/, "\\1 \\2")
|
20
|
+
line.gsub(/(.{1,#{length}})(\s+|$)/, "\\1\n").rstrip
|
21
|
+
else
|
22
|
+
line
|
23
|
+
end
|
24
|
+
end * "\n"
|
18
25
|
end
|
19
26
|
|
20
27
|
end
|
@@ -1,18 +1,9 @@
|
|
1
1
|
module Bashly
|
2
2
|
module Models
|
3
3
|
class Argument < Base
|
4
|
-
def optional
|
5
|
-
!required
|
6
|
-
end
|
7
|
-
|
8
4
|
def usage_string
|
9
5
|
required ? name.upcase : "[#{name.upcase}]"
|
10
6
|
end
|
11
|
-
|
12
|
-
def summary
|
13
|
-
return "" unless help
|
14
|
-
help.split("\n").first
|
15
|
-
end
|
16
7
|
end
|
17
8
|
end
|
18
9
|
end
|
data/lib/bashly/models/base.rb
CHANGED
@@ -26,13 +26,24 @@ module Bashly
|
|
26
26
|
verify if respond_to? :verify
|
27
27
|
end
|
28
28
|
|
29
|
+
def optional
|
30
|
+
!required
|
31
|
+
end
|
32
|
+
|
33
|
+
def summary
|
34
|
+
help.empty? ? "" : help.split("\n").first
|
35
|
+
end
|
36
|
+
|
37
|
+
def help
|
38
|
+
options['help'] ||= ''
|
39
|
+
end
|
40
|
+
|
29
41
|
def method_missing(method_name, *arguments, &block)
|
30
42
|
key = method_name.to_s
|
31
43
|
respond_to?(method_name) ? options[key] : super
|
32
44
|
end
|
33
45
|
|
34
46
|
def respond_to?(method_name, include_private = false)
|
35
|
-
# options.has_key?(method_name.to_s) || super
|
36
47
|
OPTION_KEYS.include?(method_name) || super
|
37
48
|
end
|
38
49
|
end
|
@@ -1,6 +1,15 @@
|
|
1
1
|
module Bashly
|
2
2
|
module Models
|
3
3
|
class Command < Base
|
4
|
+
# Returns the name to be used as an action.
|
5
|
+
# - If it is the root command, the action is "root"
|
6
|
+
# - Else, it is all the parents, except the first tone (root) joined
|
7
|
+
# by space. For example, for a command like "docker container run"
|
8
|
+
# the action name is "container run".
|
9
|
+
def action_name
|
10
|
+
parents.any? ? (parents[1..-1] + [name]).join(' ') : "root"
|
11
|
+
end
|
12
|
+
|
4
13
|
# Returns all the possible aliases for this command
|
5
14
|
def aliases
|
6
15
|
short ? [name, short] : [name]
|
@@ -28,11 +37,30 @@ module Bashly
|
|
28
37
|
def commands
|
29
38
|
return [] unless options["commands"]
|
30
39
|
options["commands"].map do |options|
|
31
|
-
options['
|
40
|
+
options['parents'] = parents + [name]
|
32
41
|
command = Command.new options
|
33
42
|
end
|
34
43
|
end
|
35
44
|
|
45
|
+
# Returns a flat array containing all the commands in this tree.
|
46
|
+
# This includes self + children + grandchildres + ...
|
47
|
+
def deep_commands
|
48
|
+
result = []
|
49
|
+
commands.each do |command|
|
50
|
+
result << command
|
51
|
+
if command.commands.any?
|
52
|
+
result += command.deep_commands
|
53
|
+
end
|
54
|
+
end
|
55
|
+
result
|
56
|
+
end
|
57
|
+
|
58
|
+
# Returns the bash filename that is expected to hold the user code
|
59
|
+
# for this command
|
60
|
+
def filename
|
61
|
+
"#{action_name.to_underscore}_command.sh"
|
62
|
+
end
|
63
|
+
|
36
64
|
# Returns an array of Flags
|
37
65
|
def flags
|
38
66
|
return [] unless options["flags"]
|
@@ -41,10 +69,15 @@ module Bashly
|
|
41
69
|
end
|
42
70
|
end
|
43
71
|
|
72
|
+
# Returns a unique name, suitable to be used in a bash function
|
73
|
+
def function_name
|
74
|
+
full_name.to_underscore
|
75
|
+
end
|
76
|
+
|
44
77
|
# Returns the name of the command, including its parent name (in case
|
45
78
|
# this is a subcommand)
|
46
79
|
def full_name
|
47
|
-
|
80
|
+
parents.any? ? (parents + [name]).join(' ') : name
|
48
81
|
end
|
49
82
|
|
50
83
|
# Reads a file from the userspace (Settings.source_dir) and returns
|
@@ -52,7 +85,7 @@ module Bashly
|
|
52
85
|
# If the file is not found, returns a string with a hint.
|
53
86
|
def load_user_file(file, placeholder: true)
|
54
87
|
path = "#{Settings.source_dir}/#{file}"
|
55
|
-
default_content = placeholder ? "
|
88
|
+
default_content = placeholder ? "echo \"error: cannot load file\"" : ''
|
56
89
|
|
57
90
|
content = if File.exist? path
|
58
91
|
File.read path
|
@@ -63,6 +96,12 @@ module Bashly
|
|
63
96
|
"# :#{path}\n#{content}"
|
64
97
|
end
|
65
98
|
|
99
|
+
# Returns an array of all parents. For example, the command
|
100
|
+
# "docker container run" will have [docker, container] as its parents
|
101
|
+
def parents
|
102
|
+
options['parents'] || []
|
103
|
+
end
|
104
|
+
|
66
105
|
# Returns an array of all the required Arguments
|
67
106
|
def required_args
|
68
107
|
args.select &:required
|
@@ -73,10 +112,9 @@ module Bashly
|
|
73
112
|
flags.select &:required
|
74
113
|
end
|
75
114
|
|
76
|
-
# Returns
|
77
|
-
def
|
78
|
-
|
79
|
-
help.split("\n").first
|
115
|
+
# Returns trus if this is the root command (no parents)
|
116
|
+
def root_command?
|
117
|
+
parents.empty?
|
80
118
|
end
|
81
119
|
|
82
120
|
# Returns a constructed string suitable for Usage pattern
|
@@ -109,10 +147,6 @@ module Bashly
|
|
109
147
|
if args.any? or flags.any?
|
110
148
|
raise ConfigurationError, "Error in the !txtgrn!#{full_name}!txtrst! command.\nThe !txtgrn!commands!txtrst! key cannot be at the same level as the !txtgrn!args!txtrst! or !txtgrn!flags!txtrst! keys."
|
111
149
|
end
|
112
|
-
|
113
|
-
if parent_name
|
114
|
-
raise ConfigurationError, "Error in the !txtgrn!#{full_name}!txtrst! command.\nNested commands are not supported."
|
115
|
-
end
|
116
150
|
end
|
117
151
|
|
118
152
|
end
|
data/lib/bashly/models/flag.rb
CHANGED
@@ -11,15 +11,6 @@ module Bashly
|
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
-
def optional
|
15
|
-
!required
|
16
|
-
end
|
17
|
-
|
18
|
-
def summary
|
19
|
-
return "" unless help
|
20
|
-
help.split("\n").first
|
21
|
-
end
|
22
|
-
|
23
14
|
def usage_string(extended: false)
|
24
15
|
result = [aliases.join(", ")]
|
25
16
|
result << arg.upcase if arg
|
@@ -100,7 +100,6 @@ config_show() {
|
|
100
100
|
# done
|
101
101
|
#
|
102
102
|
config_keys() {
|
103
|
-
key=$1
|
104
103
|
regex="^(.*)\s*="
|
105
104
|
|
106
105
|
config_init
|
@@ -112,5 +111,5 @@ config_keys() {
|
|
112
111
|
keys+=("$key")
|
113
112
|
fi
|
114
113
|
done < "$CONFIG_FILE"
|
115
|
-
echo ${keys[@]}
|
114
|
+
echo "${keys[@]}"
|
116
115
|
}
|
@@ -7,8 +7,8 @@ examples: "Examples:"
|
|
7
7
|
environment_variables: "Environment Variables:"
|
8
8
|
|
9
9
|
# Fixed flags help text
|
10
|
-
|
11
|
-
|
10
|
+
help_flag_text: Show this help
|
11
|
+
version_flag_text: Show version number
|
12
12
|
|
13
13
|
# Error messages
|
14
14
|
flag_requires_an_argument: "%{long} requires an argument: %{usage}"
|
data/lib/bashly/version.rb
CHANGED
@@ -10,17 +10,17 @@ case $action in
|
|
10
10
|
<%= command.aliases.join " | " %> )
|
11
11
|
action="<%= command.name %>"
|
12
12
|
shift
|
13
|
-
<%= command.
|
13
|
+
<%= command.function_name %>_parse_args "$@"
|
14
14
|
shift $#
|
15
15
|
;;
|
16
16
|
|
17
17
|
<%- end -%>
|
18
18
|
* )
|
19
|
-
<%=
|
19
|
+
<%= function_name %>_usage
|
20
20
|
exit 1
|
21
21
|
;;
|
22
22
|
|
23
23
|
esac
|
24
24
|
<%- else -%>
|
25
|
-
action=
|
25
|
+
action="<%= action_name %>"
|
26
26
|
<%- end -%>
|
@@ -1,4 +1,4 @@
|
|
1
|
-
echo "# this file is located in '<%= Settings.source_dir
|
1
|
+
echo "# this file is located in '<%= "#{Settings.source_dir}/#{filename}" %>'"
|
2
2
|
echo "# code for '<%= full_name %>' goes here"
|
3
3
|
echo "# you can edit it freely and regenerate (it will not be overwritten)"
|
4
4
|
inspect_args
|
@@ -1,5 +1,9 @@
|
|
1
1
|
# :command.parse_args
|
2
|
+
<%- if root_command? -%>
|
2
3
|
parse_args() {
|
4
|
+
<%- else -%>
|
5
|
+
<%= function_name %>_parse_args() {
|
6
|
+
<%- end -%>
|
3
7
|
<%= render(:fixed_flags_filter).indent 2 %>
|
4
8
|
<%= render(:command_filter).indent 2 %>
|
5
9
|
<%= render(:required_args_filter).indent 2 %>
|
@@ -8,5 +12,5 @@ parse_args() {
|
|
8
12
|
}
|
9
13
|
|
10
14
|
<%- commands.each do |command| %>
|
11
|
-
<%= command.render '
|
15
|
+
<%= command.render 'parse_args' %>
|
12
16
|
<%- end -%>
|
@@ -4,13 +4,13 @@ run() {
|
|
4
4
|
parse_args "$@"
|
5
5
|
|
6
6
|
<%- condition = "if" -%>
|
7
|
-
<%-
|
8
|
-
<%= condition %> [[ $action == "<%= command.
|
7
|
+
<%- deep_commands.each do |command| -%>
|
8
|
+
<%= condition %> [[ $action == "<%= command.action_name %>" ]]; then
|
9
9
|
if [[ ${args[--help]} ]]; then
|
10
10
|
long_usage=yes
|
11
|
-
<%= command.
|
11
|
+
<%= command.function_name %>_usage
|
12
12
|
else
|
13
|
-
<%= command.
|
13
|
+
<%= command.function_name %>_command
|
14
14
|
fi
|
15
15
|
<% condition = "elif" %>
|
16
16
|
<%- end -%>
|
@@ -1,9 +1,29 @@
|
|
1
1
|
# :command.usage
|
2
|
-
<%=
|
3
|
-
|
4
|
-
|
2
|
+
<%= function_name %>_usage() {
|
3
|
+
if [[ -n $long_usage ]]; then
|
4
|
+
<%- if summary == help -%>
|
5
|
+
echo -e "<%= caption_string %>"
|
6
|
+
echo
|
7
|
+
<%- else -%>
|
8
|
+
echo -e "<%= full_name %>"
|
9
|
+
echo
|
10
|
+
echo -e "<%= help.wrap(78).indent(2).escape_newlines %>"
|
11
|
+
echo
|
12
|
+
<%- end -%>
|
13
|
+
else
|
14
|
+
echo -e "<%= caption_string %>"
|
15
|
+
echo
|
16
|
+
fi
|
5
17
|
echo -e "<%= strings[:usage] %>"
|
6
18
|
echo -e " <%= usage_string %>"
|
19
|
+
<%- if commands.any? -%>
|
20
|
+
echo -e " <%= full_name %> [command] --help | -h"
|
21
|
+
<%- else -%>
|
22
|
+
echo -e " <%= full_name %> --help | -h"
|
23
|
+
<%- end -%>
|
24
|
+
<%- if root_command? -%>
|
25
|
+
echo -e " <%= full_name %> --version"
|
26
|
+
<%- end -%>
|
7
27
|
echo
|
8
28
|
<%= render(:usage_commands).indent 2 if commands.any? %>
|
9
29
|
|
@@ -1,7 +1,9 @@
|
|
1
1
|
# :command.usage_fixed_flags
|
2
2
|
echo " --help, -h"
|
3
|
-
echo -e " <%= strings[:
|
3
|
+
echo -e " <%= strings[:help_flag_text] %>"
|
4
4
|
echo
|
5
|
+
<%- if root_command? -%>
|
5
6
|
echo " --version"
|
6
|
-
echo -e " <%= strings[:
|
7
|
+
echo -e " <%= strings[:version_flag_text] %>"
|
7
8
|
echo
|
9
|
+
<%- end -%>
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bashly
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.3
|
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: 2019-11-
|
11
|
+
date: 2019-11-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: colsole
|
@@ -101,7 +101,6 @@ files:
|
|
101
101
|
- lib/bashly/views/command/master_script.erb
|
102
102
|
- lib/bashly/views/command/parse_args.erb
|
103
103
|
- lib/bashly/views/command/parse_args_case.erb
|
104
|
-
- lib/bashly/views/command/parse_args_secondary.erb
|
105
104
|
- lib/bashly/views/command/parse_args_while.erb
|
106
105
|
- lib/bashly/views/command/required_args_filter.erb
|
107
106
|
- lib/bashly/views/command/required_flags_filter.erb
|