This series brings a few enhancements to product links: code cleanup, better conflict detection and easier navigation between product and branch pages on the website. Julien Floret (3): job: rm redundant code in _link_to_product() job: detect product link conflicts templates: add branch links to product page dlrepo/fs/job.py | 15 +++------------ dlrepo/templates/product_version.html | 14 ++++++++++++++ dlrepo/views/product.py | 10 ++++++++++ 3 files changed, 27 insertions(+), 12 deletions(-) -- 2.39.2
dlrepo/patches/.build.yml: SUCCESS in 1m31s [product link enhancements][0] from [Julien Floret][1] [0]: https://lists.sr.ht/~rjarry/dlrepo/patches/44874 [1]: mailto:julien.floret@6wind.com ✓ #1059958 SUCCESS dlrepo/patches/.build.yml https://builds.sr.ht/~rjarry/job/1059958
Copy & paste the following snippet into your terminal to import this patchset into git:
curl -s https://lists.sr.ht/~rjarry/dlrepo/patches/44874/mbox | git am -3Learn more about email & git
The method iterates over the job formats to symlink each format into the product folder. It then attempts to symlink the "container" format explicitly. The latter is redundant since containers are already taken care of in the loop. Fixes: bd1c23893882 ("server: add filesystem api") Signed-off-by: Julien Floret <julien.floret@6wind.com> Acked-by: Thomas Faivre <thomas.faivre@6wind.com> --- dlrepo/fs/job.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/dlrepo/fs/job.py b/dlrepo/fs/job.py index 662f52dde964..3790893909aa 100644 --- a/dlrepo/fs/job.py +++ b/dlrepo/fs/job.py @@ -110,9 +110,6 @@ class Job(SubDir): self.update_symlink(version.path(), self._product_link_path()) for fmt in self.get_formats(): self.update_symlink(fmt.path(), version.path() / fmt.name) - container = self.path() / "container" - if container.is_dir(): - self.update_symlink(container, version.path() / "container") def _cleanup_product_tree(self): link = self._product_link_path() -- 2.39.2
Several jobs may be linked to the same product. For example, we can have a job handling the generation of the binary packages (a "bin" format), and another job handling the generation of the documentation (a "doc" format) for the same product. However, if some formats of the two jobs overlap (e.g. each job has a "bin" format), the product format will point to the latest uploaded job. This usually happens if there is a mistake in the declaration of the product variant of one of the jobs. However, since there is no error, the conflict can easily be missed. To avoid this, when updating the symlinks, let symlink_to() throw an exception if the link already exists. The dlrepo-cli "set-info" command will then return an error and it will be easier to detect the conflict. Rename the update_symlink() method to reflect the change. Note that this works because we should never have to update an existing link: in set_metadata(), the current links are removed before creating the new links. Signed-off-by: Julien Floret <julien.floret@6wind.com> Acked-by: Thomas Faivre <thomas.faivre@6wind.com> --- dlrepo/fs/job.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/dlrepo/fs/job.py b/dlrepo/fs/job.py index 3790893909aa..c2884399d25e 100644 --- a/dlrepo/fs/job.py +++ b/dlrepo/fs/job.py @@ -3,7 +3,6 @@ # SPDX-License-Identifier: BSD-3-Clause import asyncio -import errno import hashlib import json import logging @@ -82,12 +81,7 @@ class Job(SubDir): path.unlink() @staticmethod - def update_symlink(dst, link): - if link.exists(): - if link.is_symlink(): - link.unlink() - else: - raise OSError(errno.ENOTEMPTY, f"{link} exists and is not a symlink") + def create_symlink(dst, link): link.symlink_to(os.path.relpath(dst, link.parent)) def _link_to_product(self, version: Version): @@ -107,9 +101,9 @@ class Job(SubDir): The formats in a product version are not necessarily linked to the same job. """ version.create() - self.update_symlink(version.path(), self._product_link_path()) + self.create_symlink(version.path(), self._product_link_path()) for fmt in self.get_formats(): - self.update_symlink(fmt.path(), version.path() / fmt.name) + self.create_symlink(fmt.path(), version.path() / fmt.name) def _cleanup_product_tree(self): link = self._product_link_path() -- 2.39.2
To ease navigation between the product page and the original job(s) in /branches/, add a "Branch Link(s)" section to the bottom of the product page (similar to the "Product Link" section at the bottom of the job page). The branch links are not displayed if the user does not have the rights to access the job (typically, customers should have access to /products/ but not to /branches/). Signed-off-by: Julien Floret <julien.floret@6wind.com> Acked-by: Thomas Faivre <thomas.faivre@6wind.com> --- dlrepo/templates/product_version.html | 14 ++++++++++++++ dlrepo/views/product.py | 10 ++++++++++ 2 files changed, 24 insertions(+) diff --git a/dlrepo/templates/product_version.html b/dlrepo/templates/product_version.html index 65ecc868cc4b..b1839ff3636e 100644 --- a/dlrepo/templates/product_version.html +++ b/dlrepo/templates/product_version.html @@ -37,4 +37,18 @@ {{macros.install_procedure(version.name, version.artifact_formats)}} </section> + +{% if version.branch_links %} +<section class="product-link"> + <h2>Branch Link{{'s' if version.branch_links|length > 1}}</h2> + <hr/> + {% for link in version.branch_links|sort %} + <a href="/{{'~' + user + '/' if user}}branches/{{link}}/" + title="Branch link" class="product"> + <span>{{link.split('/')[-1]}}</span> + </a> + {% endfor %} +</section> +{% endif %} + {% endblock %} diff --git a/dlrepo/views/product.py b/dlrepo/views/product.py index c54709db6288..d03a55fd5a20 100644 --- a/dlrepo/views/product.py +++ b/dlrepo/views/product.py @@ -183,6 +183,7 @@ class VersionView(BaseView): html = "html" in self.request.headers.get("Accept", "json") formats = [] + branch_links = [] for fmt in version.get_formats(): fmt_url = fmt.url() if self.access_granted(fmt_url): @@ -202,12 +203,21 @@ class VersionView(BaseView): "url": fmt_url, } ) + job = fmt.path().resolve().parent + link = f"{job.parent.parent.name}/{job.parent.name}/{job.name}" + if link not in branch_links and self.access_granted( + fmt.root().url() + link + ): + branch_links.append(link) else: formats.append(fmt.name) data = {"version": {"name": version.name, "artifact_formats": formats}} if html: + if branch_links: + data["version"]["branch_links"] = branch_links + return aiohttp_jinja2.render_template( "product_version.html", self.request, data ) -- 2.39.2
builds.sr.ht <builds@sr.ht>dlrepo/patches/.build.yml: SUCCESS in 1m31s [product link enhancements][0] from [Julien Floret][1] [0]: https://lists.sr.ht/~rjarry/dlrepo/patches/44874 [1]: mailto:julien.floret@6wind.com ✓ #1059958 SUCCESS dlrepo/patches/.build.yml https://builds.sr.ht/~rjarry/job/1059958