bashly 0.3.8 → 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e3a38c45e77dbe9cae7c0f8949bef8727f248803cb903f2028c4069dcbbed392
4
- data.tar.gz: 6dd5bd930b3cdd217ac46c232a06c4f652afab2f3fe6ce09ff1dfae2b0e257b6
3
+ metadata.gz: 4d486637f9d7ec6604d0495aec9f2396f69153f8cd193c126d51bc7dbc329a62
4
+ data.tar.gz: 5c58b05ad9ccb84d432c42228b7594e678b033555e55ea275948d4e70be118c7
5
5
  SHA512:
6
- metadata.gz: 30970143ef9c35e9ee568bfd38b6e6030551e7fe38866b469570b1cb204639f5f56706002d62dd9b97149537d57b30a028620aa39fd6cbf79b9dc24adcbaa6ed
7
- data.tar.gz: 7cf260e1917e582a76138522b5d54436fe0e87dfcf62251f7c2bd89aabe742a58516927cf526cf20629747a3f09940518d3a07b603f5318603a940e2262328fe
6
+ metadata.gz: 02fd6e6c50c5d370dde3d50047b0b6d317454c3d48531222711c6341c6e93d263cafa6a7d541bb939ff44a36b6025c9c8411e8f3820157c41e476312f4c64781
7
+ data.tar.gz: 031ea1db4c68fb6b780f01862b216178804cdc44f2e86fc66bc11f2910fff6d03ed250d7a01dd1c566d74c8f002ae6e9441bb13292f3e74620db455c993029e2
data/README.md CHANGED
@@ -1,8 +1,7 @@
1
1
  <div align='center'>
2
2
  <img src='logo.svg' width=280>
3
3
 
4
- Bashly - Bash CLI Framework and Generator
5
- ==================================================
4
+ # Bashly - Bash CLI Framework and Generator
6
5
 
7
6
  Create beautiful bash scripts from simple YAML configuration
8
7
 
@@ -16,25 +15,46 @@ Create beautiful bash scripts from simple YAML configuration
16
15
 
17
16
  </div>
18
17
 
18
+ ## Table of Contents
19
+
20
+ - [Table of Contents](#table-of-contents)
21
+ - [Installation](#installation)
22
+ - [Prerequisites](#prerequisites)
23
+ - [What is Bashly](#what-is-bashly)
24
+ - [Usage](#usage)
25
+ - [Using the input arguemnts in your code](#using-the-input-arguemnts-in-your-code)
26
+ - [Examples](#examples)
27
+ - [Sample configuraiton for a script without commands](#sample-configuraiton-for-a-script-without-commands)
28
+ - [Sample configuraiton for a script with commands](#sample-configuraiton-for-a-script-with-commands)
29
+ - [Configuration Reference](#configuration-reference)
30
+ - [Command options](#command-options)
31
+ - [Argument options](#argument-options)
32
+ - [Flag options](#flag-options)
33
+ - [Environment Variable options](#environment-variable-options)
34
+ - [Real World Examples](#real-world-examples)
35
+ - [Contributing / Support](#contributing--support)
36
+
19
37
  ---
20
38
 
21
- Installation
22
- --------------------------------------------------
39
+ ## Installation
23
40
 
24
41
  ```shell
25
42
  $ gem install bashly
26
43
  ```
27
44
 
45
+ or with Docker:
28
46
 
29
- Prerequisites
30
- --------------------------------------------------
47
+ ```shell
48
+ $ alias bashly='docker run --rm -it --volume "$PWD:/app" dannyben/bashly'
49
+ ```
50
+
51
+ ## Prerequisites
31
52
 
32
53
  The bash scripts generated by bashly require bash 4 or higher due to heavy
33
54
  use of associative arrays.
34
55
 
35
56
 
36
- What is Bashly
37
- --------------------------------------------------
57
+ ## What is Bashly
38
58
 
39
59
  Bashly is a command line application (written in Ruby) that lets you generate
40
60
  feature-rich bash command line tools.
@@ -61,9 +81,9 @@ Bahsly is responsible for:
61
81
  - **Color output**.
62
82
  - **Config file management** (INI format).
63
83
  - **YAML parsing**.
84
+ - and more.
64
85
 
65
- Usage
66
- --------------------------------------------------
86
+ ## Usage
67
87
 
68
88
  In an empty directory, create a sample configuration file by running
69
89
 
@@ -93,9 +113,46 @@ Finally, edit the files in the `src` folder. Each of your script's commands
93
113
  get their own file. Once you edit, run `bashly generate` again to merge the
94
114
  content from your functions back into the script.
95
115
 
116
+ ### Using the input arguemnts in your code
117
+
118
+ In order to access the parsed arguments in any of your partial scripts, you
119
+ may simply access the `$args` associative array.
120
+
121
+ For example:
122
+
123
+ 1. Generate a minimal configuration with `bashly init --minimal`
124
+ 2. Generate the bash script with `bashly generate`
125
+ 3. Run the script with `./download hello --force`
126
+
127
+ You will notice that all the arguments of the associative array are printed
128
+ on screen. This is done by the `inspect_args` function that was inserted into
129
+ the generated partial script `src/root_command.sh`.
130
+
131
+ You can now access these variables by modifying `sec/root_command.sh` like
132
+ this:
96
133
 
97
- Examples
98
- --------------------------------------------------
134
+
135
+ ```bash
136
+ # src/root_command.sh
137
+ source_url=${args[source]}
138
+ force=${args[--force]}
139
+
140
+ if [[ $force ]]; then
141
+ echo "downloading $source_url with --force"
142
+ else
143
+ echo "downloading $source_url"
144
+ fi
145
+ ```
146
+
147
+ After editing the file, run `bashly generate` (or `bashly g` for short) and
148
+ run:
149
+
150
+ ```
151
+ $ ./download a --force
152
+ downloading a with --force
153
+ ```
154
+
155
+ ## Examples
99
156
 
100
157
  The `bashly.yml` file can be set up to generate two types of scripts:
101
158
 
@@ -123,8 +180,7 @@ See the [examples](examples) folder for more examples.
123
180
 
124
181
 
125
182
 
126
- Configuration Reference
127
- --------------------------------------------------
183
+ ## Configuration Reference
128
184
 
129
185
  The `bashly.yml` configuration file consists of these types:
130
186
 
@@ -167,6 +223,7 @@ bash function.
167
223
  `help` | The message to display when using `--help`. Can have multiple lines.
168
224
  `required` | Specify if this argument is required. Note that once you define an optional argument (without required: true) then you cannot define required arguments after it.
169
225
  `default` | The value to use in case it is not provided by the user. Implies that this argument is optional.
226
+ `allowed` | Limit the allowed values by providing an array.
170
227
 
171
228
  ### Flag options
172
229
 
@@ -182,6 +239,7 @@ short form).
182
239
  `arg` | If the flag requires an argument, specify its name here.
183
240
  `required` | Specify if this flag is required.
184
241
  `default` | The value to use in case it is not provided by the user. Implies that this flag is optional, and only makes sense when the flag has an argument.
242
+ `allowed` | For flags with an argument, you can limit the allowed values by providing an array.
185
243
 
186
244
  #### Special handling for -v and -h
187
245
 
@@ -204,15 +262,14 @@ set.
204
262
  `required` | Specify if this variable is required.
205
263
 
206
264
 
207
- Real World Examples
208
- --------------------------------------------------
265
+ ## Real World Examples
209
266
 
210
267
  - [Rush][rush] - a Personal Package Manager
211
268
  - [Alf][alf] - a generator for bash aliases and sub-aliases
269
+ - [git-changelog][git-changelog] - a change log generator
212
270
 
213
271
 
214
- Contributing / Support
215
- --------------------------------------------------
272
+ ## Contributing / Support
216
273
 
217
274
  If you experience any issue, have a question or a suggestion, or if you wish
218
275
  to contribute, feel free to [open an issue][issues].
@@ -220,4 +277,6 @@ to contribute, feel free to [open an issue][issues].
220
277
  [issues]: https://github.com/DannyBen/bashly/issues
221
278
  [rush]: https://github.com/DannyBen/rush-cli
222
279
  [alf]: https://github.com/DannyBen/alf
280
+ [git-changelog]: https://github.com/DannyBen/git-changelog
281
+
223
282
 
@@ -3,14 +3,18 @@ module Bashly
3
3
  class Generate < Base
4
4
  help "Generate the bash script and required files"
5
5
 
6
- usage "bashly generate [--force]"
6
+ usage "bashly generate [--force --wrap FUNCTION]"
7
7
  usage "bashly generate (-h|--help)"
8
8
 
9
9
  option "-f --force", "Overwrite existing files"
10
+ option "-w --wrap FUNCTION", "Wrap the entire script in a function so it can also be sourced"
10
11
 
11
12
  environment "BASHLY_SOURCE_DIR", "The path containing the bashly configuration and source files [default: src]"
12
13
  environment "BASHLY_TARGET_DIR", "The path to use for creating the bash script [default: .]"
13
14
 
15
+ example "bashly generate --force"
16
+ example "bashly generate --wrap my_function"
17
+
14
18
  def run
15
19
  create_user_files
16
20
  create_master_script
@@ -54,12 +58,15 @@ module Bashly
54
58
  end
55
59
 
56
60
  def create_master_script
57
- master_script = command.render('master_script').lint
58
- File.write master_script_path, master_script
61
+ File.write master_script_path, script.code
59
62
  FileUtils.chmod "+x", master_script_path
60
63
  say "created !txtgrn!#{master_script_path}"
61
64
  end
62
65
 
66
+ def script
67
+ @script ||= Models::Script.new(command, args['--wrap'])
68
+ end
69
+
63
70
  def master_script_path
64
71
  "#{Settings.target_dir}/#{command.name}"
65
72
  end
@@ -11,7 +11,8 @@ module Bashly
11
11
  def run
12
12
  config = Config.new "#{Settings.source_dir}/bashly.yml"
13
13
  command = Models::Command.new(config)
14
- puts command.render 'master_script'
14
+ script = Models::Script.new command
15
+ puts script.code
15
16
  end
16
17
  end
17
18
  end
@@ -6,10 +6,11 @@ module Bashly
6
6
  attr_reader :options
7
7
 
8
8
  OPTION_KEYS = %i[
9
+ allowed
9
10
  arg
11
+ default
10
12
  dependencies
11
13
  description
12
- default
13
14
  environment_variables
14
15
  examples
15
16
  flags
@@ -175,6 +175,16 @@ module Bashly
175
175
  verify_commands if commands.any?
176
176
  end
177
177
 
178
+ # Returns an array of all the args with a whitelist
179
+ def whitelisted_args
180
+ args.select &:allowed
181
+ end
182
+
183
+ # Returns an array of all the flags with a whitelist arg
184
+ def whitelisted_flags
185
+ flags.select &:allowed
186
+ end
187
+
178
188
  private
179
189
 
180
190
  def verify_commands
@@ -11,6 +11,10 @@ module Bashly
11
11
  end
12
12
  end
13
13
 
14
+ def name
15
+ long || short
16
+ end
17
+
14
18
  def usage_string(extended: false)
15
19
  result = [aliases.join(", ")]
16
20
  result << arg.upcase if arg
@@ -0,0 +1,33 @@
1
+ module Bashly
2
+ module Models
3
+ class Script
4
+ include Renderable
5
+
6
+ attr_reader :command, :function_name
7
+
8
+ def initialize(command, function_name = nil)
9
+ @command, @function_name = command, function_name
10
+ end
11
+
12
+ def code
13
+ if function_name
14
+ result = [header, render('wrapper')].join "\n"
15
+ else
16
+ result = [header, body].join "\n"
17
+ end
18
+
19
+ result.lint
20
+ end
21
+
22
+ private
23
+
24
+ def header
25
+ @header ||= render('header')
26
+ end
27
+
28
+ def body
29
+ @body ||= command.render('master_script')
30
+ end
31
+ end
32
+ end
33
+ end
@@ -21,7 +21,7 @@ config_init() {
21
21
  # Usage: result=$(config_get hello)
22
22
  config_get() {
23
23
  key=$1
24
- regex="^$key\s*=\s*(.+)$"
24
+ regex="^$key *= *(.+)$"
25
25
 
26
26
  config_init
27
27
 
@@ -44,7 +44,7 @@ config_set() {
44
44
 
45
45
  config_init
46
46
 
47
- regex="^($key)\s*=\s*.+$"
47
+ regex="^($key) *= *.+$"
48
48
  output=""
49
49
  found_key=""
50
50
 
@@ -71,7 +71,7 @@ config_set() {
71
71
  config_del() {
72
72
  key=$1
73
73
 
74
- regex="^($key)\s*="
74
+ regex="^($key) *="
75
75
  output=""
76
76
 
77
77
  config_init
@@ -100,7 +100,7 @@ config_show() {
100
100
  # done
101
101
  #
102
102
  config_keys() {
103
- regex="^(.*)\s*="
103
+ regex="^([a-zA-Z0-9_\-\/\.]+) *="
104
104
 
105
105
  config_init
106
106
 
@@ -113,3 +113,14 @@ config_keys() {
113
113
  done < "$CONFIG_FILE"
114
114
  echo "${keys[@]}"
115
115
  }
116
+
117
+ # Returns true if the specified key exists in the config file
118
+ # Usage:
119
+ #
120
+ # if config_has_key "key" ; then
121
+ # echo "key exists"
122
+ # fi
123
+ #
124
+ config_has_key() {
125
+ [[ $(config_get "$1") ]]
126
+ }
@@ -15,16 +15,19 @@ command_shortcut: "Shortcut: %{short}"
15
15
  default_command_summary: "%{summary} (default)"
16
16
  required: "(required)"
17
17
  default: "Default: %{value}"
18
+ allowed: "Allowed: %{values}"
18
19
 
19
20
  # Fixed flags help text
20
21
  help_flag_text: Show this help
21
22
  version_flag_text: Show version number
22
23
 
23
24
  # Error messages
24
- flag_requires_an_argument: "%{long} requires an argument: %{usage}"
25
+ flag_requires_an_argument: "%{name} requires an argument: %{usage}"
25
26
  invalid_argument: "invalid argument: %s"
26
27
  invalid_flag: "invalid option: %s"
27
28
  missing_required_argument: "missing required argument: %{arg}\\nusage: %{usage}"
28
29
  missing_required_flag: "missing required flag: %{usage}"
29
30
  missing_required_environment_variable: "missing required environment variable: %{var}"
30
31
  missing_dependency: "missing dependency: %{dependency}"
32
+ disallowed_flag: "%{name} must be one of: %{allowed}"
33
+ disallowed_argument: "%{name} must be one of: %{allowed}"
@@ -1,3 +1,3 @@
1
1
  module Bashly
2
- VERSION = "0.3.8"
2
+ VERSION = "0.4.2"
3
3
  end
@@ -1,6 +1,9 @@
1
1
  # :argument.usage
2
2
  echo " <%= name.upcase %>"
3
3
  printf "<%= help.wrap(76).indent(4).sanitize_for_print %>\n"
4
+ <%- if allowed -%>
5
+ printf " <%= strings[:allowed] % { values: allowed.join(', ') } -%>\n"
6
+ <%- end -%>
4
7
  <%- if default -%>
5
8
  printf " <%= strings[:default] % { value: default } -%>\n"
6
9
  <%- end -%>
@@ -1,5 +1,10 @@
1
1
  # :command.inspect_args
2
2
  inspect_args() {
3
- echo args:
4
- for k in "${!args[@]}"; do echo "- \${args[$k]} = ${args[$k]}"; done
3
+ readarray -t sorted_keys < <(printf '%s\n' "${!args[@]}" | sort)
4
+ if (( ${#args[@]} )); then
5
+ echo args:
6
+ for k in "${sorted_keys[@]}"; do echo "- \${args[$k]} = ${args[$k]}"; done
7
+ else
8
+ echo args: none
9
+ fi
5
10
  }
@@ -1,7 +1,3 @@
1
- #!/usr/bin/env bash
2
- # This script was generated by bashly (https://github.com/DannyBen/bashly)
3
- # Modifying it manually is not recommended
4
-
5
1
  <%= render :root_command if commands.empty? %>
6
2
  <%= render :version_command %>
7
3
  <%= render :usage %>
@@ -12,6 +12,7 @@ parse_requirements() {
12
12
  <%= render(:required_flags_filter).indent 2 %>
13
13
  <%= render(:parse_requirements_while).indent 2 %>
14
14
  <%= render(:default_assignments).indent 2 %>
15
+ <%= render(:whitelist_filter).indent 2 %>
15
16
  }
16
17
 
17
18
  <%- commands.each do |command| %>
@@ -14,12 +14,7 @@ run() {
14
14
  fi
15
15
  <% condition = "elif" %>
16
16
  <%- end -%>
17
- <%= condition %> [[ ${args[--version]} ]]; then
18
- version_command
19
- elif [[ ${args[--help]} ]]; then
20
- long_usage=yes
21
- <%= name %>_usage
22
- elif [[ $action == "root" ]]; then
17
+ <%= condition %> [[ $action == "root" ]]; then
23
18
  root_command
24
19
  fi
25
20
  }
@@ -0,0 +1,13 @@
1
+ # :command.whitelist_filter
2
+ <%- whitelisted_args.each do |arg| -%>
3
+ if [[ ! ${args[<%= arg.name %>]} =~ ^(<%= arg.allowed.join '|' %>)$ ]]; then
4
+ printf "%s\n" "<%= strings[:disallowed_argument] % { name: arg.name, allowed: arg.allowed.join(', ') } %>"
5
+ exit 1
6
+ fi
7
+ <%- end -%>
8
+ <%- whitelisted_flags.each do |flag| -%>
9
+ if [[ ! ${args[<%= flag.name %>]} =~ ^(<%= flag.allowed.join '|' %>)$ ]]; then
10
+ printf "%s\n" "<%= strings[:disallowed_flag] % { name: flag.name, allowed: flag.allowed.join(', ') } %>"
11
+ exit 1
12
+ fi
13
+ <%- end -%>
@@ -1,16 +1,16 @@
1
1
  # :flag.case
2
2
  <%= aliases.join " | " %> )
3
3
  <%- if arg -%>
4
- if [[ $2 && $2 != -* ]]; then
5
- args[<%= long %>]="$2"
4
+ if [[ $2 ]]; then
5
+ args[<%= name %>]="$2"
6
6
  shift
7
7
  shift
8
8
  else
9
- printf "%s\n" "<%= strings[:flag_requires_an_argument] % { long: long, usage: usage_string } %>"
9
+ printf "%s\n" "<%= strings[:flag_requires_an_argument] % { name: name, usage: usage_string } %>"
10
10
  exit 1
11
11
  fi
12
12
  <%- else -%>
13
- args[<%= long %>]=1
13
+ args[<%= name %>]=1
14
14
  shift
15
15
  <%- end -%>
16
16
  ;;
@@ -1,6 +1,9 @@
1
1
  # :flag.usage
2
2
  echo " <%= usage_string extended: true %>"
3
3
  printf "<%= help.wrap(76).indent(4).sanitize_for_print %>\n"
4
+ <%- if allowed -%>
5
+ printf " <%= strings[:allowed] % { values: allowed.join(', ') } -%>\n"
6
+ <%- end -%>
4
7
  <%- if default -%>
5
8
  printf " <%= strings[:default] % { value: default } -%>\n"
6
9
  <%- end -%>
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env bash
2
+ # This script was generated by bashly (https://github.com/DannyBen/bashly)
3
+ # Modifying it manually is not recommended
@@ -0,0 +1,6 @@
1
+ # :script.wrapper
2
+ <%= function_name %>() {
3
+ <%= body.indent 2 %>
4
+ }
5
+
6
+ (return 0 2>/dev/null) || <%= function_name %> "$@"
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.3.8
4
+ version: 0.4.2
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: 2020-03-02 00:00:00.000000000 Z
11
+ date: 2021-03-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colsole
@@ -80,6 +80,7 @@ files:
80
80
  - lib/bashly/models/command.rb
81
81
  - lib/bashly/models/environment_variable.rb
82
82
  - lib/bashly/models/flag.rb
83
+ - lib/bashly/models/script.rb
83
84
  - lib/bashly/polyfills/hash.rb
84
85
  - lib/bashly/settings.rb
85
86
  - lib/bashly/templates/bashly.yml
@@ -120,9 +121,12 @@ files:
120
121
  - lib/bashly/views/command/usage_flags.erb
121
122
  - lib/bashly/views/command/user_lib.erb
122
123
  - lib/bashly/views/command/version_command.erb
124
+ - lib/bashly/views/command/whitelist_filter.erb
123
125
  - lib/bashly/views/environment_variable/usage.erb
124
126
  - lib/bashly/views/flag/case.erb
125
127
  - lib/bashly/views/flag/usage.erb
128
+ - lib/bashly/views/script/header.erb
129
+ - lib/bashly/views/script/wrapper.erb
126
130
  homepage: https://github.com/dannyben/bashly
127
131
  licenses:
128
132
  - MIT
@@ -142,7 +146,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
142
146
  - !ruby/object:Gem::Version
143
147
  version: '0'
144
148
  requirements: []
145
- rubygems_version: 3.0.3
149
+ rubygems_version: 3.2.3
146
150
  signing_key:
147
151
  specification_version: 4
148
152
  summary: Bash Command Line Tool Generator