Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions examples/command-line-manipulation/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
download
102 changes: 102 additions & 0 deletions examples/command-line-manipulation/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# Command Line Manipulation

Demonstrates how to read or override the raw input command line.

Note that this is *not needed nor recommended* under most circumstances - it
is provided as an edge case utility.

This example was generated with:

```bash
$ bashly init --minimal
$ bashly add hooks
# ... now edit src/bashly.yml to match the example ...
# ... now edit src/initialize.sh to match the example ...
# ... now edit src/before.sh to match the example ...
$ bashly generate
```

<!-- include: src/initialize.sh src/before.sh -->

-----

## `bashly.yml`

````yaml
name: download
help: Sample minimal application without commands
version: 0.1.0

args:
- name: source
required: true
help: URL to download from
- name: target
help: "Target filename (default: same as source)"

flags:
- long: --force
short: -f
help: Overwrite existing files
````

## `src/initialize.sh`

````bash
echo "==[ Initialize Called ]=="

# Override the command line completely if the first argument is 'debug'
if [[ "${command_line[0]:-""}" = "debug" ]]; then
command_line=("modified" "args" "--force")
fi

````

## `src/before.sh`

````bash
echo "==[ Before Hook Called ]=="

echo "Read-only copy of the raw input array: ${input[*]}"
inspect_args

````


## Output

### `$ ./download `

````shell
==[ Initialize Called ]==
missing required argument: SOURCE
usage: download SOURCE [TARGET] [OPTIONS]


````

### `$ ./download debug`

````shell
==[ Initialize Called ]==
==[ Before Hook Called ]==
Read-only copy of the raw input array: modified args --force
args:
- ${args[--force]} = 1
- ${args[source]} = modified
- ${args[target]} = args
# This file is located at 'src/root_command.sh'.
# It contains the implementation for the 'download' command.
# The code you write here will be wrapped by a function named 'download_command()'.
# Feel free to edit this file; your changes will persist when regenerating.
args:
- ${args[--force]} = 1
- ${args[source]} = modified
- ${args[target]} = args
==[ After Hook Called ]==


````



7 changes: 7 additions & 0 deletions examples/command-line-manipulation/src/after.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
## after hook
##
## Any code here will be placed inside an `after_hook()` function and called
## after running any command.
##
## You can safely delete this file if you do not need it.
echo "==[ After Hook Called ]=="
15 changes: 15 additions & 0 deletions examples/command-line-manipulation/src/bashly.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
name: download
help: Sample minimal application without commands
version: 0.1.0

args:
- name: source
required: true
help: URL to download from
- name: target
help: "Target filename (default: same as source)"

flags:
- long: --force
short: -f
help: Overwrite existing files
4 changes: 4 additions & 0 deletions examples/command-line-manipulation/src/before.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
echo "==[ Before Hook Called ]=="

echo "Read-only copy of the raw input array: ${input[*]}"
inspect_args
6 changes: 6 additions & 0 deletions examples/command-line-manipulation/src/initialize.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
echo "==[ Initialize Called ]=="

# Override the command line completely if the first argument is 'debug'
if [[ "${command_line[0]:-""}" = "debug" ]]; then
command_line=("modified" "args" "--force")
fi
5 changes: 5 additions & 0 deletions examples/command-line-manipulation/src/root_command.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
echo "# This file is located at 'src/root_command.sh'."
echo "# It contains the implementation for the 'download' command."
echo "# The code you write here will be wrapped by a function named 'download_command()'."
echo "# Feel free to edit this file; your changes will persist when regenerating."
inspect_args
10 changes: 10 additions & 0 deletions examples/command-line-manipulation/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/usr/bin/env bash

set -x

bashly generate

### Try Me ###

./download
./download debug
9 changes: 6 additions & 3 deletions examples/hooks/src/before.sh
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
## before hook
##
## Any code here will be placed inside a `before_hook()` function and called
## before running any command (but after processing its arguments).
## Any code here will be placed inside the `before_hook()` function and called
## before running any command (but after argument processing is complete).
##
## - The processed args are available to you here as `args` and `extra_args`
## - The raw input array is also available in read-only mode as `input`
##
## You can safely delete this file if you do not need it.
echo "==[ Before Hook Called ]=="
inspect_args
inspect_args
4 changes: 4 additions & 0 deletions examples/hooks/src/initialize.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,8 @@
## Any code here will be placed inside the `initialize()` function and called
## before running anything else.
##
## The original command line arguments are available in the `command_line` array.
## You can modify this array to adjust or override the input before the app runs,
## though this is usually only needed for advanced use cases.
##
## You can safely delete this file if you do not need it.
9 changes: 6 additions & 3 deletions lib/bashly/libraries/hooks/before.sh
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
## before hook
##
## Any code here will be placed inside a `before_hook()` function and called
## before running any command (but after processing its arguments).
## Any code here will be placed inside the `before_hook()` function and called
## before running any command (but after argument processing is complete).
##
## - The processed args are available to you here as `args` and `extra_args`
## - The raw input array is also available in read-only mode as `input`
##
## You can safely delete this file if you do not need it.
echo "==[ Before Hook Called ]=="
inspect_args
inspect_args
4 changes: 4 additions & 0 deletions lib/bashly/libraries/hooks/initialize.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,8 @@
## Any code here will be placed inside the `initialize()` function and called
## before running anything else.
##
## The original command line arguments are available in the `command_line`
## array. You can modify or override the input before it is processed further,
## though this is usually only needed for advanced use cases.
##
## You can safely delete this file if you do not need it.
6 changes: 2 additions & 4 deletions lib/bashly/views/command/master_script.gtx
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,9 @@
>
if Settings.enabled? :sourcing
> if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
> {{ Settings.function_name :initialize }}
> {{ Settings.function_name :run }} "$@"
= render(:start).indent 2
> fi
else
> {{ Settings.function_name :initialize }}
> {{ Settings.function_name :run }} "$@"
= render :start
end
>
5 changes: 5 additions & 0 deletions lib/bashly/views/command/start.gtx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
= view_marker

> command_line=("$@")
> {{ Settings.function_name :initialize }}
> {{ Settings.function_name :run }} "${command_line[@]}"
2 changes: 1 addition & 1 deletion spec/approvals/cli/preview/no-args
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#!/usr/bin/env bash
...
run "$@"
fi
26 changes: 26 additions & 0 deletions spec/approvals/examples/command-line-manipulation
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
+ bashly generate
creating user files in src
skipped src/root_command.sh (exists)
created ./download
run ./download --help to test your bash script
+ ./download
==[ Initialize Called ]==
missing required argument: SOURCE
usage: download SOURCE [TARGET] [OPTIONS]
+ ./download debug
==[ Initialize Called ]==
==[ Before Hook Called ]==
Read-only copy of the raw input array: modified args --force
args:
- ${args[--force]} = 1
- ${args[source]} = modified
- ${args[target]} = args
# This file is located at 'src/root_command.sh'.
# It contains the implementation for the 'download' command.
# The code you write here will be wrapped by a function named 'download_command()'.
# Feel free to edit this file; your changes will persist when regenerating.
args:
- ${args[--force]} = 1
- ${args[source]} = modified
- ${args[target]} = args
==[ After Hook Called ]==
2 changes: 1 addition & 1 deletion spec/approvals/examples/render-mandoc
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,4 @@ ISSUE TRACKER
AUTHORS
Lana Lang.

Version 0.1.0 August 2025 download(1)
<footer>
8 changes: 4 additions & 4 deletions spec/approvals/examples/stacktrace
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ Examples:

+ ./download something
./download: line 15: no_such_command: command not found
./download:15 in `root_command`: no_such_command
./download:<line> in `root_command`: no_such_command

Stack trace:
from ./download:15 in `root_command`
from ./download:259 in `run`
from ./download:265 in `main`
from ./download:<line> in `root_command`
from ./download:<line> in `run`
from ./download:<line> in `main`
4 changes: 3 additions & 1 deletion spec/bashly/commands/preview_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@

it 'prints the generated cli script' do
expect { subject.execute %w[preview] }.to output_approval('cli/preview/no-args')
.except(/env bash\n.*\n\s*run "\$@"\n.*/m, "env bash\n...\nrun \"$@\"")
.except(/env bash\n.*\n\s*fi\n/m, "env bash\n...\nfi\b")
end
end
end


15 changes: 14 additions & 1 deletion spec/bashly/integration/examples_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@
# Allow up to a certain string distance from the approval text in CI
leeway = ENV['CI'] ? 40 : 0

# For certain examples, allow some exceptions (replacements) since they
# are too volatile (e.g. line number changes)
exceptions = {
'examples/stacktrace' => [/download:\d+/, 'download:<line>'],
'examples/render-mandoc' => [/Version 0.1.0.*download\(1\)/, '<footer>'],
}

test_cases.each do |example|
approval_name = example.gsub 'spec/fixtures/workspaces', 'fixtures'

Expand All @@ -41,7 +48,13 @@
# - The "+ ..." shell messages driven by `set -x` have no space
# - The order of our `inspect_args` sometimes differs
# - The result of the `deps` array sometimes differs
expect(output).to match_approval(approval_name).diff(leeway)
# In addition, for some examples we allow exceptions, so the below is
# just a more granular version of:
# expect(output).to match_approval(approval_name).diff(leeway).except(*except)
match_output = match_approval(approval_name).diff(leeway)
except = exceptions[example]
match_output = match_output.except(*except) if except
expect(output).to match_output
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion spec/bashly/script/wrapper_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
lines = subject.code.split "\n"
expect(lines[0..13].join("\n")).to match_approval('script/wrapper/code')
.except(/\d+\.\d+\.\d+(\.rc\d)?/)
expect(lines[-2]).to eq ' run "$@"'
expect(lines[-2]).to eq ' run "${command_line[@]}"'
end
end

Expand Down