bashly 0.5.1 → 0.6.0

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: ca34648c628c4e7fe167d5f5b0d253792e9b4d3c494b253ed68d0127e4935572
4
- data.tar.gz: 5247da7780a8424dd0a808ace6d182ed4284597e094122d94a8716bfca8f343b
3
+ metadata.gz: 7fe733a46c8634cc39b4c792b177ca9ac7610a8d408714fa482b3c0ad15fc10f
4
+ data.tar.gz: 908960de1cb2d682ff801630e0f6667a42df171612ed6a92aee72bcc369cc0e2
5
5
  SHA512:
6
- metadata.gz: 2145d1f4125d762c3d583f560c4caa9f4b98cfc2500e7e7b9ac977f4284a190a150a26da6e935c4e59c689f5efcd627924a10091cff0d4d91f00c3f60d26b943
7
- data.tar.gz: 9df4695f43e4c57371f876de1dee3eab587bb227b7b0ee51d52d1772faf119cbd59cb117f5a1e3cbb06ef49b5796cd02b6fecba685b733aa35c51442fe9baf19
6
+ metadata.gz: 9e0dcf39faf63d5d798fac7ed41768994ec6715a58b898e390ec2a6019948497d314c08bc8ce1041fb5f1a105884a04d759e258085fdcf7fbbe87af1c4a7a4e0
7
+ data.tar.gz: 83279b0a7df6eb6f3c2a779bbc54221e9cad58e6e08c4a207f1d592aa12329cc488d7169b682191be02474f098dbfda0f3d6ad6cd03e3a91e1bf793bb29fcdc3
data/README.md CHANGED
@@ -31,6 +31,7 @@ Create beautiful bash scripts from simple YAML configuration
31
31
  - [Flag options](#flag-options)
32
32
  - [Environment Variable options](#environment-variable-options)
33
33
  - [Extensible Scripts](#extensible-scripts)
34
+ - [Bash Completions](#bash-completions)
34
35
  - [Real World Examples](#real-world-examples)
35
36
  - [Contributing / Support](#contributing--support)
36
37
 
@@ -75,6 +76,7 @@ Bahsly is responsible for:
75
76
  - Optional or required **option flags** (with or without flag arguments).
76
77
  - **Commands** (and subcommands).
77
78
  - Standard flags (like **--help** and **--version**).
79
+ - Preventing your script from running unless the command line is valid.
78
80
  - Providing you with a place to input your code for each of the functions
79
81
  your tool performs, and merging it back to the final script.
80
82
  - Providing you with additional (optional) framework-style, standard
@@ -82,6 +84,7 @@ Bahsly is responsible for:
82
84
  - **Color output**.
83
85
  - **Config file management** (INI format).
84
86
  - **YAML parsing**.
87
+ - **Bash completions**.
85
88
  - and more.
86
89
 
87
90
 
@@ -198,6 +201,7 @@ command and subcommands (under the `commands` definition).
198
201
  `commands` | Specify the array of [commands](#command-options). Each command will have its own args and flags. Note: if `commands` is provided, you cannot specify flags or args at the same level.
199
202
  `args` | Specify the array of [positional arguments](#argument-options) this script needs.
200
203
  `flags` | Specify the array of option [flags](#flag-options) this script needs.
204
+ `completions` | Specify an array of additional completion suggestions when used in conjunction with `bashly add comp`. See [Bash Completions](#bash-completions).
201
205
  `catch_all` | Specify that this command should allow for additional arbitrary arguments or flags. It can be set in one of three ways:<br>- Set to `true` to just enable it.<br>- Set to a string, to use this string in the usage help text.<br>- Set to a hash containing `label` and `help` keys, to show a detailed help for it when running with `--help`.
202
206
  `dependencies` | Specify an array of any required external dependencies (commands). The script execution will be halted with a friendly error unless all dependency commands exist.
203
207
  `group` | In case you have many commands, use this option to specify a caption to display before this command. This option is purely for display purposes, and needs to be specified only for the first command in each group.
@@ -263,7 +267,7 @@ command will look for a file named `git-whatever` in the path, and execute it.
263
267
  Note that this option cannot be specified together with the `default` option,
264
268
  since both specify a handler for unknown commands.
265
269
 
266
- Bashly supports two operation modes.
270
+ The `extensible` option supports two operation modes:
267
271
 
268
272
  ### Extension Mode (`extensible: true`)
269
273
 
@@ -326,6 +330,71 @@ The generated script will execute `git status`.
326
330
  See the [extensible-delegate example](examples/extensible-delegate).
327
331
 
328
332
 
333
+ ## Bash Completions
334
+
335
+ Bashly comes with built-in bash completions generator, provided by the
336
+ [completely][completely] gem.
337
+
338
+ By running any of the `bashly add comp` commands, you can add this
339
+ functionality to your script in one of three ways:
340
+
341
+ - `bashly add comp function` - creates a function in your `./src/lib` directory
342
+ that echoes a completion script. You can then call this function from any
343
+ command (for example `yourcli completions`) and your users will be able to
344
+ install the completions by running `eval "$(yourcli completions)"`.
345
+ - `bashly add comp script` - creates a standalone completion script that can be
346
+ sourced or copies to the system's bash completions directory.
347
+ - `bashly add comp yaml` - creates the "raw data" YAML file. This is intended
348
+ mainly for development purposes.
349
+
350
+ The bash completions generation is completely automatic, and you will have to
351
+ rerun the `bashly add comp *` command whenever you change your `bashly.yml`
352
+ script.
353
+
354
+ In addition to suggesting subcommands and flags, you can instruct bashly to
355
+ also suggest files, directories, users and more. To do this, add another option
356
+ in your `bashly.yml` on the command you wish to alter:
357
+
358
+ ```yaml
359
+ # bashly.yml
360
+ commands:
361
+ - name: upload
362
+ help: Upload a file
363
+ completions: [directory, user]
364
+
365
+ ```
366
+
367
+ Valid completion additions are:
368
+
369
+ | Keyword | Meaning
370
+ |-------------|---------------------
371
+ | `alias` | Alias names
372
+ | `arrayvar` | Array variable names
373
+ | `binding` | Readline key binding names
374
+ | `builtin` | Names of shell builtin commands
375
+ | `command` | Command names
376
+ | `directory` | Directory names
377
+ | `disabled` | Names of disabled shell builtins
378
+ | `enabled` | Names of enabled shell builtins
379
+ | `export` | Names of exported shell variables
380
+ | `file` | File names
381
+ | `function` | Names of shell functions
382
+ | `group` | Group names
383
+ | `helptopic` | Help topics as accepted by the help builtin
384
+ | `hostname` | Hostnames, as taken from the file specified by the HOSTFILE shell variable
385
+ | `job` | Job names
386
+ | `keyword` | Shell reserved words
387
+ | `running` | Names of running jobs
388
+ | `service` | Service names
389
+ | `signal` | Signal names
390
+ | `stopped` | Names of stopped jobs
391
+ | `user` | User names
392
+ | `variable` | Names of all shell variables
393
+
394
+ Note that these are taken from the [Programmable Completion Builtin][compgen],
395
+ and will simply be added using the `compgen -A action` command.
396
+
397
+
329
398
  ## Real World Examples
330
399
 
331
400
  - [Rush][rush] - a Personal Package Manager
@@ -344,3 +413,5 @@ to contribute, feel free to [open an issue][issues].
344
413
  [rush]: https://github.com/DannyBen/rush-cli
345
414
  [alf]: https://github.com/DannyBen/alf
346
415
  [git-changelog]: https://github.com/DannyBen/git-changelog
416
+ [completely]: https://github.com/DannyBen/completely
417
+ [compgen]: https://www.gnu.org/software/bash/manual/html_node/Programmable-Completion-Builtins.html
@@ -8,15 +8,24 @@ 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 comp FORMAT [OUTPUT]"
11
12
  usage "bashly add (-h|--help)"
12
13
 
13
14
  option "-f --force", "Overwrite existing files"
14
15
 
16
+ param "FORMAT", "Output format, can be one of:\n function : generate a function file to be included in your script.\n script : generate a standalone bash completions script\n yaml : generate a yaml compatible with 'completely'"
17
+ param "OUTPUT", "For the 'comp function' command: Name of the generated function.\nFor the 'comp script' or 'comp yaml' commands: path to output file.\nIn all cases, this is optional and will have sensible defaults."
18
+
15
19
  command "strings", "Copy an additional configuration file to your project, allowing you to customize all the tips and error strings."
16
20
  command "lib", "Create the additional lib directory for additional user scripts. All *.sh scripts in this folder will be included in the final bash script."
17
21
  command "config", "Add standard functions for handling INI files to the lib directory."
18
22
  command "colors", "Add standard functions for printing colorful and formatted text to the lib directory."
19
23
  command "yaml", "Add standard functions for reading YAML files to the lib directory."
24
+ command "comp", "Generate a bash completions script or function."
25
+
26
+ example "bashly add strings --force"
27
+ example "bashly add comp function"
28
+ example "bashly add comp script completions.bash"
20
29
 
21
30
  environment "BASHLY_SOURCE_DIR", "The path containing the bashly configuration and source files [default: src]"
22
31
 
@@ -40,7 +49,25 @@ module Bashly
40
49
  safe_copy_lib "yaml.sh"
41
50
  end
42
51
 
52
+ def comp_command
53
+ format = args['FORMAT']
54
+ output = args['OUTPUT']
55
+
56
+ case format
57
+ when "function"
58
+ save_comp_function output
59
+ when "yaml"
60
+ save_comp_yaml output
61
+ when "script"
62
+ save_comp_script output
63
+ else
64
+ raise Error, "Unrecognized format: #{format}"
65
+ end
66
+
67
+ end
68
+
43
69
  private
70
+
44
71
  def safe_copy_lib(libfile)
45
72
  safe_copy asset("templates/lib/#{libfile}"), "#{Settings.source_dir}/lib/#{libfile}"
46
73
  end
@@ -63,6 +90,61 @@ module Bashly
63
90
  FileUtils.mkdir_p target_dir unless Dir.exist? target_dir
64
91
  FileUtils.cp source, target
65
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"
136
+
137
+ FileUtils.mkdir_p target_dir unless Dir.exist? target_dir
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)\""
146
+ end
147
+
66
148
  end
67
149
  end
68
150
  end
@@ -0,0 +1,50 @@
1
+ require 'completely'
2
+
3
+ module Bashly
4
+ # This is a `Command` concern responsible for providing bash completion data
5
+ module Completions
6
+ def completion_data(with_version: true)
7
+ result = { full_name => completion_words(with_version: with_version) }
8
+
9
+ commands.each do |command|
10
+ result.merge! command.completion_data(with_version: false)
11
+ end
12
+
13
+ result
14
+ end
15
+
16
+ def completion_script
17
+ completion_generator.script
18
+ end
19
+
20
+ def completion_function(name = nil)
21
+ completion_generator.wrapper_function(name)
22
+ end
23
+
24
+ private
25
+
26
+ def completion_generator
27
+ Completely::Completions.new(completion_data)
28
+ end
29
+
30
+ def completion_flag_names
31
+ flags.map(&:name) + flags.map(&:short)
32
+ end
33
+
34
+ def completion_actions
35
+ completions ? completions.map { |c| "<#{c}>" } : []
36
+ end
37
+
38
+ def completion_words(with_version: false)
39
+ trivial_flags = %w[--help -h]
40
+ trivial_flags += %w[--version -v] if with_version
41
+ all = (
42
+ command_names + trivial_flags +
43
+ completion_flag_names + completion_actions
44
+ )
45
+
46
+ all.compact.uniq.sort
47
+ end
48
+
49
+ end
50
+ end
@@ -4,10 +4,7 @@ module Bashly
4
4
  module Renderable
5
5
  def render(view)
6
6
  template = File.read view_path(view)
7
- # TODO: This new format is only supported in Ruby >= 2.6
8
- # So for now, we keep the old deprecated syntax
9
- # ERB.new(template, trim_mode: '%-').result(binding)
10
- ERB.new(template, nil, '%-').result(binding)
7
+ ERB.new(template, trim_mode: '%-').result(binding)
11
8
  end
12
9
 
13
10
  def strings
@@ -9,6 +9,7 @@ module Bashly
9
9
  allowed
10
10
  arg
11
11
  catch_all
12
+ completions
12
13
  default
13
14
  dependencies
14
15
  description
@@ -1,6 +1,8 @@
1
1
  module Bashly
2
2
  module Models
3
3
  class Command < Base
4
+ include Completions
5
+
4
6
  # Returns the name to be used as an action.
5
7
  # - If it is the root command, the action is "root"
6
8
  # - Else, it is all the parents, except the first tone (root) joined
@@ -1,3 +1,3 @@
1
1
  module Bashly
2
- VERSION = "0.5.1"
2
+ VERSION = "0.6.0"
3
3
  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.5.1
4
+ version: 0.6.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-07-02 00:00:00.000000000 Z
11
+ date: 2021-07-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colsole
@@ -24,6 +24,26 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: completely
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.1'
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: 0.1.2
37
+ type: :runtime
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - "~>"
42
+ - !ruby/object:Gem::Version
43
+ version: '0.1'
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: 0.1.2
27
47
  - !ruby/object:Gem::Dependency
28
48
  name: mister_bin
29
49
  requirement: !ruby/object:Gem::Requirement
@@ -69,6 +89,7 @@ files:
69
89
  - lib/bashly/commands/init.rb
70
90
  - lib/bashly/commands/preview.rb
71
91
  - lib/bashly/concerns/asset_helper.rb
92
+ - lib/bashly/concerns/completions.rb
72
93
  - lib/bashly/concerns/renderable.rb
73
94
  - lib/bashly/config.rb
74
95
  - lib/bashly/exceptions.rb
@@ -141,7 +162,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
141
162
  requirements:
142
163
  - - ">="
143
164
  - !ruby/object:Gem::Version
144
- version: 2.3.0
165
+ version: 2.7.0
145
166
  required_rubygems_version: !ruby/object:Gem::Requirement
146
167
  requirements:
147
168
  - - ">="