bashly 0.3.8 → 0.4.2

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 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