bashly 1.3.6 → 1.3.8

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: c216518e1752d66966dfa1b8efad9a24afb5d55119a350ac9ad460abea748be0
4
- data.tar.gz: 8626f99cfc41d424363969bbe46474fc86f8998f44c17d8196c03044281fbf6e
3
+ metadata.gz: 411dc6262c3232175e5a968a31ad90b56aa59be9d9b46203c3eb2db14f35d491
4
+ data.tar.gz: 2ce20d069c93e1e7081984ff1fb2dd9c7bca530d6fbf127e0bb1c996c0117cc1
5
5
  SHA512:
6
- metadata.gz: 7b49310fec1d05dcf12504a8be34493d4e6d8af7ef9b2e35ea57da6424ca0820ee6abb7145ea54835ac31778db0ff89e6c6999050133f5851545ac67dc7f5b6c
7
- data.tar.gz: 0b443ed8497671ff9faf2c720961d3344a5bbfb670096c9a74388cb54541f782b4316a198e4b2dfc7ed17b45a83991df2894ce05f3d76f943f694a63aa090bb2
6
+ metadata.gz: 3bff0a363b5c52c0f54b2b1e413b909256579c0b29ef8a44e88cd73b1803c584c3de26af99fa737edac8cc103a218f418a7a5f463e38b27c416ebf26bbcfe8ef
7
+ data.tar.gz: 2691947ed69d6f693625be4ba66a1b9803d01e46f50768d266c5f0f27c60f74242977fb91131443f6bd29161a9810970b542ecef3d3be0e9b3a84641da8dc080
data/README.md CHANGED
@@ -13,6 +13,8 @@ Create feature-rich bash scripts using simple YAML configuration
13
13
 
14
14
  </div>
15
15
 
16
+ ![repocard](https://repocard.dannyben.com/svg/bashly.svg)
17
+
16
18
  Bashly is a command line application (written in Ruby) that lets you
17
19
  generate feature-rich bash command line tools.
18
20
 
@@ -193,6 +193,7 @@ module Bashly
193
193
  assert_optional_string "#{key}.group", value['group']
194
194
  assert_optional_string "#{key}.filename", value['filename']
195
195
  assert_optional_string "#{key}.function", value['function']
196
+ assert_optional_string "#{key}.argfile", value['argfile']
196
197
 
197
198
  assert_boolean "#{key}.private", value['private']
198
199
  assert_default_command "#{key}.default", value['default']
@@ -42,6 +42,7 @@ white() { print_in_color "\e[37m" "$*"; }
42
42
 
43
43
  bold() { print_in_color "\e[1m" "$*"; }
44
44
  underlined() { print_in_color "\e[4m" "$*"; }
45
+ bold_underlined() { print_in_color "\e[1;4m" "$*"; }
45
46
 
46
47
  red_bold() { print_in_color "\e[1;31m" "$*"; }
47
48
  green_bold() { print_in_color "\e[1;32m" "$*"; }
@@ -47,7 +47,7 @@ ini_load() {
47
47
  elif [[ $line =~ $key_regex ]]; then
48
48
  key="${BASH_REMATCH[1]}"
49
49
  value="${BASH_REMATCH[2]}"
50
- [[ $value == *\$* ]] && eval "value=\"$value\""
50
+ [[ $value == *\$* ]] && value=$(envsubst <<<"$value")
51
51
  ini["${section}${key}"]="$value"
52
52
  fi
53
53
  done <"$ini_file"
@@ -121,21 +121,6 @@ strings:
121
121
  - source: "strings/strings.yml"
122
122
  target: "%{user_source_dir}/bashly-strings.yml"
123
123
 
124
- test:
125
- help: Add approval testing.
126
- files:
127
- - source: "test/approvals.bash"
128
- target: "%{user_target_dir}/test/approvals.bash"
129
- - source: "test/approve"
130
- target: "%{user_target_dir}/test/approve"
131
-
132
- post_install_message: |
133
- Edit your tests in g`test/approve` and then run:
134
-
135
- m`$ test/approve`
136
-
137
- Docs: bu`https://github.com/DannyBen/approvals.bash`
138
-
139
124
  validations:
140
125
  help: Add argument validation functions to the lib directory.
141
126
  files:
@@ -120,6 +120,12 @@ show_examples_on_error: false
120
120
  # all the private elements in the usage texts, as if they were public.
121
121
  private_reveal_key: ~
122
122
 
123
+ # When enabling argfile for any command, this setting controls the name of the
124
+ # environment variable that can override or disable argfile loading at runtime.
125
+ # Set the variable to `0`, `off`, `no` or `false` to disable argfile loading,
126
+ # or to a different path to load another argfile instead.
127
+ argfile_var: ARGFILE
128
+
123
129
  # Display various usage elements in color by providing the name of the color
124
130
  # function. The value for each property is a name of a function that is
125
131
  # available in your script, for example: `green` or `bold`.
@@ -159,6 +165,17 @@ enable_env_var_names_array: always
159
165
  enable_sourcing: development
160
166
 
161
167
 
168
+ #-------------------------------------------------------------------------------
169
+ # DEVELOPER OPTIONS
170
+ #-------------------------------------------------------------------------------
171
+
172
+ # When true, use filesystem evented watching instead of polling
173
+ watch_evented: false
174
+
175
+ # File change detection latency (seconds)
176
+ watch_latency: 1.0
177
+
178
+
162
179
  #-------------------------------------------------------------------------------
163
180
  # SCRIPTING OPTIONS
164
181
  #-------------------------------------------------------------------------------
@@ -14,7 +14,7 @@ module Bashly
14
14
  class << self
15
15
  def option_keys
16
16
  @option_keys ||= %i[
17
- alias args catch_all commands completions
17
+ alias argfile args catch_all commands completions
18
18
  default dependencies environment_variables examples
19
19
  extensible expose filename filters flags
20
20
  footer function group help help_header_override name
@@ -4,6 +4,7 @@ module Bashly
4
4
  include AssetHelper
5
5
 
6
6
  attr_writer(
7
+ :argfile_var,
7
8
  :commands_dir,
8
9
  :compact_short_flags,
9
10
  :conjoined_flag_args,
@@ -28,9 +29,19 @@ module Bashly
28
29
  :target_dir,
29
30
  :usage_colors,
30
31
  :var_aliases,
32
+ :watch_evented,
33
+ :watch_latency,
31
34
  :word_wrap
32
35
  )
33
36
 
37
+ def all_lib_dirs
38
+ @all_lib_dirs = [full_lib_dir] + extra_lib_dirs
39
+ end
40
+
41
+ def argfile_var
42
+ @argfile_var ||= get :argfile_var
43
+ end
44
+
34
45
  def commands_dir
35
46
  @commands_dir ||= get :commands_dir
36
47
  end
@@ -89,6 +100,17 @@ module Bashly
89
100
  @env = value&.to_sym
90
101
  end
91
102
 
103
+ def extra_lib_dirs
104
+ @extra_lib_dirs ||= begin
105
+ dirs = get :extra_lib_dirs
106
+ case dirs
107
+ when Array then dirs
108
+ when String then dirs.split(',').map(&:strip)
109
+ else []
110
+ end
111
+ end
112
+ end
113
+
92
114
  def formatter
93
115
  @formatter ||= get :formatter
94
116
  end
@@ -109,21 +131,6 @@ module Bashly
109
131
  @lib_dir ||= get :lib_dir
110
132
  end
111
133
 
112
- def extra_lib_dirs
113
- @extra_lib_dirs ||= begin
114
- dirs = get :extra_lib_dirs
115
- case dirs
116
- when Array then dirs
117
- when String then dirs.split(',').map(&:strip)
118
- else []
119
- end
120
- end
121
- end
122
-
123
- def all_lib_dirs
124
- @all_lib_dirs = [full_lib_dir] + extra_lib_dirs
125
- end
126
-
127
134
  def partials_extension
128
135
  @partials_extension ||= get :partials_extension
129
136
  end
@@ -174,6 +181,14 @@ module Bashly
174
181
  @var_aliases ||= get :var_aliases
175
182
  end
176
183
 
184
+ def watch_evented
185
+ @watch_evented ||= get :watch_evented
186
+ end
187
+
188
+ def watch_latency
189
+ @watch_latency ||= get :watch_latency
190
+ end
191
+
177
192
  def word_wrap
178
193
  @word_wrap ||= get :word_wrap
179
194
  end
@@ -1,3 +1,3 @@
1
1
  module Bashly
2
- VERSION = '1.3.6'
2
+ VERSION = '1.3.8'
3
3
  end
@@ -0,0 +1,29 @@
1
+ = view_marker
2
+
3
+ > local argfile argfile_line argfile_key argfile_value env_argfile env_argfile_var
4
+ > argfile="{{ argfile }}"
5
+ > env_argfile_var="{{ Settings.argfile_var }}"
6
+ > env_argfile="${!env_argfile_var:-}"
7
+ >
8
+ > case "${env_argfile,,}" in
9
+ > 0 | off | no | false)
10
+ > argfile=''
11
+ > ;;
12
+ > esac
13
+ >
14
+ > [[ -n "$env_argfile" ]] && argfile="$env_argfile"
15
+ > if [[ -f "$argfile" ]]; then
16
+ > while IFS= read -r argfile_line || [[ -n "$argfile_line" ]]; do
17
+ > [[ "$argfile_line" =~ ^[[:space:]]*(-{1,2}[^[:space:]]+)([[:space:]]+(.+))?[[:space:]]*$ ]] || continue
18
+ > argfile_key="${BASH_REMATCH[1]}"
19
+ > argfile_value="${BASH_REMATCH[3]:-}"
20
+ > argfile_value="${argfile_value#"${argfile_value%%[![:space:]]*}"}"
21
+ > argfile_value="${argfile_value%"${argfile_value##*[![:space:]]}"}"
22
+ > [[ "$argfile_value" =~ ^\"(.*)\"$ || "$argfile_value" =~ ^\'(.*)\'$ ]] && argfile_value="${BASH_REMATCH[1]}"
23
+ >
24
+ > case "$argfile_key" in
25
+ = flags.map { |flag| flag.render(:argfile_case) }.join.indent 6
26
+ > esac
27
+ > done <"$argfile"
28
+ > fi
29
+ >
@@ -9,6 +9,7 @@ end
9
9
  >
10
10
 
11
11
  = render(:fixed_flags_filter).indent 2
12
+ = render(:argfile_filter).indent 2 if argfile
12
13
  = render(:environment_variables_filter).indent 2
13
14
  = render(:dependencies_filter).indent 2
14
15
  = render(:command_filter).indent 2
@@ -0,0 +1,6 @@
1
+ = view_marker
2
+
3
+ > {{ aliases.join " | " }})
4
+ = render(arg ? :argfile_case_arg : :argfile_case_no_arg).indent 2
5
+ > ;;
6
+ >
@@ -0,0 +1,23 @@
1
+ = view_marker
2
+
3
+ > if [[ -n "$argfile_value" ]]; then
4
+
5
+ if repeatable
6
+ > escaped="$(printf '%q' "$argfile_value")"
7
+ > if [[ -z ${args['{{ name }}']+x} ]]; then
8
+ > args['{{ name }}']="$escaped"
9
+ if unique
10
+ > unique_lookup["{{ name }}:$escaped"]=1
11
+ > elif [[ -z "${unique_lookup["{{ name }}:$escaped"]:-}" ]]; then
12
+ > args['{{ name }}']="${args['{{ name }}']} $escaped"
13
+ > unique_lookup["{{ name }}:$escaped"]=1
14
+ else
15
+ > else
16
+ > args['{{ name }}']="${args['{{ name }}']} $escaped"
17
+ end
18
+ > fi
19
+ else
20
+ > [[ -n ${args['{{ name }}']+x} ]] || args['{{ name }}']="$argfile_value"
21
+ end
22
+
23
+ > fi
@@ -0,0 +1,7 @@
1
+ = view_marker
2
+
3
+ if repeatable
4
+ > ((args['{{ name }}'] += 1))
5
+ else
6
+ > [[ -n ${args['{{ name }}']+x} ]] || args['{{ name }}']=1
7
+ end
data/lib/bashly/watch.rb CHANGED
@@ -5,13 +5,8 @@ module Bashly
5
5
  class Watch
6
6
  attr_reader :dirs, :options
7
7
 
8
- DEFAULT_OPTIONS = {
9
- force_polling: true,
10
- latency: 1.0,
11
- }.freeze
12
-
13
8
  def initialize(*dirs, **options)
14
- @options = DEFAULT_OPTIONS.merge(options).freeze
9
+ @options = default_options.merge(options).freeze
15
10
  @dirs = dirs.empty? ? ['.'] : dirs
16
11
  end
17
12
 
@@ -24,10 +19,20 @@ module Bashly
24
19
 
25
20
  private
26
21
 
27
- def build_listener
28
- listen.to(*dirs, **options) do |modified, added, removed|
29
- yield changes(modified, added, removed)
30
- end
22
+ def default_options
23
+ {
24
+ force_polling: force_polling?,
25
+ latency: latency,
26
+ }
27
+ end
28
+
29
+ def force_polling?
30
+ !Settings.watch_evented
31
+ end
32
+
33
+ def latency
34
+ value = Settings.watch_latency.to_f
35
+ value.positive? ? value : 0.1
31
36
  end
32
37
 
33
38
  def start(&block)
@@ -42,16 +47,22 @@ module Bashly
42
47
  @listener = nil
43
48
  end
44
49
 
45
- def changes(modified, added, removed)
46
- { modified:, added:, removed: }
47
- end
48
-
49
50
  def wait
50
51
  sleep
51
52
  rescue ::Interrupt => e
52
53
  raise Bashly::Interrupt, cause: e
53
54
  end
54
55
 
56
+ def build_listener
57
+ listen.to(*dirs, **options) do |modified, added, removed|
58
+ yield changes(modified, added, removed)
59
+ end
60
+ end
61
+
62
+ def changes(modified, added, removed)
63
+ { modified:, added:, removed: }
64
+ end
65
+
55
66
  def listen = Listen
56
67
  end
57
68
  end
data/lib/bashly.rb CHANGED
@@ -1,8 +1,3 @@
1
- if ENV['DEBUGGER']
2
- require 'debug'
3
- require 'lp'
4
- end
5
-
6
1
  require 'requires'
7
2
  requires 'bashly/extensions'
8
3
  requires 'bashly/exceptions'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bashly
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.6
4
+ version: 1.3.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Danny Ben Shitrit
@@ -206,8 +206,6 @@ files:
206
206
  - lib/bashly/libraries/settings/settings.yml
207
207
  - lib/bashly/libraries/stacktrace/stacktrace.sh
208
208
  - lib/bashly/libraries/strings/strings.yml
209
- - lib/bashly/libraries/test/approvals.bash
210
- - lib/bashly/libraries/test/approve
211
209
  - lib/bashly/libraries/validations/validate_dir_exists.sh
212
210
  - lib/bashly/libraries/validations/validate_file_exists.sh
213
211
  - lib/bashly/libraries/validations/validate_integer.sh
@@ -248,6 +246,7 @@ files:
248
246
  - lib/bashly/views/argument/case_repeatable.gtx
249
247
  - lib/bashly/views/argument/usage.gtx
250
248
  - lib/bashly/views/argument/validations.gtx
249
+ - lib/bashly/views/command/argfile_filter.gtx
251
250
  - lib/bashly/views/command/catch_all_filter.gtx
252
251
  - lib/bashly/views/command/command_fallback.gtx
253
252
  - lib/bashly/views/command/command_filter.gtx
@@ -299,6 +298,9 @@ files:
299
298
  - lib/bashly/views/dependency/filter.gtx
300
299
  - lib/bashly/views/environment_variable/usage.gtx
301
300
  - lib/bashly/views/environment_variable/validations.gtx
301
+ - lib/bashly/views/flag/argfile_case.gtx
302
+ - lib/bashly/views/flag/argfile_case_arg.gtx
303
+ - lib/bashly/views/flag/argfile_case_no_arg.gtx
302
304
  - lib/bashly/views/flag/case.gtx
303
305
  - lib/bashly/views/flag/case_arg.gtx
304
306
  - lib/bashly/views/flag/case_no_arg.gtx
@@ -1,172 +0,0 @@
1
- # approvals.bash v0.5.1
2
- #
3
- # Interactive approval testing for Bash.
4
- # https://github.com/DannyBen/approvals.bash
5
- #
6
- # shellcheck disable=SC2059
7
- # Disabling SC2059 (quoted format string) because we use dynamic format strings
8
- approve() {
9
- local expected approval approval_file actual cmd
10
- approvals_dir=${APPROVALS_DIR:=approvals}
11
-
12
- cmd=$1
13
- last_exit_code=0
14
- actual=$(eval "$cmd" 2>&1) || last_exit_code=$?
15
- if [[ -v allow_diff_regex && "$allow_diff_regex" ]]; then
16
- actual=$(echo "$actual" | sed -E "s/$allow_diff_regex/*/g")
17
- unset allow_diff_regex
18
- fi
19
- approval=$(printf "%b" "$cmd" | tr -s -c "[:alnum:]" _)
20
- approval_file="$approvals_dir/${2:-"$approval"}"
21
-
22
- [[ -d "$approvals_dir" ]] || mkdir "$approvals_dir"
23
-
24
- if [[ -f "$approval_file" ]]; then
25
- expected=$(cat "$approval_file")
26
- else
27
- printf -- "$new_diff_string\n" "$cmd"
28
- printf "%b\n" "$actual"
29
- printf -- "$new_diff_string\n" "$cmd"
30
- expected="$actual"
31
- user_approval "$cmd" "$actual" "$approval_file"
32
- return
33
- fi
34
-
35
- if [[ "$(printf "%b" "$actual")" = "$(printf "%b" "$expected")" ]]; then
36
- pass "$cmd"
37
- else
38
- printf -- "$changed_diff_string\n" "$cmd"
39
- $diff_cmd <(printf "%b" "$expected\n") <(printf "%b" "$actual\n") | tail -n +4
40
- printf -- "$changed_diff_string\n" "$cmd"
41
- user_approval "$cmd" "$actual" "$approval_file"
42
- fi
43
- }
44
-
45
- allow_diff() {
46
- allow_diff_regex="$1"
47
- }
48
-
49
- describe() {
50
- printf "$describe_string\n" "$*"
51
- }
52
-
53
- context() {
54
- printf "$context_string\n" "$*"
55
- }
56
-
57
- it() {
58
- printf "$it_string\n" "$*"
59
- }
60
-
61
- fail() {
62
- printf "$fail_string\n" "$*"
63
- exit 1
64
- }
65
-
66
- pass() {
67
- printf "$pass_string\n" "$*"
68
- return 0
69
- }
70
-
71
- expect_exit_code() {
72
- if [[ $last_exit_code == "$1" ]]; then
73
- pass "exit $last_exit_code"
74
- else
75
- fail "expected exit code $1, got $last_exit_code"
76
- fi
77
- }
78
-
79
- # Private
80
-
81
- print_in_color() {
82
- local color="$1"
83
- shift
84
- if [[ -z ${NO_COLOR+x} ]]; then
85
- printf "$color%b\e[0m\n" "$*"
86
- else
87
- printf "%b\n" "$*"
88
- fi
89
- }
90
-
91
- red() { print_in_color "\e[31m" "$*"; }
92
- green() { print_in_color "\e[32m" "$*"; }
93
- yellow() { print_in_color "\e[33m" "$*"; }
94
- blue() { print_in_color "\e[34m" "$*"; }
95
- magenta() { print_in_color "\e[35m" "$*"; }
96
- cyan() { print_in_color "\e[36m" "$*"; }
97
- bold() { print_in_color "\e[1m" "$*"; }
98
- underlined() { print_in_color "\e[4m" "$*"; }
99
- red_bold() { print_in_color "\e[1;31m" "$*"; }
100
- green_bold() { print_in_color "\e[1;32m" "$*"; }
101
- yellow_bold() { print_in_color "\e[1;33m" "$*"; }
102
- blue_bold() { print_in_color "\e[1;34m" "$*"; }
103
- magenta_bold() { print_in_color "\e[1;35m" "$*"; }
104
- cyan_bold() { print_in_color "\e[1;36m" "$*"; }
105
- red_underlined() { print_in_color "\e[4;31m" "$*"; }
106
- green_underlined() { print_in_color "\e[4;32m" "$*"; }
107
- yellow_underlined() { print_in_color "\e[4;33m" "$*"; }
108
- blue_underlined() { print_in_color "\e[4;34m" "$*"; }
109
- magenta_underlined() { print_in_color "\e[4;35m" "$*"; }
110
- cyan_underlined() { print_in_color "\e[4;36m" "$*"; }
111
-
112
- user_approval() {
113
- local cmd="$1"
114
- local actual="$2"
115
- local approval_file="$3"
116
-
117
- if [[ -v CI || -v GITHUB_ACTIONS ]] && [[ -z "${AUTO_APPROVE+x}" ]]; then
118
- fail "$cmd"
119
- fi
120
-
121
- if [[ -v AUTO_APPROVE ]]; then
122
- response=a
123
- else
124
- echo
125
- printf "$approval_string"
126
- response=$(bash -c "read -n 1 key; echo \$key")
127
- printf "\b%.s" $(seq 1 $((${#approval_string} + 1)))
128
- fi
129
-
130
- if [[ $response =~ [Aa] ]]; then
131
- printf "%b\n" "$actual" >"$approval_file"
132
- pass "$cmd"
133
- else
134
- fail "$cmd"
135
- fi
136
- }
137
-
138
- onexit() {
139
- exitcode=$?
140
- if [[ "$exitcode" == 0 ]]; then
141
- printf "$exit_success_string\n" "$0"
142
- else
143
- printf "$exit_failed_string\n" "$0"
144
- fi
145
- echo
146
- exit $exitcode
147
- }
148
-
149
- onerror() {
150
- fail "caller: $(caller)"
151
- }
152
-
153
- set -e
154
- trap 'onexit' EXIT
155
- trap 'onerror' ERR
156
-
157
- describe_string="$(bold ▌ describe) %s"
158
- context_string="$(bold ▌ context) %s"
159
- it_string="$(bold ▌ it) %s"
160
- fail_string=" $(red_bold failed) %s"
161
- pass_string=" $(green approved) %s"
162
- exit_success_string="$(green ▌ exit) $(bold %s finished successfully)"
163
- exit_failed_string="$(red_bold ▌ exit) $(bold %s finished with errors)"
164
- new_diff_string="────┤ $(yellow new): $(bold %s) ├────"
165
- changed_diff_string="────┤ $(blue changed): $(bold %s) ├────"
166
- approval_string="[A]pprove? "
167
-
168
- if diff --help | grep -- --color >/dev/null 2>&1; then
169
- diff_cmd="diff --unified --color=always"
170
- else
171
- diff_cmd="diff --unified"
172
- fi
@@ -1,25 +0,0 @@
1
- #!/usr/bin/env bash
2
- # Run this from the root directory
3
-
4
- cd ./test || exit
5
- source approvals.bash
6
-
7
- # Update me
8
- cli=./download
9
-
10
- # Tests (context, describe and indentation are optional)
11
- context "when DEBUG is on"
12
- export DEBUG=1
13
-
14
- describe "root command"
15
- approve "$cli"
16
- approve "$cli --help"
17
-
18
- context "when DEBUG is off"
19
- unset DEBUG
20
-
21
- describe "some other command"
22
- approve "$cli other"
23
- approve "$cli other --help"
24
-
25
- # ...more tests...