From 2fb3f0673377c4676bd1e50289fd2bae4eb038cc Mon Sep 17 00:00:00 2001 From: Tahoora Tabassum Date: Tue, 23 Dec 2025 22:27:34 +0530 Subject: [PATCH 1/5] Fix --version-id -> --versionid in CLI --- databusclient/cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/databusclient/cli.py b/databusclient/cli.py index 4e97470..0dc7047 100644 --- a/databusclient/cli.py +++ b/databusclient/cli.py @@ -16,7 +16,7 @@ def app(): @app.command() @click.option( - "--version-id", "version_id", + "--versionid", "version_id", required=True, help="Target databus version/dataset identifier of the form " "", From d4bb454af8fc7011ee652aa82394f1273bfe0407 Mon Sep 17 00:00:00 2001 From: Tahoora Tabassum Date: Tue, 23 Dec 2025 22:28:36 +0530 Subject: [PATCH 2/5] Fix --version-id -> --versionid in test script --- test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test.sh b/test.sh index f590198..0a4c096 100755 --- a/test.sh +++ b/test.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash databusclient deploy \ - --version-id "https://d8lr.tools.dbpedia.org/hopver/testGroup/testArtifact/1.0-alpha/" \ + --versionid "https://d8lr.tools.dbpedia.org/hopver/testGroup/testArtifact/1.0-alpha/" \ --title "Test Title" \ --abstract "Test Abstract" \ --description "Test Description" \ From 189458ec1f673c55f66b97d43b5507c648230f47 Mon Sep 17 00:00:00 2001 From: Tahoora Tabassum Date: Fri, 26 Dec 2025 19:42:42 +0530 Subject: [PATCH 3/5] cli: add mkdist validations, completion helper, tests and docs --- README.md | 54 ++++++++++++++++++++++++++++++++++++++++---- databusclient/cli.py | 47 ++++++++++++++++++++++++++++++++++++++ tests/test_cli.py | 42 ++++++++++++++++++++++++++++++++++ 3 files changed, 138 insertions(+), 5 deletions(-) create mode 100644 tests/test_cli.py diff --git a/README.md b/README.md index 0b65641..a828d75 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,8 @@ Options: Commands: deploy download + mkdist + completion ``` @@ -183,7 +185,7 @@ Arguments: - Metdata mode: None Options: - --version-id TEXT Target databus version/dataset identifier of the form [required] --title TEXT Dataset title [required] @@ -202,11 +204,11 @@ Options: #### Examples of using deploy command ##### Mode 1: Classic Deploy (Distributions) ``` -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' +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' ``` ``` -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' +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' ``` A few more notes for CLI usage: @@ -223,7 +225,7 @@ All files referenced there will be registered on the Databus. ```bash databusclient deploy \ --metadata /home/metadata.json \ - --version-id https://databus.org/user/dataset/version/1.0 \ + --versionid https://databus.org/user/dataset/version/1.0 \ --title "Metadata Deploy Example" \ --abstract "This is a short abstract of the dataset." \ --description "This dataset was uploaded using metadata.json." \ @@ -261,7 +263,7 @@ databusclient deploy \ --webdav-url https://cloud.example.com/remote.php/webdav \ --remote nextcloud \ --path datasets/mydataset \ - --version-id https://databus.org/user/dataset/version/1.0 \ + --versionid https://databus.org/user/dataset/version/1.0 \ --title "Test Dataset" \ --abstract "Short abstract of dataset" \ --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 ``` +### mkdist command + +Create a distribution string from components. + +Usage: +``` +databusclient mkdist URL --cv key=value --cv key2=value2 --format ttl --compression gz --sha-length : +``` + +Example: +``` +python -m databusclient mkdist "https://example.org/file.ttl" --cv lang=en --cv part=sorted --format ttl --compression gz --sha-length aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:12345 +``` + +## Completion + +Enable shell completion (bash example): +``` +eval "$(_DATABUSCLIENT_COMPLETE=source_bash python -m databusclient)" +``` + +### mkdist command + +Create a distribution string from components. + +Usage: +``` +databusclient mkdist URL --cv key=value --cv key2=value2 --format ttl --compression gz --sha-length : +``` + +Example: +``` +python -m databusclient mkdist "https://example.org/file.ttl" --cv lang=en --cv part=sorted --format ttl --compression gz --sha-length aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:12345 +``` + +## Completion + +Enable shell completion (bash example): +``` +eval "$(_DATABUSCLIENT_COMPLETE=source_bash python -m databusclient)" +``` + ## Module Usage ### Step 1: Create lists of distributions for the dataset diff --git a/databusclient/cli.py b/databusclient/cli.py index 0dc7047..d900c0f 100644 --- a/databusclient/cli.py +++ b/databusclient/cli.py @@ -3,6 +3,7 @@ import os import click +import re from typing import List from databusclient import client @@ -111,5 +112,51 @@ def download(databusuris: List[str], localdir, databus, token, authurl, clientid ) +@app.command() +@click.argument("url") +@click.option("--cv", "cvs", multiple=True, help="Content variant like key=value (repeatable). Keys must not contain '|' or '_'") +@click.option("--format", "file_format", help="Format extension (e.g. ttl)") +@click.option("--compression", help="Compression (e.g. gzip)") +@click.option("--sha-length", help="sha256:length (64 hex chars followed by ':' and integer length)") +@click.option("--json-output", is_flag=True, help="Output JSON distribution object instead of plain string") +def mkdist(url, cvs, file_format, compression, sha_length, json_output): + """Create a distribution string from components.""" + # Validate CVs + cvs_dict = {} + for cv in cvs: + if "=" not in cv: + raise click.BadParameter(f"Invalid content variant '{cv}': expected key=value") + key, val = cv.split("=", 1) + if any(ch in key for ch in ("|", "_")): + raise click.BadParameter("Invalid characters in content-variant key (forbidden: '|' and '_')") + if key in cvs_dict: + raise click.BadParameter(f"Duplicate content-variant key '{key}'") + cvs_dict[key] = val + + # Validate sha-length + sha_tuple = None + if sha_length: + if not re.match(r'^[A-Fa-f0-9]{64}:\d+$', sha_length): + raise click.BadParameter("Invalid --sha-length; expected SHA256HEX:length") + sha, length = sha_length.split(":", 1) + sha_tuple = (sha, int(length)) + + # Deterministic ordering + sorted_cvs = {k: cvs_dict[k] for k in sorted(cvs_dict)} + + dist = client.create_distribution(url=url, cvs=sorted_cvs, file_format=file_format, compression=compression, sha256_length_tuple=sha_tuple) + if json_output: + import json as _json + click.echo(_json.dumps({"distribution": dist})) + else: + click.echo(dist) + + +@app.command() +@click.argument("shell", type=click.Choice(["bash","zsh","fish","powershell"]), required=False) +def completion(shell="bash"): + click.echo(f"Run: eval \"$(_DATABUSCLIENT_COMPLETE=source_{shell} python -m databusclient)\"") + + if __name__ == "__main__": app() diff --git a/tests/test_cli.py b/tests/test_cli.py new file mode 100644 index 0000000..3dfd3eb --- /dev/null +++ b/tests/test_cli.py @@ -0,0 +1,42 @@ +from click.testing import CliRunner +from databusclient import cli + + +def test_mkdist_multiple_cv(): + runner = CliRunner() + sha = 'a' * 64 + res = runner.invoke(cli.app, [ + 'mkdist', + 'https://example.org/file', + '--cv', 'b=2', + '--cv', 'a=1', + '--format', 'ttl', + '--compression', 'gz', + '--sha-length', f'{sha}:42' + ]) + assert res.exit_code == 0, res.output + # keys should be sorted alphabetically: a then b + assert res.output.strip() == f'https://example.org/file|a=1_b=2|ttl|gz|{sha}:42' + + +def test_mkdist_invalid_cv(): + runner = CliRunner() + res = runner.invoke(cli.app, ['mkdist', 'https://example.org/file', '--cv', 'badcv']) + assert res.exit_code != 0 + assert 'Invalid content variant' in res.output + + +def test_mkdist_invalid_sha(): + runner = CliRunner() + res = runner.invoke(cli.app, [ + 'mkdist', 'https://example.org/file', '--cv', 'k=v', '--sha-length', 'abc:123' + ]) + assert res.exit_code != 0 + assert 'Invalid --sha-length' in res.output + + +def test_completion_output(): + runner = CliRunner() + res = runner.invoke(cli.app, ['completion', 'bash']) + assert res.exit_code == 0 + assert '_DATABUSCLIENT_COMPLETE' in res.output From d72a444a1bce7c26960648c0540556fd4e5c15b4 Mon Sep 17 00:00:00 2001 From: Tahoora Tabassum Date: Fri, 26 Dec 2025 20:24:43 +0530 Subject: [PATCH 4/5] Resolve remaining merge markers in cli.py --- databusclient/cli.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/databusclient/cli.py b/databusclient/cli.py index d59dde5..3525a0a 100644 --- a/databusclient/cli.py +++ b/databusclient/cli.py @@ -22,12 +22,8 @@ def app(): @app.command() @click.option( -<<<<<<< HEAD - "--versionid", "version_id", -======= "--version-id", "version_id", ->>>>>>> upstream/main required=True, help="Target databus version/dataset identifier of the form " "", From af27e181070c1806df5cf924954fc93cf177da18 Mon Sep 17 00:00:00 2001 From: Tahoora Tabassum Date: Fri, 26 Dec 2025 20:26:00 +0530 Subject: [PATCH 5/5] Use api_deploy.create_distribution to avoid circular import --- databusclient/cli.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/databusclient/cli.py b/databusclient/cli.py index 3525a0a..b5145bf 100644 --- a/databusclient/cli.py +++ b/databusclient/cli.py @@ -5,8 +5,6 @@ import click import re -from typing import List -from databusclient import client import databusclient.api.deploy as api_deploy from databusclient.api.delete import delete as api_delete @@ -248,7 +246,7 @@ def mkdist(url, cvs, file_format, compression, sha_length, json_output): # Deterministic ordering sorted_cvs = {k: cvs_dict[k] for k in sorted(cvs_dict)} - dist = client.create_distribution(url=url, cvs=sorted_cvs, file_format=file_format, compression=compression, sha256_length_tuple=sha_tuple) + dist = api_deploy.create_distribution(url=url, cvs=sorted_cvs, file_format=file_format, compression=compression, sha256_length_tuple=sha_tuple) if json_output: import json as _json click.echo(_json.dumps({"distribution": dist}))