forked from dbpedia/databus-python-client
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcli.py
More file actions
222 lines (200 loc) · 7.13 KB
/
cli.py
File metadata and controls
222 lines (200 loc) · 7.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
#!/usr/bin/env python3
import json
import os
from typing import List
import click
import databusclient.api.deploy as api_deploy
from databusclient.api.delete import delete as api_delete
from databusclient.api.download import download as api_download, DownloadAuthError
from databusclient.extensions import webdav
@click.group()
def app():
"""Databus Client CLI"""
pass
@app.command()
@click.option(
"--version-id",
"version_id",
required=True,
help="Target databus version/dataset identifier of the form "
"<https://databus.dbpedia.org/$ACCOUNT/$GROUP/$ARTIFACT/$VERSION>",
)
@click.option("--title", required=True, help="Artifact title: the permanent name of the data series (applies to all versions)")
@click.option("--abstract", required=True, help="Version Abstract: a short summary (max 200 chars) specific to this timestamped release")
@click.option("--description", required=True, help="Version Description: detailed metadata for this specific release (supports Markdown)")
@click.option(
"--license", "license_url", required=True, help="License (see dalicc.net)"
)
@click.option("--apikey", required=True, help="API key")
@click.option(
"--metadata",
"metadata_file",
type=click.Path(exists=True),
help="Path to metadata JSON file (for metadata mode)",
)
@click.option(
"--webdav-url",
"webdav_url",
help="WebDAV URL (e.g., https://cloud.example.com/remote.php/webdav)",
)
@click.option("--remote", help="rclone remote name (e.g., 'nextcloud')")
@click.option("--path", help="Remote path on Nextcloud (e.g., 'datasets/mydataset')")
@click.argument("distributions", nargs=-1)
def deploy(
version_id,
title,
abstract,
description,
license_url,
apikey,
metadata_file,
webdav_url,
remote,
path,
distributions: List[str],
):
"""
Flexible deploy to Databus command supporting three modes:\n
- Classic deploy (distributions as arguments)\n
- Metadata-based deploy (--metadata <file>)\n
- Upload & deploy via Nextcloud (--webdav-url, --remote, --path)
"""
# Sanity checks for conflicting options
if metadata_file and any([distributions, webdav_url, remote, path]):
raise click.UsageError(
"Invalid combination: when using --metadata, do not provide --webdav-url, --remote, --path, or distributions."
)
if any([webdav_url, remote, path]) and not all([webdav_url, remote, path]):
raise click.UsageError(
"Invalid combination: when using WebDAV/Nextcloud mode, please provide --webdav-url, --remote, and --path together."
)
# === Mode 1: Classic Deploy ===
if distributions and not (metadata_file or webdav_url or remote or path):
click.echo("[MODE] Classic deploy with distributions")
click.echo(f"Deploying dataset version: {version_id}")
dataid = api_deploy.create_dataset(
version_id=version_id,
artifact_title=title,
artifact_abstract=abstract,
artifact_description=description,
license_url=license_url,
distributions=distributions
)
api_deploy.deploy(dataid=dataid, api_key=apikey)
return
# === Mode 2: Metadata File ===
if metadata_file:
click.echo(f"[MODE] Deploy from metadata file: {metadata_file}")
with open(metadata_file, "r") as f:
metadata = json.load(f)
api_deploy.deploy_from_metadata(
metadata, version_id, title, abstract, description, license_url, apikey
)
return
# === Mode 3: Upload & Deploy (Nextcloud) ===
if webdav_url and remote and path:
if not distributions:
raise click.UsageError(
"Please provide files to upload when using WebDAV/Nextcloud mode."
)
# Check that all given paths exist and are files or directories.
invalid = [f for f in distributions if not os.path.exists(f)]
if invalid:
raise click.UsageError(
f"The following input files or folders do not exist: {', '.join(invalid)}"
)
click.echo("[MODE] Upload & Deploy to DBpedia Databus via Nextcloud")
click.echo(f"→ Uploading to: {remote}:{path}")
metadata = webdav.upload_to_webdav(distributions, remote, path, webdav_url)
api_deploy.deploy_from_metadata(
metadata, version_id, title, abstract, description, license_url, apikey
)
return
raise click.UsageError(
"No valid input provided. Please use one of the following modes:\n"
" - Classic deploy: pass distributions as arguments\n"
" - Metadata deploy: use --metadata <file>\n"
" - Upload & deploy: use --webdav-url, --remote, --path, and file arguments"
)
@app.command()
@click.argument("databusuris", nargs=-1, required=True)
@click.option(
"--localdir",
help="Local databus folder (if not given, databus folder structure is created in current working directory)",
)
@click.option(
"--databus",
help="Databus URL (if not given, inferred from databusuri, e.g. https://databus.dbpedia.org/sparql)",
)
@click.option("--vault-token", help="Path to Vault refresh token file")
@click.option(
"--databus-key", help="Databus API key to download from protected databus"
)
@click.option(
"--all-versions",
is_flag=True,
help="When downloading artifacts, download all versions instead of only the latest",
)
@click.option(
"--authurl",
default="https://auth.dbpedia.org/realms/dbpedia/protocol/openid-connect/token",
show_default=True,
help="Keycloak token endpoint URL",
)
@click.option(
"--clientid",
default="vault-token-exchange",
show_default=True,
help="Client ID for token exchange",
)
def download(
databusuris: List[str],
localdir,
databus,
vault_token,
databus_key,
all_versions,
authurl,
clientid,
):
"""
Download datasets from databus, optionally using vault access if vault options are provided.
"""
try:
api_download(
localDir=localdir,
endpoint=databus,
databusURIs=databusuris,
token=vault_token,
databus_key=databus_key,
all_versions=all_versions,
auth_url=authurl,
client_id=clientid,
)
except DownloadAuthError as e:
raise click.ClickException(str(e))
@app.command()
@click.argument("databusuris", nargs=-1, required=True)
@click.option(
"--databus-key", help="Databus API key to access protected databus", required=True
)
@click.option(
"--dry-run", is_flag=True, help="Perform a dry run without actual deletion"
)
@click.option(
"--force", is_flag=True, help="Force deletion without confirmation prompt"
)
def delete(databusuris: List[str], databus_key: str, dry_run: bool, force: bool):
"""
Delete a dataset from the databus.
Delete a group, artifact, or version identified by the given databus URI.
Will recursively delete all data associated with the dataset.
"""
api_delete(
databusURIs=databusuris,
databus_key=databus_key,
dry_run=dry_run,
force=force,
)
if __name__ == "__main__":
app()