~rjarry/dlrepo

dlrepo: product link enhancements v1 APPLIED

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
#1059958 .build.yml success
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
Export patchset (mbox)
How do I use this?

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 -3
Learn more about email & git

[PATCH dlrepo 1/3] job: rm redundant code in _link_to_product() Export this patch

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

[PATCH dlrepo 2/3] job: detect product link conflicts Export this patch

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

[PATCH dlrepo 3/3] templates: add branch links to product page Export this patch

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
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