From c023ebe165dfe612688c05f03e011884bb323aca Mon Sep 17 00:00:00 2001 From: Evgenii Alekseev Date: Wed, 7 Aug 2024 18:22:18 +0300 Subject: [PATCH] docs: update documentation for implicit dependencies resolution --- docs/architecture.rst | 30 ++++++++++++++++++- .../templates/build-status/alerts.jinja2 | 2 +- .../build-status/key-import-modal.jinja2 | 4 +-- .../templates/build-status/login-modal.jinja2 | 11 ++++--- .../build-status/package-add-modal.jinja2 | 10 +++---- .../build-status/package-info-modal.jinja2 | 4 +-- .../build-status/package-rebuild-modal.jinja2 | 6 ++-- .../templates/build-status/table.jinja2 | 8 ++--- .../share/ahriman/templates/repo-index.jinja2 | 6 ++-- 9 files changed, 56 insertions(+), 25 deletions(-) diff --git a/docs/architecture.rst b/docs/architecture.rst index be6caeed..0d661187 100644 --- a/docs/architecture.rst +++ b/docs/architecture.rst @@ -192,6 +192,7 @@ Idea is to add package to a build queue from which it will be handled automatica * If supplied argument is file, then application moves the file to the directory with built packages. Same rule applies for directory, but in this case it copies every package-like file from the specified directory. * If supplied argument is directory and there is ``PKGBUILD`` file there, it will be treated as local package. In this case it will queue this package to build and copy source files (``PKGBUILD`` and ``.SRCINFO``) to caches. +* If supplied argument looks like URL (i.e. it has scheme - e.g. ``http://`` which is neither ``data`` nor ``file``), it tries to download the package from the specified remote source. * If supplied argument is not file then application tries to lookup for the specified name in AUR and clones it into the directory with manual updates. This scenario can also handle package dependencies which are missing in repositories. This logic can be overwritten by specifying the ``source`` parameter, which is partially useful if you would like to add package from AUR, but there is local directory cloned from AUR. Also official repositories calls are hidden behind explicit source definition. @@ -206,10 +207,20 @@ Remove packages This flow removes package from filesystem, updates repository database and also runs synchronization and reporting methods. +Check outdated packages +^^^^^^^^^^^^^^^^^^^^^^^ + +There are few ways for packages to be marked as out-of-date and hence requiring rebuild. Those are following: + +#. User requested update of the package. It can be caused by calling ``package-add`` subcommand (or ``package-update`` with arguments). +#. The most common way for packages to be marked as out-of-dated is that the version in AUR (or the official repositories) is newer than in the repository. +#. In addition to the above, if package is named as VCS (e.g. has suffix ``-git``) and the last update was more than specified threshold ago, the service will also try to fetch sources and check if the revision is newer than the built one. +#. In addition, there is ability to check if the dependencies of the package have been updated (e.g. if linked library has been renamed or the modules directory - e.g. in case of python and ruby packages - has been changed). And if so, the package will be marked as out-of-dated as well. + Update packages ^^^^^^^^^^^^^^^ -This feature is divided into to the following stages: check AUR for updates and run rebuild for required packages. Whereas check does not do anything except for check itself, update flow is the following: +This feature is divided into to the following stages: check AUR for updates and run rebuild for required packages. The package update flow is the following: #. Process every built package first. Those packages are usually added manually. #. Run sync and report methods. @@ -259,6 +270,23 @@ The application is able to automatically bump package release (``pkgrel``) durin #. If it has ``major.minor`` notation (e.g. ``1.1``), then increment last part by 1, e.g. ``1.1 -> 1.2``, ``1.0.1 -> 1.0.2``. #. If ``pkgrel`` is a number (e.g. ``1``), then append 1 to the end of the string, e.g. ``1 -> 1.1``. +Implicit dependencies resolution +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In addition to the depends/optional/make/check depends lists the server also handles implicit dependencies. After success build, the application traverse through the build tree and finds + +* Libraries to which the binaries (ELF-files) are linked. To do so, the ``NEEDED`` section of the ELF-files are read. +* Directories which contains files of the package, but do not belong to this package. This case covers, for example, python and ruby submodules. + +Having the initial dependencies tree, the application is looking for packages which contains those (both files and directories) paths and creates the initial packages list. After that, the packages list is reduced in the following way: + +* If the entry (i.e. file or directory) belongs to the package which is in base group, it will be removed. +* If there is a package which depends on the another package which provide the same entry, the package will be removed. +* After that, if there is a package which *optionally* depends on the another package in the remaining list, the package will be removed. +* And finally, if there is any path, which is the child of the entry, and it contains the same package, the package from the smaller entry will be removed. + +All those implicit dependencies are stored in the database and extracted on each check. In case if any of the repository packages doesn't contain any entry anymore (e.g. so version has been changed or modules directory has been changed), the dependent package will be marked as out-of-dated. + Core functions reference ------------------------ diff --git a/package/share/ahriman/templates/build-status/alerts.jinja2 b/package/share/ahriman/templates/build-status/alerts.jinja2 index 927b116f..cf922b09 100644 --- a/package/share/ahriman/templates/build-status/alerts.jinja2 +++ b/package/share/ahriman/templates/build-status/alerts.jinja2 @@ -21,7 +21,7 @@ alertPlaceholder.append(wrapper); const toast = new bootstrap.Toast(wrapper); - wrapper.addEventListener("hidden.bs.toast", () => { + wrapper.addEventListener("hidden.bs.toast", _ => { wrapper.remove(); // bootstrap doesn't remove elements (action || reload)(); }); diff --git a/package/share/ahriman/templates/build-status/key-import-modal.jinja2 b/package/share/ahriman/templates/build-status/key-import-modal.jinja2 index 9767abb3..80a6efbc 100644 --- a/package/share/ahriman/templates/build-status/key-import-modal.jinja2 +++ b/package/share/ahriman/templates/build-status/key-import-modal.jinja2 @@ -87,8 +87,8 @@ } } - $(() => { - keyImportModal.on("hidden.bs.modal", () => { + $(_ => { + keyImportModal.on("hidden.bs.modal", _ => { keyImportBodyInput.text(""); keyImportForm.trigger("reset"); }); diff --git a/package/share/ahriman/templates/build-status/login-modal.jinja2 b/package/share/ahriman/templates/build-status/login-modal.jinja2 index 834ba738..baf4daa3 100644 --- a/package/share/ahriman/templates/build-status/login-modal.jinja2 +++ b/package/share/ahriman/templates/build-status/login-modal.jinja2 @@ -53,10 +53,13 @@ contentType: "application/json", success: _ => { loginModal.modal("hide"); - showSuccess("Logged in", `Successfully logged in as ${username}`, () => location.href = "/"); + showSuccess("Logged in", `Successfully logged in as ${username}`, _ => location.href = "/"); }, error: (jqXHR, _, errorThrown) => { - const message = _ => `Could not login as ${username}`; + const message = _ => + username === "admin" && password === "admin" + ? "You've entered a password for user \"root\", did you make a typo in username?" + : `Could not login as ${username}`; showFailure("Login error", message, jqXHR, errorThrown); }, }); @@ -75,8 +78,8 @@ } } - $(() => { - loginModal.on("hidden.bs.modal", () => { + $(_ => { + loginModal.on("hidden.bs.modal", _ => { loginForm.trigger("reset"); }); }); diff --git a/package/share/ahriman/templates/build-status/package-add-modal.jinja2 b/package/share/ahriman/templates/build-status/package-add-modal.jinja2 index 171e6cab..78fb4cd9 100644 --- a/package/share/ahriman/templates/build-status/package-add-modal.jinja2 +++ b/package/share/ahriman/templates/build-status/package-add-modal.jinja2 @@ -126,18 +126,18 @@ } } - $(() => { - packageAddModal.on("shown.bs.modal", () => { + $(_ => { + packageAddModal.on("shown.bs.modal", _ => { $(`#package-add-repository-input option[value="${repository.architecture}-${repository.repository}"]`).prop("selected", true); }); - packageAddModal.on("hidden.bs.modal", () => { + packageAddModal.on("hidden.bs.modal", _ => { packageAddVariablesDiv.empty(); packageAddForm.trigger("reset"); }); - packageAddInput.keyup(() => { + packageAddInput.keyup(_ => { clearTimeout(packageAddInput.data("timeout")); - packageAddInput.data("timeout", setTimeout($.proxy(() => { + packageAddInput.data("timeout", setTimeout($.proxy(_ => { const value = packageAddInput.val(); if (value.length >= 3) { diff --git a/package/share/ahriman/templates/build-status/package-info-modal.jinja2 b/package/share/ahriman/templates/build-status/package-info-modal.jinja2 index f1575e29..1aca277b 100644 --- a/package/share/ahriman/templates/build-status/package-info-modal.jinja2 +++ b/package/share/ahriman/templates/build-status/package-info-modal.jinja2 @@ -290,8 +290,8 @@ if (isPackageBaseSet) packageInfoModal.modal("show"); } - $(() => { - packageInfoModal.on("hidden.bs.modal", () => { + $(_ => { + packageInfoModal.on("hidden.bs.modal", _ => { packageInfoAurUrl.empty(); packageInfoDepends.empty(); packageInfoGroups.empty(); diff --git a/package/share/ahriman/templates/build-status/package-rebuild-modal.jinja2 b/package/share/ahriman/templates/build-status/package-rebuild-modal.jinja2 index 02b31f3a..ba53a62d 100644 --- a/package/share/ahriman/templates/build-status/package-rebuild-modal.jinja2 +++ b/package/share/ahriman/templates/build-status/package-rebuild-modal.jinja2 @@ -50,11 +50,11 @@ } } - $(() => { - packageRebuildModal.on("shown.bs.modal", () => { + $(_ => { + packageRebuildModal.on("shown.bs.modal", _ => { $(`#package-rebuild-repository-input option[value="${repository.architecture}-${repository.repository}"]`).prop("selected", true); }); - packageRebuildModal.on("hidden.bs.modal", () => { packageRebuildForm.trigger("reset"); }); + packageRebuildModal.on("hidden.bs.modal", _ => { packageRebuildForm.trigger("reset"); }); }); diff --git a/package/share/ahriman/templates/build-status/table.jinja2 b/package/share/ahriman/templates/build-status/table.jinja2 index 1d7df0dd..81c0ed7a 100644 --- a/package/share/ahriman/templates/build-status/table.jinja2 +++ b/package/share/ahriman/templates/build-status/table.jinja2 @@ -182,7 +182,7 @@ return {classes: cellClass(value)}; } - $(() => { + $(_ => { $("#repositories a").on("click", event => { const element = event.target; repository = { @@ -194,7 +194,7 @@ reload(); }); - table.on("check.bs.table uncheck.bs.table check-all.bs.table uncheck-all.bs.table", () => { + table.on("check.bs.table uncheck.bs.table check-all.bs.table uncheck-all.bs.table", _ => { packageRemoveButton.prop("disabled", !table.bootstrapTable("getSelections").length); }); table.on("click-row.bs.table", (self, data, row, cell) => { @@ -203,7 +203,7 @@ table.bootstrapTable(method, {field: "id", values: [data.id]}); } else showPackageInfo(data.id); }); - table.on("created-controls.bs.table", () => { + table.on("created-controls.bs.table", _ => { const pickerInput = $(".bootstrap-table-filter-control-timestamp"); pickerInput.daterangepicker({ autoUpdateInput: false, @@ -217,7 +217,7 @@ table.bootstrapTable("triggerSearch"); }); - pickerInput.on("cancel.daterangepicker", () => { + pickerInput.on("cancel.daterangepicker", _ => { pickerInput.val(""); table.bootstrapTable("triggerSearch"); }); diff --git a/package/share/ahriman/templates/repo-index.jinja2 b/package/share/ahriman/templates/repo-index.jinja2 index 266e0801..e6314f53 100644 --- a/package/share/ahriman/templates/repo-index.jinja2 +++ b/package/share/ahriman/templates/repo-index.jinja2 @@ -123,8 +123,8 @@ SigLevel = Database{% if has_repo_signed %}Required{% else %}Never{% endif %} Pa return extractDataList(table.bootstrapTable("getData"), "licenses"); } - $(() => { - table.on("created-controls.bs.table", () => { + $(_ => { + table.on("created-controls.bs.table", _ => { const pickerInput = $(".bootstrap-table-filter-control-timestamp"); pickerInput.daterangepicker({ autoUpdateInput: false, @@ -138,7 +138,7 @@ SigLevel = Database{% if has_repo_signed %}Required{% else %}Never{% endif %} Pa table.bootstrapTable("triggerSearch"); }); - pickerInput.on("cancel.daterangepicker", () => { + pickerInput.on("cancel.daterangepicker", _ => { pickerInput.val(""); table.bootstrapTable("triggerSearch"); });