exist-shell 0.1.0__tar.gz → 0.1.2__tar.gz
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.
- {exist_shell-0.1.0 → exist_shell-0.1.2}/CHANGELOG.md +13 -0
- exist_shell-0.1.2/LICENSE +21 -0
- exist_shell-0.1.2/PKG-INFO +280 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/README.md +23 -1
- {exist_shell-0.1.0 → exist_shell-0.1.2}/docs/api.md +8 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/docs/index.md +1 -1
- {exist_shell-0.1.0 → exist_shell-0.1.2}/docs/installation.md +24 -2
- exist_shell-0.1.2/pyproject.toml +62 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/uv.lock +1 -1
- exist_shell-0.1.0/PKG-INFO +0 -10
- exist_shell-0.1.0/pyproject.toml +0 -37
- {exist_shell-0.1.0 → exist_shell-0.1.2}/.gitguardian.yaml +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/.github/dependabot.yml +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/.github/workflows/docs.yml +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/.github/workflows/e2e.yml +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/.github/workflows/release.yml +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/.github/workflows/ruff.yml +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/.github/workflows/tests.yml +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/.github/workflows/ty.yml +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/.gitignore +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/CLAUDE.md +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/Makefile +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/docs/commands.md +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/docs/completion.md +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/docs/configuration.md +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/docs/development.md +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/docs/sync.md +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/mkdocs.yml +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/scripts/e2e/docker.sh +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/scripts/e2e/lib.sh +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/scripts/e2e/sections/T02_server.sh +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/scripts/e2e/sections/T03_collection.sh +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/scripts/e2e/sections/T04_ls.sh +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/scripts/e2e/sections/T05_put.sh +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/scripts/e2e/sections/T06_ls_after.sh +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/scripts/e2e/sections/T07_cat.sh +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/scripts/e2e/sections/T08_cp.sh +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/scripts/e2e/sections/T09_rm.sh +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/scripts/e2e/sections/T10_mkdir.sh +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/scripts/e2e/sections/T11_edit.sh +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/scripts/e2e/sections/T12_sync.sh +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/scripts/e2e/sections/T13_mv.sh +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/scripts/e2e/sections/T14_exec.sh +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/scripts/e2e/sections/T15_user.sh +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/scripts/e2e/sections/T16_group.sh +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/scripts/e2e/sections/T17_chown.sh +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/scripts/e2e/sections/T18_chmod.sh +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/scripts/e2e.sh +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/src/exist_shell/__init__.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/src/exist_shell/cache.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/src/exist_shell/client/__init__.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/src/exist_shell/client/_base.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/src/exist_shell/client/_collections.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/src/exist_shell/client/_documents.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/src/exist_shell/client/_groups.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/src/exist_shell/client/_permissions.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/src/exist_shell/client/_queries.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/src/exist_shell/client/_users.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/src/exist_shell/commands/__init__.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/src/exist_shell/commands/cat.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/src/exist_shell/commands/chmod.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/src/exist_shell/commands/chown.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/src/exist_shell/commands/collection.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/src/exist_shell/commands/cp.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/src/exist_shell/commands/edit.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/src/exist_shell/commands/exec.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/src/exist_shell/commands/group.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/src/exist_shell/commands/ls.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/src/exist_shell/commands/mkdir.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/src/exist_shell/commands/mv.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/src/exist_shell/commands/put.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/src/exist_shell/commands/rm.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/src/exist_shell/commands/server.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/src/exist_shell/commands/sync.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/src/exist_shell/commands/user.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/src/exist_shell/completions.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/src/exist_shell/config.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/src/exist_shell/exceptions.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/src/exist_shell/main.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/src/exist_shell/models.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/src/exist_shell/utils.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/src/exist_shell/xquery.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/tests/__init__.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/tests/conftest.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/tests/test_cache.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/tests/test_client.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/tests/test_commands_cat.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/tests/test_commands_chmod.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/tests/test_commands_chown.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/tests/test_commands_collection.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/tests/test_commands_cp.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/tests/test_commands_edit.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/tests/test_commands_exec.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/tests/test_commands_group.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/tests/test_commands_ls.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/tests/test_commands_mkdir.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/tests/test_commands_mv.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/tests/test_commands_put.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/tests/test_commands_rm.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/tests/test_commands_server.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/tests/test_commands_sync.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/tests/test_commands_user.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/tests/test_completions.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/tests/test_config.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/tests/test_utils.py +0 -0
- {exist_shell-0.1.0 → exist_shell-0.1.2}/tests/test_xquery.py +0 -0
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
## unreleased
|
|
4
4
|
|
|
5
|
+
## 0.1.2 - 2026-06-23
|
|
6
|
+
|
|
7
|
+
### Documentation
|
|
8
|
+
|
|
9
|
+
- Document installing `exsh` from PyPI (`uv tool install`, `pipx install`, `uvx --from`); the existing `git+https://...` instructions are kept as an alternative for tracking unreleased commits
|
|
10
|
+
|
|
11
|
+
## 0.1.1 - 2026-06-23
|
|
12
|
+
|
|
13
|
+
### Fixes
|
|
14
|
+
|
|
15
|
+
- Complete PyPI project metadata: `readme`, `license` (MIT), `authors`, `classifiers`, `project.urls`, and `keywords` were all missing, leaving the 0.1.0 PyPI listing with no description, license, or links
|
|
16
|
+
- Add `LICENSE` file (MIT)
|
|
17
|
+
|
|
5
18
|
## 0.1.0 - 2026-06-23
|
|
6
19
|
|
|
7
20
|
### Commands
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Alberto Simões
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: exist-shell
|
|
3
|
+
Version: 0.1.2
|
|
4
|
+
Summary: Command-line tool to interact with eXist-db via REST
|
|
5
|
+
Project-URL: Homepage, https://github.com/ambs/exist-shell
|
|
6
|
+
Project-URL: Repository, https://github.com/ambs/exist-shell
|
|
7
|
+
Project-URL: Documentation, https://ambs.github.io/exist-shell/
|
|
8
|
+
Project-URL: Issues, https://github.com/ambs/exist-shell/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/ambs/exist-shell/blob/main/CHANGELOG.md
|
|
10
|
+
Author-email: Alberto Simões <ambs@zbr.pt>
|
|
11
|
+
License-Expression: MIT
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Keywords: cli,exist-db,xml,xquery
|
|
14
|
+
Classifier: Development Status :: 4 - Beta
|
|
15
|
+
Classifier: Environment :: Console
|
|
16
|
+
Classifier: Intended Audience :: Developers
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Database
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
23
|
+
Classifier: Topic :: Utilities
|
|
24
|
+
Requires-Python: >=3.11
|
|
25
|
+
Requires-Dist: httpx>=0.27
|
|
26
|
+
Requires-Dist: platformdirs>=4.10.0; sys_platform == 'win32'
|
|
27
|
+
Requires-Dist: pydantic>=2.13.4
|
|
28
|
+
Requires-Dist: tomlkit>=0.15.0
|
|
29
|
+
Requires-Dist: typer>=0.26.7
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+
# exsh — eXist-db Shell
|
|
33
|
+
|
|
34
|
+
[](https://github.com/ambs/exist-shell/actions/workflows/tests.yml)
|
|
35
|
+
[](https://codecov.io/gh/ambs/exist-shell)
|
|
36
|
+
[](https://github.com/ambs/exist-shell/actions/workflows/e2e.yml)
|
|
37
|
+
[](https://github.com/ambs/exist-shell/actions/workflows/ruff.yml)
|
|
38
|
+
[](https://github.com/ambs/exist-shell/actions/workflows/ty.yml)
|
|
39
|
+
[](https://ambs.github.io/exist-shell/)
|
|
40
|
+
|
|
41
|
+
A command-line tool to interact with an [eXist-db](https://exist-db.org) server via its REST API. Designed for shell scripting and pipe-friendly workflows.
|
|
42
|
+
|
|
43
|
+
## Requirements
|
|
44
|
+
|
|
45
|
+
- Python 3.11+
|
|
46
|
+
- [uv](https://docs.astral.sh/uv/)
|
|
47
|
+
|
|
48
|
+
## Installation
|
|
49
|
+
|
|
50
|
+
Install system-wide with `uv tool`:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
uv tool install exist-shell
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Or with `pipx`:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
pipx install exist-shell
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
This places `exsh` on your `PATH`. Verify with:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
exsh --version
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
To uninstall:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
uv tool uninstall exist-shell
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Run without installing
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
uvx --from exist-shell exsh --version
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
`uvx` fetches the package into a temporary, cached environment and runs it — handy for one-off use or trying out a new release.
|
|
81
|
+
|
|
82
|
+
### Install from git
|
|
83
|
+
|
|
84
|
+
To track an unreleased commit instead of a PyPI release:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
uv tool install git+https://github.com/ambs/exist-shell
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Configuration
|
|
91
|
+
|
|
92
|
+
### Add a server
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
exsh server add localhost --port 8080 --user admin
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
A nickname is derived from the hostname by default (e.g. `localhost`). Override with `--nick`.
|
|
99
|
+
|
|
100
|
+
### Add an existing collection
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
exsh collection add mydata@localhost
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
This registers the `/db/mydata` collection on the `localhost` server under the nick `mydata`.
|
|
107
|
+
|
|
108
|
+
### Create and register a new collection
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
exsh collection new mydata@localhost
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Creates `/db/mydata` on the server and registers it in one step. If the collection already exists, it prints a message and exits without modifying the config. Use `--nick` to register it under a different name:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
exsh collection new mydata@localhost --nick md
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
List configured servers and collections:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
exsh server ls
|
|
124
|
+
exsh collection ls
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Configuration is stored at `~/.config/exsh/config.toml`.
|
|
128
|
+
|
|
129
|
+
## Commands
|
|
130
|
+
|
|
131
|
+
| Command | Description |
|
|
132
|
+
|---------|-------------|
|
|
133
|
+
| `exsh ls <nick>[:<path>]` | List subcollections and documents at a path |
|
|
134
|
+
| `exsh cat <nick>:<path>` | Print a document to stdout |
|
|
135
|
+
| `exsh put <file> <nick>:<path>` | Upload a local file to a collection |
|
|
136
|
+
| `exsh cp <src> <dst>` | Copy a document (local ↔ remote or remote ↔ remote) |
|
|
137
|
+
| `exsh edit <nick>:<path>` | Open a document in `$EDITOR`, re-upload if changed |
|
|
138
|
+
| `exsh rm <nick>:<path>...` | Delete one or more documents |
|
|
139
|
+
| `exsh mkdir <nick>:<path>` | Create a collection |
|
|
140
|
+
| `exsh sync <local> <nick>[:<path>]` | Push a local folder to a remote collection |
|
|
141
|
+
| `exsh sync <nick>[:<path>] <local>` | Pull a remote collection to a local folder |
|
|
142
|
+
| `exsh exec <nick>[:<path>]` | Execute an XQuery script on a server |
|
|
143
|
+
| `exsh server add <host>` | Register a server |
|
|
144
|
+
| `exsh server ls` | List registered servers |
|
|
145
|
+
| `exsh server rm <nick>` | Remove a server (and its collections) |
|
|
146
|
+
| `exsh server rename <old> <new>` | Rename a server nick (updates collection references) |
|
|
147
|
+
| `exsh collection add <name>[@<server>]` | Register an existing collection |
|
|
148
|
+
| `exsh collection new <name>[@<server>]` | Create a collection on the server and register it |
|
|
149
|
+
| `exsh collection ls` | List registered collections |
|
|
150
|
+
| `exsh collection rm <nick>` | Remove a collection from the config |
|
|
151
|
+
| `exsh user ls [@server]` | List user accounts and their groups |
|
|
152
|
+
| `exsh user add <user[@server]>` | Create a user account (prompts for password) |
|
|
153
|
+
| `exsh user rm <user[@server]>` | Remove a user account |
|
|
154
|
+
| `exsh user info <user[@server]>` | Show user account details |
|
|
155
|
+
| `exsh group ls [@server]` | List groups and their members |
|
|
156
|
+
| `exsh group add <group[@server]>` | Create a group |
|
|
157
|
+
| `exsh group rm <group[@server]>` | Remove a group |
|
|
158
|
+
| `exsh chown <spec> <nick>:<path>` | Change owner and/or group of a document or collection |
|
|
159
|
+
| `exsh chmod <mode> <nick>:<path>` | Change POSIX permissions of a document or collection |
|
|
160
|
+
|
|
161
|
+
### Examples
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
# List the root of a collection
|
|
165
|
+
exsh ls mydata
|
|
166
|
+
|
|
167
|
+
# List a subdirectory
|
|
168
|
+
exsh ls mydata:reports/2025
|
|
169
|
+
|
|
170
|
+
# Print a document
|
|
171
|
+
exsh cat mydata:reports/2025/summary.xml
|
|
172
|
+
|
|
173
|
+
# Upload a file
|
|
174
|
+
exsh put report.xml mydata:reports/2025/report.xml
|
|
175
|
+
|
|
176
|
+
# Copy from remote to local
|
|
177
|
+
exsh cp mydata:reports/2025/report.xml ./report.xml
|
|
178
|
+
|
|
179
|
+
# Edit in place
|
|
180
|
+
exsh edit mydata:reports/2025/report.xml
|
|
181
|
+
|
|
182
|
+
# Delete a document
|
|
183
|
+
exsh rm mydata:reports/2025/old.xml
|
|
184
|
+
|
|
185
|
+
# Delete multiple documents
|
|
186
|
+
exsh rm mydata:reports/2025/a.xml mydata:reports/2025/b.xml
|
|
187
|
+
|
|
188
|
+
# Create a subcollection
|
|
189
|
+
exsh mkdir mydata:reports/2026
|
|
190
|
+
|
|
191
|
+
# Execute an XQuery script from a file
|
|
192
|
+
exsh exec mydata:/ -f query.xq
|
|
193
|
+
|
|
194
|
+
# Execute an XQuery script from stdin
|
|
195
|
+
echo 'count(collection("/db/mydata"))' | exsh exec mydata:/
|
|
196
|
+
|
|
197
|
+
# Execute without local preprocessing
|
|
198
|
+
exsh exec mydata:/ --no-fix -f query.xq
|
|
199
|
+
|
|
200
|
+
# List locally available XQuery validators
|
|
201
|
+
exsh exec --list-validators
|
|
202
|
+
|
|
203
|
+
# Push a local folder to the server (only transfers changed files)
|
|
204
|
+
exsh sync ./reports mydata:reports
|
|
205
|
+
|
|
206
|
+
# Pull a remote collection to a local folder
|
|
207
|
+
exsh sync mydata:reports ./reports
|
|
208
|
+
|
|
209
|
+
# Preview what would be transferred without doing it
|
|
210
|
+
exsh sync --dry-run ./reports mydata:reports
|
|
211
|
+
|
|
212
|
+
# Push and remove files on the server that no longer exist locally
|
|
213
|
+
exsh sync --delete ./reports mydata:reports
|
|
214
|
+
|
|
215
|
+
# Change owner and group of a document
|
|
216
|
+
exsh chown alice:editors mydata:reports/annual.xml
|
|
217
|
+
|
|
218
|
+
# Recursively reassign a collection tree
|
|
219
|
+
exsh chown -R alice mydata:reports
|
|
220
|
+
|
|
221
|
+
# Set permissions with octal mode
|
|
222
|
+
exsh chmod 0644 mydata:reports/annual.xml
|
|
223
|
+
|
|
224
|
+
# Add execute permission for the owner
|
|
225
|
+
exsh chmod u+x mydata:scripts/run.xq
|
|
226
|
+
|
|
227
|
+
# Recursively set permissions for a collection
|
|
228
|
+
exsh chmod -R 0644 mydata:data
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## Sync
|
|
232
|
+
|
|
233
|
+
`exsh sync` transfers only files that have changed, using a local manifest stored at `~/.cache/exsh/sync/`. Direction is inferred from the argument order: local-first means push, remote-first means pull.
|
|
234
|
+
|
|
235
|
+
**Change detection:**
|
|
236
|
+
- **Push**: SHA-256 hash of the local file is compared against the manifest. Same-size edits are caught.
|
|
237
|
+
- **Pull**: `last_modified` timestamp from the eXist listing is compared against the manifest.
|
|
238
|
+
|
|
239
|
+
**Conflicts** (both sides changed since last sync) are reported and skipped — use `--force` to override.
|
|
240
|
+
|
|
241
|
+
**Options:**
|
|
242
|
+
|
|
243
|
+
| Flag | Effect |
|
|
244
|
+
|------|--------|
|
|
245
|
+
| `--force` / `-f` | Transfer all files, bypassing change detection |
|
|
246
|
+
| `--dry-run` / `-n` | Show what would happen without transferring |
|
|
247
|
+
| `--delete` | Remove files and empty folders on the destination that no longer exist on the source |
|
|
248
|
+
| `--verbose` / `-v` | Also print unchanged (skipped) files |
|
|
249
|
+
| `--checkpoint-every N` | Flush the manifest every N files (default: 100); allows interrupted syncs to resume near the point of failure |
|
|
250
|
+
|
|
251
|
+
## Shell completion
|
|
252
|
+
|
|
253
|
+
Generate and install tab-completion for your shell:
|
|
254
|
+
|
|
255
|
+
```bash
|
|
256
|
+
# bash
|
|
257
|
+
exsh --install-completion bash
|
|
258
|
+
|
|
259
|
+
# zsh
|
|
260
|
+
exsh --install-completion zsh
|
|
261
|
+
|
|
262
|
+
# fish
|
|
263
|
+
exsh --install-completion fish
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
## Development
|
|
267
|
+
|
|
268
|
+
```bash
|
|
269
|
+
git clone https://github.com/ambs/exist-shell
|
|
270
|
+
cd exist-shell
|
|
271
|
+
uv sync
|
|
272
|
+
exsh --help
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
Run checks:
|
|
276
|
+
|
|
277
|
+
```bash
|
|
278
|
+
make checks # lint, type-check, and tests
|
|
279
|
+
make test # tests only
|
|
280
|
+
```
|
|
@@ -19,7 +19,13 @@ A command-line tool to interact with an [eXist-db](https://exist-db.org) server
|
|
|
19
19
|
Install system-wide with `uv tool`:
|
|
20
20
|
|
|
21
21
|
```bash
|
|
22
|
-
uv tool install
|
|
22
|
+
uv tool install exist-shell
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Or with `pipx`:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pipx install exist-shell
|
|
23
29
|
```
|
|
24
30
|
|
|
25
31
|
This places `exsh` on your `PATH`. Verify with:
|
|
@@ -34,6 +40,22 @@ To uninstall:
|
|
|
34
40
|
uv tool uninstall exist-shell
|
|
35
41
|
```
|
|
36
42
|
|
|
43
|
+
### Run without installing
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
uvx --from exist-shell exsh --version
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
`uvx` fetches the package into a temporary, cached environment and runs it — handy for one-off use or trying out a new release.
|
|
50
|
+
|
|
51
|
+
### Install from git
|
|
52
|
+
|
|
53
|
+
To track an unreleased commit instead of a PyPI release:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
uv tool install git+https://github.com/ambs/exist-shell
|
|
57
|
+
```
|
|
58
|
+
|
|
37
59
|
## Configuration
|
|
38
60
|
|
|
39
61
|
### Add a server
|
|
@@ -7,10 +7,16 @@
|
|
|
7
7
|
|
|
8
8
|
## Install as a tool
|
|
9
9
|
|
|
10
|
-
The recommended way is to install `exsh` as a uv tool so it is available system-wide:
|
|
10
|
+
The recommended way is to install `exsh` from PyPI as a uv tool so it is available system-wide:
|
|
11
11
|
|
|
12
12
|
```bash
|
|
13
|
-
uv tool install
|
|
13
|
+
uv tool install exist-shell
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Or with `pipx`:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pipx install exist-shell
|
|
14
20
|
```
|
|
15
21
|
|
|
16
22
|
Verify the installation:
|
|
@@ -19,6 +25,14 @@ Verify the installation:
|
|
|
19
25
|
exsh --version
|
|
20
26
|
```
|
|
21
27
|
|
|
28
|
+
## Run without installing
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
uvx --from exist-shell exsh --version
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
`uvx` runs the command in a temporary, cached environment without installing it permanently — useful for trying out `exsh` or running a one-off command.
|
|
35
|
+
|
|
22
36
|
## Upgrade
|
|
23
37
|
|
|
24
38
|
```bash
|
|
@@ -31,6 +45,14 @@ uv tool upgrade exist-shell
|
|
|
31
45
|
uv tool uninstall exist-shell
|
|
32
46
|
```
|
|
33
47
|
|
|
48
|
+
## Install from git
|
|
49
|
+
|
|
50
|
+
To install an unreleased commit instead of the latest PyPI release:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
uv tool install git+https://github.com/ambs/exist-shell
|
|
54
|
+
```
|
|
55
|
+
|
|
34
56
|
## Install from a local clone
|
|
35
57
|
|
|
36
58
|
If you want to develop or test from source:
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "exist-shell"
|
|
7
|
+
version = "0.1.2"
|
|
8
|
+
description = "Command-line tool to interact with eXist-db via REST"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
authors = [
|
|
12
|
+
{ name = "Alberto Simões", email = "ambs@zbr.pt" },
|
|
13
|
+
]
|
|
14
|
+
keywords = ["exist-db", "xml", "xquery", "cli"]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 4 - Beta",
|
|
17
|
+
"Environment :: Console",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"Topic :: Database",
|
|
20
|
+
"Topic :: Software Development :: Libraries",
|
|
21
|
+
"Topic :: Utilities",
|
|
22
|
+
"Programming Language :: Python :: 3",
|
|
23
|
+
"Programming Language :: Python :: 3.11",
|
|
24
|
+
"Programming Language :: Python :: 3.12",
|
|
25
|
+
"Programming Language :: Python :: 3.13",
|
|
26
|
+
]
|
|
27
|
+
requires-python = ">=3.11"
|
|
28
|
+
dependencies = [
|
|
29
|
+
"typer>=0.26.7",
|
|
30
|
+
"httpx>=0.27",
|
|
31
|
+
"pydantic>=2.13.4",
|
|
32
|
+
"tomlkit>=0.15.0",
|
|
33
|
+
"platformdirs>=4.10.0; sys_platform == 'win32'",
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
[project.urls]
|
|
37
|
+
Homepage = "https://github.com/ambs/exist-shell"
|
|
38
|
+
Repository = "https://github.com/ambs/exist-shell"
|
|
39
|
+
Documentation = "https://ambs.github.io/exist-shell/"
|
|
40
|
+
Issues = "https://github.com/ambs/exist-shell/issues"
|
|
41
|
+
Changelog = "https://github.com/ambs/exist-shell/blob/main/CHANGELOG.md"
|
|
42
|
+
|
|
43
|
+
[project.scripts]
|
|
44
|
+
exsh = "exist_shell.main:app"
|
|
45
|
+
|
|
46
|
+
[tool.hatch.build.targets.wheel]
|
|
47
|
+
packages = ["src/exist_shell"]
|
|
48
|
+
|
|
49
|
+
[tool.ruff.lint]
|
|
50
|
+
select = ["D"]
|
|
51
|
+
|
|
52
|
+
[tool.ruff.lint.pydocstyle]
|
|
53
|
+
convention = "google"
|
|
54
|
+
|
|
55
|
+
[dependency-groups]
|
|
56
|
+
dev = [
|
|
57
|
+
"pytest>=8",
|
|
58
|
+
"pytest-cov>=5",
|
|
59
|
+
"pytest-httpx>=0.30",
|
|
60
|
+
"ruff>=0.15.16",
|
|
61
|
+
"ty>=0.0.46",
|
|
62
|
+
]
|
exist_shell-0.1.0/PKG-INFO
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: exist-shell
|
|
3
|
-
Version: 0.1.0
|
|
4
|
-
Summary: Command-line tool to interact with eXist-db via REST
|
|
5
|
-
Requires-Python: >=3.11
|
|
6
|
-
Requires-Dist: httpx>=0.27
|
|
7
|
-
Requires-Dist: platformdirs>=4.10.0; sys_platform == 'win32'
|
|
8
|
-
Requires-Dist: pydantic>=2.13.4
|
|
9
|
-
Requires-Dist: tomlkit>=0.15.0
|
|
10
|
-
Requires-Dist: typer>=0.26.7
|
exist_shell-0.1.0/pyproject.toml
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
[build-system]
|
|
2
|
-
requires = ["hatchling"]
|
|
3
|
-
build-backend = "hatchling.build"
|
|
4
|
-
|
|
5
|
-
[project]
|
|
6
|
-
name = "exist-shell"
|
|
7
|
-
version = "0.1.0"
|
|
8
|
-
description = "Command-line tool to interact with eXist-db via REST"
|
|
9
|
-
requires-python = ">=3.11"
|
|
10
|
-
dependencies = [
|
|
11
|
-
"typer>=0.26.7",
|
|
12
|
-
"httpx>=0.27",
|
|
13
|
-
"pydantic>=2.13.4",
|
|
14
|
-
"tomlkit>=0.15.0",
|
|
15
|
-
"platformdirs>=4.10.0; sys_platform == 'win32'",
|
|
16
|
-
]
|
|
17
|
-
|
|
18
|
-
[project.scripts]
|
|
19
|
-
exsh = "exist_shell.main:app"
|
|
20
|
-
|
|
21
|
-
[tool.hatch.build.targets.wheel]
|
|
22
|
-
packages = ["src/exist_shell"]
|
|
23
|
-
|
|
24
|
-
[tool.ruff.lint]
|
|
25
|
-
select = ["D"]
|
|
26
|
-
|
|
27
|
-
[tool.ruff.lint.pydocstyle]
|
|
28
|
-
convention = "google"
|
|
29
|
-
|
|
30
|
-
[dependency-groups]
|
|
31
|
-
dev = [
|
|
32
|
-
"pytest>=8",
|
|
33
|
-
"pytest-cov>=5",
|
|
34
|
-
"pytest-httpx>=0.30",
|
|
35
|
-
"ruff>=0.15.16",
|
|
36
|
-
"ty>=0.0.46",
|
|
37
|
-
]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|