Skip to content

Commit 189458e

Browse files
cli: add mkdist validations, completion helper, tests and docs
1 parent d4bb454 commit 189458e

3 files changed

Lines changed: 138 additions & 5 deletions

File tree

README.md

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ Options:
9090
Commands:
9191
deploy
9292
download
93+
mkdist
94+
completion
9395
```
9496

9597

@@ -183,7 +185,7 @@ Arguments:
183185
- Metdata mode: None
184186
185187
Options:
186-
--version-id TEXT Target databus version/dataset identifier of the form <h
188+
--versionid TEXT Target databus version/dataset identifier of the form <h
187189
ttps://databus.dbpedia.org/$ACCOUNT/$GROUP/$ARTIFACT/$VE
188190
RSION> [required]
189191
--title TEXT Dataset title [required]
@@ -202,11 +204,11 @@ Options:
202204
#### Examples of using deploy command
203205
##### Mode 1: Classic Deploy (Distributions)
204206
```
205-
databusclient deploy --version-id https://databus.dbpedia.org/user1/group1/artifact1/2022-05-18 --title title1 --abstract abstract1 --description description1 --license http://dalicc.net/licenselibrary/AdaptivePublicLicense10 --apikey MYSTERIOUS 'https://raw.githubusercontent.com/dbpedia/databus/master/server/app/api/swagger.yml|type=swagger'
207+
databusclient deploy --versionid https://databus.dbpedia.org/user1/group1/artifact1/2022-05-18 --title title1 --abstract abstract1 --description description1 --license http://dalicc.net/licenselibrary/AdaptivePublicLicense10 --apikey MYSTERIOUS 'https://raw.githubusercontent.com/dbpedia/databus/master/server/app/api/swagger.yml|type=swagger'
206208
```
207209

208210
```
209-
databusclient deploy --version-id https://dev.databus.dbpedia.org/denis/group1/artifact1/2022-05-18 --title "Client Testing" --abstract "Testing the client...." --description "Testing the client...." --license http://dalicc.net/licenselibrary/AdaptivePublicLicense10 --apikey MYSTERIOUS 'https://raw.githubusercontent.com/dbpedia/databus/master/server/app/api/swagger.yml|type=swagger'
211+
databusclient deploy --versionid https://dev.databus.dbpedia.org/denis/group1/artifact1/2022-05-18 --title "Client Testing" --abstract "Testing the client...." --description "Testing the client...." --license http://dalicc.net/licenselibrary/AdaptivePublicLicense10 --apikey MYSTERIOUS 'https://raw.githubusercontent.com/dbpedia/databus/master/server/app/api/swagger.yml|type=swagger'
210212
```
211213
A few more notes for CLI usage:
212214

@@ -223,7 +225,7 @@ All files referenced there will be registered on the Databus.
223225
```bash
224226
databusclient deploy \
225227
--metadata /home/metadata.json \
226-
--version-id https://databus.org/user/dataset/version/1.0 \
228+
--versionid https://databus.org/user/dataset/version/1.0 \
227229
--title "Metadata Deploy Example" \
228230
--abstract "This is a short abstract of the dataset." \
229231
--description "This dataset was uploaded using metadata.json." \
@@ -261,7 +263,7 @@ databusclient deploy \
261263
--webdav-url https://cloud.example.com/remote.php/webdav \
262264
--remote nextcloud \
263265
--path datasets/mydataset \
264-
--version-id https://databus.org/user/dataset/version/1.0 \
266+
--versionid https://databus.org/user/dataset/version/1.0 \
265267
--title "Test Dataset" \
266268
--abstract "Short abstract of dataset" \
267269
--description "This dataset was uploaded for testing the Nextcloud → Databus pipeline." \
@@ -296,6 +298,48 @@ docker run --rm -v $(pwd):/data dbpedia/databus-python-client download https://d
296298
```
297299

298300

301+
### mkdist command
302+
303+
Create a distribution string from components.
304+
305+
Usage:
306+
```
307+
databusclient mkdist URL --cv key=value --cv key2=value2 --format ttl --compression gz --sha-length <sha256hex>:<length>
308+
```
309+
310+
Example:
311+
```
312+
python -m databusclient mkdist "https://example.org/file.ttl" --cv lang=en --cv part=sorted --format ttl --compression gz --sha-length aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:12345
313+
```
314+
315+
## Completion
316+
317+
Enable shell completion (bash example):
318+
```
319+
eval "$(_DATABUSCLIENT_COMPLETE=source_bash python -m databusclient)"
320+
```
321+
322+
### mkdist command
323+
324+
Create a distribution string from components.
325+
326+
Usage:
327+
```
328+
databusclient mkdist URL --cv key=value --cv key2=value2 --format ttl --compression gz --sha-length <sha256hex>:<length>
329+
```
330+
331+
Example:
332+
```
333+
python -m databusclient mkdist "https://example.org/file.ttl" --cv lang=en --cv part=sorted --format ttl --compression gz --sha-length aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:12345
334+
```
335+
336+
## Completion
337+
338+
Enable shell completion (bash example):
339+
```
340+
eval "$(_DATABUSCLIENT_COMPLETE=source_bash python -m databusclient)"
341+
```
342+
299343
## Module Usage
300344
### Step 1: Create lists of distributions for the dataset
301345

databusclient/cli.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import os
44

55
import click
6+
import re
67
from typing import List
78
from databusclient import client
89

@@ -111,5 +112,51 @@ def download(databusuris: List[str], localdir, databus, token, authurl, clientid
111112
)
112113

113114

115+
@app.command()
116+
@click.argument("url")
117+
@click.option("--cv", "cvs", multiple=True, help="Content variant like key=value (repeatable). Keys must not contain '|' or '_'")
118+
@click.option("--format", "file_format", help="Format extension (e.g. ttl)")
119+
@click.option("--compression", help="Compression (e.g. gzip)")
120+
@click.option("--sha-length", help="sha256:length (64 hex chars followed by ':' and integer length)")
121+
@click.option("--json-output", is_flag=True, help="Output JSON distribution object instead of plain string")
122+
def mkdist(url, cvs, file_format, compression, sha_length, json_output):
123+
"""Create a distribution string from components."""
124+
# Validate CVs
125+
cvs_dict = {}
126+
for cv in cvs:
127+
if "=" not in cv:
128+
raise click.BadParameter(f"Invalid content variant '{cv}': expected key=value")
129+
key, val = cv.split("=", 1)
130+
if any(ch in key for ch in ("|", "_")):
131+
raise click.BadParameter("Invalid characters in content-variant key (forbidden: '|' and '_')")
132+
if key in cvs_dict:
133+
raise click.BadParameter(f"Duplicate content-variant key '{key}'")
134+
cvs_dict[key] = val
135+
136+
# Validate sha-length
137+
sha_tuple = None
138+
if sha_length:
139+
if not re.match(r'^[A-Fa-f0-9]{64}:\d+$', sha_length):
140+
raise click.BadParameter("Invalid --sha-length; expected SHA256HEX:length")
141+
sha, length = sha_length.split(":", 1)
142+
sha_tuple = (sha, int(length))
143+
144+
# Deterministic ordering
145+
sorted_cvs = {k: cvs_dict[k] for k in sorted(cvs_dict)}
146+
147+
dist = client.create_distribution(url=url, cvs=sorted_cvs, file_format=file_format, compression=compression, sha256_length_tuple=sha_tuple)
148+
if json_output:
149+
import json as _json
150+
click.echo(_json.dumps({"distribution": dist}))
151+
else:
152+
click.echo(dist)
153+
154+
155+
@app.command()
156+
@click.argument("shell", type=click.Choice(["bash","zsh","fish","powershell"]), required=False)
157+
def completion(shell="bash"):
158+
click.echo(f"Run: eval \"$(_DATABUSCLIENT_COMPLETE=source_{shell} python -m databusclient)\"")
159+
160+
114161
if __name__ == "__main__":
115162
app()

tests/test_cli.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
from click.testing import CliRunner
2+
from databusclient import cli
3+
4+
5+
def test_mkdist_multiple_cv():
6+
runner = CliRunner()
7+
sha = 'a' * 64
8+
res = runner.invoke(cli.app, [
9+
'mkdist',
10+
'https://example.org/file',
11+
'--cv', 'b=2',
12+
'--cv', 'a=1',
13+
'--format', 'ttl',
14+
'--compression', 'gz',
15+
'--sha-length', f'{sha}:42'
16+
])
17+
assert res.exit_code == 0, res.output
18+
# keys should be sorted alphabetically: a then b
19+
assert res.output.strip() == f'https://example.org/file|a=1_b=2|ttl|gz|{sha}:42'
20+
21+
22+
def test_mkdist_invalid_cv():
23+
runner = CliRunner()
24+
res = runner.invoke(cli.app, ['mkdist', 'https://example.org/file', '--cv', 'badcv'])
25+
assert res.exit_code != 0
26+
assert 'Invalid content variant' in res.output
27+
28+
29+
def test_mkdist_invalid_sha():
30+
runner = CliRunner()
31+
res = runner.invoke(cli.app, [
32+
'mkdist', 'https://example.org/file', '--cv', 'k=v', '--sha-length', 'abc:123'
33+
])
34+
assert res.exit_code != 0
35+
assert 'Invalid --sha-length' in res.output
36+
37+
38+
def test_completion_output():
39+
runner = CliRunner()
40+
res = runner.invoke(cli.app, ['completion', 'bash'])
41+
assert res.exit_code == 0
42+
assert '_DATABUSCLIENT_COMPLETE' in res.output

0 commit comments

Comments
 (0)