Commit 192beea9 authored by mhellka's avatar mhellka
Browse files

Added CDStar.delete_* and more methods to handle classes.

parent 1996b90f
......@@ -18,9 +18,9 @@ with cdstar.begin(autocommit=True): # Wrap everything in a transaction (optiona
archive_id = cdstar.create_archive(vault_name).id
cdstar.put_file(vault_name, archive_id, "test.py", __file__)
with cdstar.get_file(vault_name, archive_id, "test.py") as download:
with cdstar.get_file(vault_name, archive_id, "test.py") as stream:
with open("/tmp/test.py", "wb") as target:
for chunk in download.iter_content(buffsize=1024*64):
for chunk in stream.iter_content(buffsize=1024*64):
target.write(chunk)
```
......@@ -32,11 +32,11 @@ cdstar = CDStar("https://cdstar.gwdg.de/demo/v3/", auth=("USER", "PASS"))
with cdstar.begin(autocommit=True): # Wrap everything in a transaction (optional)
vault = CDStarVault(cdstar, "demo")
archive = vault.create_archive()
archive.put("test.py", __file__)
file = vault.new_archive().file("test.py")
file.put(__file__)
with archive.file("test.py").download() as download:
download.save_to("/tmp/")
with file.stream() as stream:
stream.save_to("/tmp/")
```
## Command-Line interface
......
......@@ -192,11 +192,12 @@ class CDStar:
def exists(self, vault, archive=None, file=None) -> bool:
""" Checks if a vault, archive or file exists """
if file:
if file is not None:
return self.raw("HEAD", vault, archive, file, expect_status=[200, 404]).ok
if archive:
elif archive is not None:
return self.raw("HEAD", vault, archive, expect_status=[200, 404]).ok
return self.raw("HEAD", vault, expect_status=[200, 404]).ok
else:
return self.raw("HEAD", vault, expect_status=[200, 404]).ok
def service_info(self) -> JsonObject:
""" Get information about the cdstar service instance """
......@@ -206,22 +207,6 @@ class CDStar:
""" Get information about a vault """
return self.rest('GET', vault)
def archive_info(self, vault, archive, meta=False, files=False) -> JsonObject:
""" Get information about an archive """
query = {"info": "true"}
if meta:
query.setdefault("with", []).append("meta")
if files:
query.setdefault("with", []).append("files")
return self.rest("GET", vault, archive, params=query)
def file_info(self, vault, archive, name, meta=False) -> JsonObject:
""" Get information about a file """
query = {"info": "true"}
if meta:
query['with'] = "meta"
return self.rest("GET", vault, archive, _fix_filename(name), params=query)
def create_archive(self, vault, form: FormUpdate = None) -> JsonObject:
""" Create a new archive. """
if form:
......@@ -235,41 +220,18 @@ class CDStar:
return self.rest("POST", vault, archive, data=form.body,
headers={'Content-Type': form.content_type})
def list_files(self, vault, archive, offset=0, limit=100, meta=False, order=None, reverse=False,
include_glob=None, exclude_glob=None) -> JsonObject:
""" Request a FileList for an archive.
The FileList may be incomplete of more than `limit` files are in an archive. See iter_files() for a
convenient way to get all files as an iterator.
"""
query = {"files": "true", "offset": offset, "limit": limit}
if include_glob:
query["include"] = include_glob
if exclude_glob:
query["exclude"] = exclude_glob
def archive_info(self, vault, archive, meta=False, files=False) -> JsonObject:
""" Get information about an archive """
query = {"info": "true"}
if meta:
query["with"] = "meta"
if order:
query["order"] = order
if reverse:
query["reverse"] = "True"
query.setdefault("with", []).append("meta")
if files:
query.setdefault("with", []).append("files")
return self.rest("GET", vault, archive, params=query)
def iter_files(self, vault, archive, offset=0, **args) -> typing.Iterator[JsonObject]:
""" Yield all FileInfo entries of an archive.
This method may (lazily) issue more than one request if an archive contains more than `limit` files.
"""
while True:
files = self.list_files(vault, archive, offset, **args)
if files['files'] and offset + files['count'] <= files['total']:
yield from files['files']
offset += files['count']
else:
break
def delete_archive(self, vault, archive) -> bool:
""" Remove an archive. This cannot be undone. """
return self.raw("DELETE", vault, archive).ok
def put_file(self, vault, archive, name, source, type=None, replace=True) -> JsonObject:
""" Create or replace a single file on an existing archive.
......@@ -311,6 +273,53 @@ class CDStar:
rs = self.raw("GET", vault, archive, name, stream=True, headers=headers)
return FileDownload(vault, archive, name, rs)
def file_info(self, vault, archive, name, meta=False) -> JsonObject:
""" Get information about a file """
query = {"info": "true"}
if meta:
query['with'] = "meta"
return self.rest("GET", vault, archive, _fix_filename(name), params=query)
def list_files(self, vault, archive, offset=0, limit=100, meta=False, order=None, reverse=False,
include_glob=None, exclude_glob=None) -> JsonObject:
""" Request a FileList for an archive.
The FileList may be incomplete of more than `limit` files are in an archive. See iter_files() for a
convenient way to get all files as an iterator.
"""
query = {"files": "true", "offset": offset, "limit": limit}
if include_glob:
query["include"] = include_glob
if exclude_glob:
query["exclude"] = exclude_glob
if meta:
query["with"] = "meta"
if order:
query["order"] = order
if reverse:
query["reverse"] = "True"
return self.rest("GET", vault, archive, params=query)
def iter_files(self, vault, archive, offset=0, **args) -> typing.Iterator[JsonObject]:
""" Yield all FileInfo entries of an archive.
This method may (lazily) issue more than one request if an archive contains more than `limit` files.
"""
while True:
files = self.list_files(vault, archive, offset, **args)
if files['files'] and offset + files['count'] <= files['total']:
yield from files['files']
offset += files['count']
else:
break
def delete_file(self, vault, archive, file) -> bool:
""" Remove a archive file. This cannot be undone. """
return self.raw("DELETE", vault, archive, file).ok
def search(self, vault, q, order=None, limit=0, scroll=None, groups=None) -> JsonObject:
""" Perform a search and return a single page of search results.
......@@ -371,6 +380,8 @@ class CDStarVault:
__slots__ = "api", "name"
def __init__(self, api: CDStar, vault: str):
if not api or not vault:
raise AssertionError("Parameters must not be none")
self.api = api
self.name = vault
......@@ -409,10 +420,27 @@ class CDStarArchive:
"""
__slots__ = "api", "vault", "id"
def __init__(self, vault, id):
def __init__(self, vault: CDStarVault, archive_id):
if not vault or not archive_id:
raise AssertionError("Parameters must not be none")
self.api = vault.api
self.vault = vault
self.id = id
self.id = archive_id
def exists(self):
""" Checks if this archive exists. """
return self.api.exists(self.vault.name, self.id)
def delete(self):
""" Delete this archive. """
return self.api.delete_archive(self.vault.name, self.id)
def file(self, name: str) -> "CDStarFile":
""" Return a file handle.
The file may or may not exist remotely. Check with `exist()`.
"""
return CDStarFile(self, name)
# TODO: Implement meee
......@@ -425,8 +453,26 @@ class CDStarFile:
__slots__ = "api", "archive", "name"
def __init__(self, archive: CDStarArchive, name: str):
if not archive or not name:
raise AssertionError("Parameters must not be none")
self.api = archive.api
self.archive = archive
self.name = name
def exists(self):
""" Checks if this file exists """
return self.api.exists(self.archive.vault.name, self.archive.id, self.name)
def delete(self):
""" Delete this file from the archive. """
return self.api.delete_file(self.archive.vault.name, self.archive.id, self.name)
def put(self, **ka) -> JsonObject:
""" Create or overwrite file content """
return self.api.put_file(self.archive.vault.name, self.archive.id, self.name, **ka)
def stream(self, **ka) -> FileDownload:
""" Request file content as a stream-able :class:`FileDownload`. """
return self.api.get_file(self.archive.vault.name, self.archive.id, self.name, **ka)
# TODO: Implement meee
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment