Skip to content

Commit 8d6a7f8

Browse files
committed
CLI: fix sh completion command flag
1 parent 808e658 commit 8d6a7f8

6 files changed

Lines changed: 157 additions & 45 deletions

File tree

README.md

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -96,15 +96,12 @@ docker compose -f docker-compose.app.yml up -d --build
9696

9797
Either way, to test that everything is running properly, you can run:
9898
```shell
99-
curl -X 'GET' 'http://localhost:5000/' \
100-
-H 'Accept: application/json'
99+
dp3 sh health
101100
```
102101

103102
Which should return a JSON response with the following content:
104103
```json
105-
{
106-
"detail": "It works!"
107-
}
104+
{"detail": "It works!"}
108105
```
109106

110107
Final note, to simplify the experience of adjusting the app configuration,
@@ -155,16 +152,14 @@ The `docker-compose.yml` configuration contains the configuration for the servic
155152
as well as a testing setup of the DP³ platform itself.
156153
The full configuration is in `tests/test_config`.
157154
The setup includes one worker process and one API process to handle requests.
158-
The API process is exposed on port 5000, so you can send requests to it using `curl` or from your browser:
155+
The API process is exposed on port 5000, so you can send requests to it using `curl`, from your browser, or using the `dp3 sh` CLI:
159156

160157
```shell
161-
curl -X 'GET' 'http://localhost:5000/' \
162-
-H 'Accept: application/json'
158+
dp3 sh health
163159
```
164160
```shell
165-
curl -X 'POST' 'http://localhost:5000/datapoints' \
166-
-H 'Content-Type: application/json' \
167-
--data '[{"type": "test_entity_type", "id": "abc", "attr": "test_attr_int", "v": 123, "t1": "2023-07-01T12:00:00", "t2": "2023-07-01T13:00:00"}]'
161+
echo '[{"type": "test_entity_type", "id": "abc", "attr": "test_attr_int", "v": 123, "t1": "2023-07-01T12:00:00", "t2": "2023-07-01T13:00:00"}]\n' \
162+
| dp3 sh datapoints
168163
```
169164

170165
### Testing

docs/howto/deploy-app.md

Lines changed: 58 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,9 @@ Generate the base supervisor configuration for the app:
210210
sudo $(which dp3) config supervisor --config <CONFIG_DIR> --app-name <APP_NAME>
211211
```
212212

213+
The generated supervisor configuration lives under `/etc/<APP_NAME>` and the process logs are written under `/var/log/<APP_NAME>`.
214+
For more on supervisor itself, see the [supervisorctl documentation](http://supervisord.org/running.html#running-supervisorctl).
215+
213216
Enable and start the generated system service:
214217

215218
```shell
@@ -231,26 +234,66 @@ This creates two app-specific helpers:
231234

232235
`<APPNAME>sh entities` returns the full entity-type configuration map exposed by the API. When you only need the configured entity type names, pipe it through `jq keys`.
233236

234-
You can also enable shell completion for the wrapper or for `dp3 sh` itself:
237+
You can also enable shell completion for the wrapper or for `dp3` itself.
238+
The completion is registered for the executable name seen by the shell:
235239

236-
```shell
237-
# Bash
238-
source <(<APPNAME>sh completion bash --command <APPNAME>sh)
239-
source <(dp3 sh completion bash --command dp3)
240+
- use `--command dp3` for the main `dp3` command tree
241+
- use `--command <APPNAME>sh` for the generated wrapper
240242

241-
# Zsh
242-
source <(<APPNAME>sh completion zsh --command <APPNAME>sh)
243-
source <(dp3 sh completion zsh --command dp3)
243+
#### Session-local autocomplete
244244

245-
# Fish
246-
<APPNAME>sh completion fish --command <APPNAME>sh | source
247-
dp3 sh completion fish --command dp3 | source
248-
```
245+
Enable completion in the current shell session only:
249246

250-
The generated completion is config-aware. It can suggest entity types and attribute names from the resolved DP3 configuration.
247+
=== "Bash"
251248

252-
The generated supervisor configuration lives under `/etc/<APP_NAME>` and the process logs are written under `/var/log/<APP_NAME>`.
253-
For more on supervisor itself, see the [supervisorctl documentation](http://supervisord.org/running.html#running-supervisorctl).
249+
```shell
250+
source <(dp3 sh completion bash --command dp3 --command <APPNAME>sh)
251+
```
252+
253+
=== "Zsh"
254+
255+
```shell
256+
source <(dp3 sh completion zsh --command dp3 --command <APPNAME>sh)
257+
```
258+
259+
=== "Fish"
260+
261+
```shell
262+
dp3 sh completion fish --command dp3 --command <APPNAME>sh | source
263+
```
264+
265+
#### Persistent activation
266+
267+
To keep completion enabled across shell sessions, add the appropriate command to your shell startup file.
268+
269+
=== "Bash"
270+
271+
Add one of these to `~/.bashrc`:
272+
273+
```shell
274+
source <(<APPNAME>sh completion bash --command <APPNAME>sh)
275+
source <(dp3 sh completion bash --command dp3)
276+
```
277+
278+
=== "Zsh"
279+
280+
Add one of these to `~/.zshrc`:
281+
282+
```shell
283+
source <(<APPNAME>sh completion zsh --command <APPNAME>sh)
284+
source <(dp3 sh completion zsh --command dp3)
285+
```
286+
287+
=== "Fish"
288+
289+
Write the generated completion to a Fish completion file:
290+
291+
```shell
292+
<APPNAME>sh completion fish --command <APPNAME>sh > ~/.config/fish/completions/<APPNAME>sh.fish
293+
dp3 sh completion fish --command dp3 > ~/.config/fish/completions/dp3.fish
294+
```
295+
296+
The generated completion is config-aware. It can suggest entity types and attribute names from the resolved DP3 configuration.
254297

255298
### 6. Check that the deployment is healthy
256299

docs/howto/get-started.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,62 @@ A healthy API responds with:
246246

247247
At this point, you have a local DP³ environment ready for trying configuration changes and testing new code.
248248

249+
### Optional: enable shell completion for `dp3`
250+
251+
By default, the following will generate completion for the `dp3` executable.
252+
253+
#### Session-local activation
254+
255+
Enable completion in the current shell session only:
256+
257+
=== "Bash"
258+
259+
```shell
260+
source <(dp3 sh completion bash)
261+
```
262+
263+
=== "Zsh"
264+
265+
```shell
266+
source <(dp3 sh completion zsh)
267+
```
268+
269+
=== "Fish"
270+
271+
```shell
272+
dp3 sh completion fish | source
273+
```
274+
275+
#### Persistent activation
276+
277+
To keep completion enabled across shell sessions, add the appropriate command to your shell startup file.
278+
279+
=== "Bash"
280+
281+
Add this to `~/.bashrc`:
282+
283+
```shell
284+
source <(dp3 sh completion bash)
285+
```
286+
287+
=== "Zsh"
288+
289+
Add this to `~/.zshrc`:
290+
291+
```shell
292+
source <(dp3 sh completion zsh)
293+
```
294+
295+
=== "Fish"
296+
297+
Write the generated completion to a Fish completion file:
298+
299+
```shell
300+
dp3 sh completion fish > ~/.config/fish/completions/dp3.fish
301+
```
302+
303+
The generated completion is config-aware. It can suggest entity types and attribute names from the resolved DP3 configuration.
304+
249305
## 7. Sanity-check configuration changes as you iterate
250306

251307
When you change configuration, especially `config/db_entities`, validate it before restarting services:

dp3/bin/sh.py

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ def render_completion_shellcode(shell_name: str, command_names: list[str]) -> st
2121

2222
def handle_completion(_client, args) -> int:
2323
"""Print shell completion registration code."""
24-
sys.stdout.write(render_completion_shellcode(args.shell_name, args.command))
24+
sys.stdout.write(render_completion_shellcode(args.shell_name, args.completion_commands))
2525
if not sys.stdout.isatty():
2626
sys.stdout.write("\n")
2727
return 0
@@ -37,24 +37,25 @@ def register_completion_parser(commands) -> None:
3737
"output in your shell or source it from your shell startup file."
3838
),
3939
)
40-
completion_commands = completion_parser.add_subparsers(dest="shell_name", required=True)
41-
for shell_name in ["bash", "zsh", "fish"]:
42-
shell_parser = completion_commands.add_parser(
43-
shell_name, help=f"Print a {shell_name.capitalize()} completion script."
44-
)
45-
shell_parser.add_argument(
46-
"-c",
47-
"--command",
48-
action="append",
49-
default=[],
50-
help=(
51-
"Command name to register completion for. Repeat to register multiple "
52-
"commands. Use 'dp3' for 'dp3 sh' and '<APPNAME>sh' for wrapper commands."
53-
),
54-
)
55-
shell_parser.set_defaults(
56-
handler=handle_completion, requires_api=False, load_model_spec=False
57-
)
40+
completion_parser.add_argument(
41+
"shell_name",
42+
help="Shell name.",
43+
choices=["bash", "zsh", "fish", "tcsh", "powershell"],
44+
)
45+
completion_parser.add_argument(
46+
"-c",
47+
"--command",
48+
dest="completion_commands",
49+
action="append",
50+
default=None,
51+
help=(
52+
"Command name to register completion for. Repeat to register multiple "
53+
"commands. Use 'dp3' for 'dp3 sh' and '<APPNAME>sh' for wrapper commands."
54+
),
55+
)
56+
completion_parser.set_defaults(
57+
handler=handle_completion, requires_api=False, load_model_spec=False
58+
)
5859

5960

6061
def init_parser(parser: argparse.ArgumentParser) -> None:

dp3/template/appsh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,12 @@
11
#!/bin/sh
2+
3+
if [ -n "${_ARGCOMPLETE:-}" ] && [ -n "${COMP_LINE:-}" ] && [ -n "${COMP_POINT:-}" ]; then
4+
wrapper_name="${0##*/}"
5+
completion_prefix="{{DP3_EXE}} sh"
6+
completion_suffix="${COMP_LINE#"$wrapper_name"}"
7+
COMP_LINE="$completion_prefix$completion_suffix"
8+
COMP_POINT=$((COMP_POINT + ${#completion_prefix} - ${#wrapper_name}))
9+
export COMP_LINE COMP_POINT
10+
fi
11+
212
DP3_CONFIG_DIR="{{CONFIG_DIR}}" exec {{DP3_EXE}} sh "$@"

tests/test_common/test_sh_completion.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
from argcomplete.finders import CompletionFinder
77

8+
from dp3.bin.cli import init_parser as init_root_parser
89
from dp3.bin.sh import init_parser, render_completion_shellcode
910
from dp3.bin.shcmd.common import complete_entity_type_names
1011

@@ -230,3 +231,9 @@ def test_fish_completion_script_registers_commands(self):
230231
script = render_completion_shellcode("fish", ["dp3", "appsh"])
231232
self.assertIn("complete --command dp3", script)
232233
self.assertIn("complete --command appsh", script)
234+
235+
def test_completion_command_flag_does_not_override_root_command(self):
236+
parser = init_root_parser()
237+
args = parser.parse_args(["sh", "completion", "zsh", "-c", "dp3"])
238+
self.assertEqual("sh", args.command)
239+
self.assertEqual(["dp3"], args.completion_commands)

0 commit comments

Comments
 (0)