~rjarry/dlrepo

6de1f15cfcf8e219c121f6e10ae144d64755bd24 — Julien Floret 11 months ago 998ec62
format: add delete method

It can be useful to delete a specific job format without deleting the
entire job. For example if there is a mistake in some additional
documentation or test result and we want to update it without
deleting and re-uploading the entire job.

Signed-off-by: Julien Floret <julien.floret@6wind.com>
Acked-by: Thomas Faivre <thomas.faivre@6wind.com>
Acked-by: Robin Jarry <robin@jarry.cc>
5 files changed, 44 insertions(+), 8 deletions(-)

M dlrepo-cli
M dlrepo/fs/fmt.py
M dlrepo/fs/job.py
M dlrepo/views/fmt.py
M docs/dlrepo-api.7.scdoc
M dlrepo-cli => dlrepo-cli +9 -8
@@ 487,21 487,22 @@ def internal(args):
    Arg("branch", metavar="BRANCH", help="the branch name"),
    Arg("tag", metavar="TAG", nargs="?", help="the tag name"),
    Arg("job", metavar="JOB", nargs="?", help="the job name"),
    Arg("format", metavar="FORMAT", nargs="?", help="the artifact format"),
)
def delete(args):
    """
    Delete a job, a tag or a branch and all its tags recursively.
    Delete a branch, a tag, a job or a format.
    """
    client = HttpClient(args.url)
    params = {}
    url = os.path.join("branches", args.branch)
    if args.tag:
        if args.job:
            url = os.path.join("branches", args.branch, args.tag, args.job) + "/"
        else:
            url = os.path.join("branches", args.branch, args.tag) + "/"
    else:
        url = os.path.join("branches", args.branch) + "/"
    client.delete(url, params)
        url = os.path.join(url, args.tag)
    if args.job:
        url = os.path.join(url, args.job)
    if args.format:
        url = os.path.join(url, args.format)
    client.delete(url + "/", params)


# --------------------------------------------------------------------------------------

M dlrepo/fs/fmt.py => dlrepo/fs/fmt.py +5 -0
@@ 229,3 229,8 @@ class ArtifactFormat(SubDir):
                os.link(fpath, blob)

        self.digest_path().write_text(json.dumps(new_digests, sort_keys=True))

    def delete(self):
        if not self.exists():
            raise FileNotFoundError()
        self.root().rmtree(self._path)

M dlrepo/fs/job.py => dlrepo/fs/job.py +1 -0
@@ 117,6 117,7 @@ class Job(SubDir):
            if not d.is_symlink():
                continue
            if not d.is_dir():
                d.unlink()
                continue
            try:
                if d.resolve().samefile(self.path() / d.name):

M dlrepo/views/fmt.py => dlrepo/views/fmt.py +16 -0
@@ 2,6 2,7 @@
# Copyright (c) 2021 Robin Jarry
# SPDX-License-Identifier: BSD-3-Clause

import asyncio
import logging
from typing import Callable



@@ 71,6 72,21 @@ class FormatDirView(BaseView):
            raise web.HTTPInternalServerError(reason="post process failed") from e
        return web.Response()

    async def delete(self):
        """
        Delete a format.
        """
        loop = asyncio.get_running_loop()
        try:
            fmt = _get_format(self.repo(), self.request.match_info)
            await loop.run_in_executor(None, fmt.delete)
            self.repo().schedule_cleanup_orphans()
        except FileNotFoundError as e:
            raise web.HTTPNotFound() from e
        except OSError as e:
            raise web.HTTPBadRequest(reason=str(e)) from e
        return web.Response()


# --------------------------------------------------------------------------------------
class FormatArchiveView(BaseView):

M docs/dlrepo-api.7.scdoc => docs/dlrepo-api.7.scdoc +13 -0
@@ 428,6 428,19 @@ Delete the specified _{job}_ and all its artifact formats.
	- _404_: the specified _{job}_ does not exist.
	- _405_: _{tag}_ is either _latest_, _stable_ or _oldstable_.

# ARTIFACT FORMATS

## DELETE /branches/{branch}/{tag}/{job}/{format}/
## DELETE /~{user}/branches/{branch}/{tag}/{job}/{format}/

Delete the specified artifact format.

*Access:*
	_d_
*Errors:*
	- _404_: the specified _{format}_ does not exist.
	- _405_: _{tag}_ is either _latest_, _stable_ or _oldstable_.

# PRODUCTS

## GET /products/