mirror of
https://github.com/arcan1s/ahriman.git
synced 2025-05-04 20:23:49 +00:00
Compare commits
11 Commits
3d50ea4686
...
0e7ca45b54
Author | SHA1 | Date | |
---|---|---|---|
0e7ca45b54 | |||
1ec1bd05eb | |||
6d05389639 | |||
daf9841717 | |||
0d243a781a | |||
cf2e66a934 | |||
f01f35238d | |||
d30d512eb6 | |||
0437f90e5a | |||
3cab65855a | |||
ecfb615f97 |
7
.github/workflows/setup.sh
vendored
7
.github/workflows/setup.sh
vendored
@ -12,7 +12,7 @@ pacman -Syu --noconfirm
|
||||
# main dependencies
|
||||
pacman -Sy --noconfirm devtools git pyalpm python-cerberus python-inflection python-passlib python-pyelftools python-requests python-srcinfo python-systemd sudo
|
||||
# make dependencies
|
||||
pacman -Sy --noconfirm python-build python-flit python-installer python-tox python-wheel
|
||||
pacman -Sy --noconfirm --asdeps base-devel python-build python-flit python-installer python-tox python-wheel
|
||||
# optional dependencies
|
||||
if [[ -z $MINIMAL_INSTALL ]]; then
|
||||
# VCS support
|
||||
@ -36,6 +36,9 @@ sudo -u nobody -- makepkg --packagelist | grep -v -- -debug- | pacman -U --nocon
|
||||
# create machine-id which is required by build tools
|
||||
systemd-machine-id-setup
|
||||
|
||||
# remove unused dependencies
|
||||
pacman -Qdtq | pacman -Rscn --noconfirm -
|
||||
|
||||
# initial setup command as root
|
||||
[[ -z $MINIMAL_INSTALL ]] && WEB_ARGS=("--web-port" "8080")
|
||||
ahriman -a x86_64 -r "github" service-setup --packager "ahriman bot <ahriman@example.com>" "${WEB_ARGS[@]}"
|
||||
@ -50,7 +53,7 @@ if [[ -z $MINIMAL_INSTALL ]]; then
|
||||
WEB_PID=$!
|
||||
fi
|
||||
# add the first package
|
||||
sudo -u ahriman -- ahriman package-add --now ahriman
|
||||
sudo -u ahriman -- ahriman --log-handler console package-add --now ahriman
|
||||
# check if package was actually installed
|
||||
test -n "$(find "/var/lib/ahriman/repository/github/x86_64" -name "ahriman*pkg*")"
|
||||
# run package check
|
||||
|
@ -3,7 +3,7 @@ version: 2
|
||||
build:
|
||||
os: ubuntu-20.04
|
||||
tools:
|
||||
python: "3.11"
|
||||
python: "3.12"
|
||||
|
||||
python:
|
||||
install:
|
||||
|
@ -33,9 +33,9 @@ COPY "docker/install-aur-package.sh" "/usr/local/bin/install-aur-package"
|
||||
## install package dependencies
|
||||
## darcs is not installed by reasons, because it requires a lot haskell packages which dramatically increase image size
|
||||
RUN pacman -Sy --noconfirm --asdeps devtools git pyalpm python-cerberus python-inflection python-passlib python-pyelftools python-requests python-srcinfo && \
|
||||
pacman -Sy --noconfirm --asdeps python-build python-flit python-installer python-wheel && \
|
||||
pacman -Sy --noconfirm --asdeps base-devel python-build python-flit python-installer python-wheel && \
|
||||
pacman -Sy --noconfirm --asdeps breezy git mercurial python-aiohttp python-boto3 python-cryptography python-jinja python-requests-unixsocket python-systemd rsync subversion && \
|
||||
runuser -u build -- install-aur-package python-aioauth-client python-aiohttp-apispec-git python-aiohttp-cors \
|
||||
runuser -u build -- install-aur-package python-aioauth-client python-webargs python-aiohttp-apispec-git python-aiohttp-cors \
|
||||
python-aiohttp-jinja2 python-aiohttp-session python-aiohttp-security
|
||||
|
||||
## FIXME since 1.0.4 devtools requires dbus to be run, which doesn't work now in container
|
||||
|
@ -6,7 +6,7 @@ for PACKAGE in "$@"; do
|
||||
BUILD_DIR="$(mktemp -d)"
|
||||
git clone https://aur.archlinux.org/"$PACKAGE".git "$BUILD_DIR"
|
||||
cd "$BUILD_DIR"
|
||||
makepkg --noconfirm --install --rmdeps --syncdeps
|
||||
makepkg --nocheck --noconfirm --install --rmdeps --syncdeps
|
||||
cd /
|
||||
rm -r "$BUILD_DIR"
|
||||
done
|
||||
|
File diff suppressed because it is too large
Load Diff
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.1 MiB |
@ -1,7 +1,7 @@
|
||||
# Maintainer: Evgeniy Alekseev
|
||||
|
||||
pkgname='ahriman'
|
||||
pkgver=2.13.4
|
||||
pkgver=2.13.6
|
||||
pkgrel=1
|
||||
pkgdesc="ArcH linux ReposItory MANager"
|
||||
arch=('any')
|
||||
|
@ -38,10 +38,6 @@
|
||||
<script>
|
||||
const keyImportModal = $("#key-import-modal");
|
||||
const keyImportForm = $("#key-import-form");
|
||||
keyImportModal.on("hidden.bs.modal", () => {
|
||||
keyImportBodyInput.text("");
|
||||
keyImportForm.trigger("reset");
|
||||
});
|
||||
|
||||
const keyImportBodyInput = $("#key-import-body-input");
|
||||
const keyImportCopyButton = $("#key-import-copy-button");
|
||||
@ -90,4 +86,11 @@
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$(() => {
|
||||
keyImportModal.on("hidden.bs.modal", () => {
|
||||
keyImportBodyInput.text("");
|
||||
keyImportForm.trigger("reset");
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
@ -36,9 +36,6 @@
|
||||
<script>
|
||||
const loginModal = $("#login-modal");
|
||||
const loginForm = $("#login-form");
|
||||
loginModal.on("hidden.bs.modal", () => {
|
||||
loginForm.trigger("reset");
|
||||
});
|
||||
|
||||
const loginPasswordInput = $("#login-password");
|
||||
const loginUsernameInput = $("#login-username");
|
||||
@ -77,4 +74,10 @@
|
||||
showHidePasswordButton.addClass("bi-eye");
|
||||
}
|
||||
}
|
||||
|
||||
$(() => {
|
||||
loginModal.on("hidden.bs.modal", () => {
|
||||
loginForm.trigger("reset");
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
@ -43,41 +43,10 @@
|
||||
<script>
|
||||
const packageAddModal = $("#package-add-modal");
|
||||
const packageAddForm = $("#package-add-form");
|
||||
packageAddModal.on("shown.bs.modal", () => {
|
||||
$(`#package-add-repository-input option[value="${repository.architecture}-${repository.repository}"]`).prop("selected", true);
|
||||
});
|
||||
packageAddModal.on("hidden.bs.modal", () => {
|
||||
packageAddVariablesDiv.empty();
|
||||
packageAddForm.trigger("reset");
|
||||
});
|
||||
|
||||
const packageAddInput = $("#package-add-input");
|
||||
const packageAddRepositoryInput = $("#package-add-repository-input");
|
||||
const packageAddKnownPackagesList = $("#package-add-known-packages-dlist");
|
||||
packageAddInput.keyup(() => {
|
||||
clearTimeout(packageAddInput.data("timeout"));
|
||||
packageAddInput.data("timeout", setTimeout($.proxy(() => {
|
||||
const value = packageAddInput.val();
|
||||
|
||||
if (value.length >= 3) {
|
||||
$.ajax({
|
||||
url: "/api/v1/service/search",
|
||||
data: {"for": value},
|
||||
type: "GET",
|
||||
dataType: "json",
|
||||
success: response => {
|
||||
const options = response.map(pkg => {
|
||||
const option = document.createElement("option");
|
||||
option.value = pkg.package;
|
||||
option.innerText = `${pkg.package} (${pkg.description})`;
|
||||
return option;
|
||||
});
|
||||
packageAddKnownPackagesList.empty().append(options);
|
||||
},
|
||||
});
|
||||
}
|
||||
}, this), 500));
|
||||
});
|
||||
|
||||
const packageAddVariablesDiv = $("#package-add-variables-div");
|
||||
|
||||
@ -156,4 +125,39 @@
|
||||
doPackageAction("/api/v1/service/request", [packages], repository, onSuccess, onFailure, patches);
|
||||
}
|
||||
}
|
||||
|
||||
$(() => {
|
||||
packageAddModal.on("shown.bs.modal", () => {
|
||||
$(`#package-add-repository-input option[value="${repository.architecture}-${repository.repository}"]`).prop("selected", true);
|
||||
});
|
||||
packageAddModal.on("hidden.bs.modal", () => {
|
||||
packageAddVariablesDiv.empty();
|
||||
packageAddForm.trigger("reset");
|
||||
});
|
||||
|
||||
packageAddInput.keyup(() => {
|
||||
clearTimeout(packageAddInput.data("timeout"));
|
||||
packageAddInput.data("timeout", setTimeout($.proxy(() => {
|
||||
const value = packageAddInput.val();
|
||||
|
||||
if (value.length >= 3) {
|
||||
$.ajax({
|
||||
url: "/api/v1/service/search",
|
||||
data: {"for": value},
|
||||
type: "GET",
|
||||
dataType: "json",
|
||||
success: response => {
|
||||
const options = response.map(pkg => {
|
||||
const option = document.createElement("option");
|
||||
option.value = pkg.package;
|
||||
option.innerText = `${pkg.package} (${pkg.description})`;
|
||||
return option;
|
||||
});
|
||||
packageAddKnownPackagesList.empty().append(options);
|
||||
},
|
||||
});
|
||||
}
|
||||
}, this), 500));
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
@ -72,26 +72,6 @@
|
||||
const packageInfoModal = $("#package-info-modal");
|
||||
const packageInfoModalHeader = $("#package-info-modal-header");
|
||||
const packageInfo = $("#package-info");
|
||||
packageInfoModal.on("hidden.bs.modal", () => {
|
||||
packageInfoAurUrl.empty();
|
||||
packageInfoDepends.empty();
|
||||
packageInfoGroups.empty();
|
||||
packageInfoLicenses.empty();
|
||||
packageInfoPackager.empty();
|
||||
packageInfoPackages.empty();
|
||||
packageInfoUpstreamUrl.empty();
|
||||
packageInfoVersion.empty();
|
||||
|
||||
packageInfoVariablesBlock.attr("hidden", true);
|
||||
packageInfoVariablesDiv.empty();
|
||||
|
||||
packageInfoLogsInput.empty();
|
||||
packageInfoChangesInput.empty();
|
||||
|
||||
packageInfoModal.trigger("reset");
|
||||
|
||||
hideInfoControls(true);
|
||||
});
|
||||
|
||||
const packageInfoLogsInput = $("#package-info-logs-input");
|
||||
const packageInfoLogsCopyButton = $("#package-info-logs-copy-button");
|
||||
@ -309,4 +289,27 @@
|
||||
|
||||
if (isPackageBaseSet) packageInfoModal.modal("show");
|
||||
}
|
||||
|
||||
$(() => {
|
||||
packageInfoModal.on("hidden.bs.modal", () => {
|
||||
packageInfoAurUrl.empty();
|
||||
packageInfoDepends.empty();
|
||||
packageInfoGroups.empty();
|
||||
packageInfoLicenses.empty();
|
||||
packageInfoPackager.empty();
|
||||
packageInfoPackages.empty();
|
||||
packageInfoUpstreamUrl.empty();
|
||||
packageInfoVersion.empty();
|
||||
|
||||
packageInfoVariablesBlock.attr("hidden", true);
|
||||
packageInfoVariablesDiv.empty();
|
||||
|
||||
packageInfoLogsInput.empty();
|
||||
packageInfoChangesInput.empty();
|
||||
|
||||
packageInfoModal.trigger("reset");
|
||||
|
||||
hideInfoControls(true);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
@ -35,11 +35,6 @@
|
||||
<script>
|
||||
const packageRebuildModal = $("#package-rebuild-modal");
|
||||
const packageRebuildForm = $("#package-rebuild-form");
|
||||
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"); });
|
||||
|
||||
const packageRebuildDependencyInput = $("#package-rebuild-dependency-input");
|
||||
const packageRebuildRepositoryInput = $("#package-rebuild-repository-input");
|
||||
@ -54,4 +49,12 @@
|
||||
doPackageAction("/api/v1/service/rebuild", [packages], repository, onSuccess, onFailure);
|
||||
}
|
||||
}
|
||||
|
||||
$(() => {
|
||||
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"); });
|
||||
});
|
||||
</script>
|
||||
|
@ -9,46 +9,8 @@
|
||||
const packageInfoUpdateButton = $("#package-info-update-button");
|
||||
|
||||
let repository = null;
|
||||
$("#repositories a").on("click", (event) => {
|
||||
const element = event.target;
|
||||
repository = {
|
||||
architecture: element.dataset.architecture,
|
||||
repository: element.dataset.repository,
|
||||
};
|
||||
packageUpdateButton.html(`<i class="bi bi-play"></i> update<span class="d-none d-sm-inline"> ${safe(repository.repository)} (${safe(repository.architecture)})</span>`);
|
||||
$(`#${element.id}`).tab("show");
|
||||
reload();
|
||||
});
|
||||
|
||||
const table = $("#packages");
|
||||
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) => {
|
||||
if (0 === cell || "base" === cell) {
|
||||
const method = data[0] === true ? "uncheckBy" : "checkBy"; // fck javascript
|
||||
table.bootstrapTable(method, {field: "id", values: [data.id]});
|
||||
} else showPackageInfo(data.id);
|
||||
});
|
||||
table.on("created-controls.bs.table", () => {
|
||||
const pickerInput = $(".bootstrap-table-filter-control-timestamp");
|
||||
pickerInput.daterangepicker({
|
||||
autoUpdateInput: false,
|
||||
locale: {
|
||||
cancelLabel: "Clear",
|
||||
},
|
||||
});
|
||||
|
||||
pickerInput.on("apply.daterangepicker", (event, picker) => {
|
||||
pickerInput.val(`${picker.startDate.format("YYYY-MM-DD")} - ${picker.endDate.format("YYYY-MM-DD")}`);
|
||||
table.bootstrapTable("triggerSearch");
|
||||
});
|
||||
|
||||
pickerInput.on("cancel.daterangepicker", () => {
|
||||
pickerInput.val("");
|
||||
table.bootstrapTable("triggerSearch");
|
||||
});
|
||||
});
|
||||
|
||||
const statusBadge = $("#badge-status");
|
||||
const versionBadge = $("#badge-version");
|
||||
@ -221,8 +183,47 @@
|
||||
}
|
||||
|
||||
$(() => {
|
||||
table.bootstrapTable({});
|
||||
$("#repositories a").on("click", event => {
|
||||
const element = event.target;
|
||||
repository = {
|
||||
architecture: element.dataset.architecture,
|
||||
repository: element.dataset.repository,
|
||||
};
|
||||
packageUpdateButton.html(`<i class="bi bi-play"></i> update<span class="d-none d-sm-inline"> ${safe(repository.repository)} (${safe(repository.architecture)})</span>`);
|
||||
$(`#${element.id}`).tab("show");
|
||||
reload();
|
||||
});
|
||||
|
||||
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) => {
|
||||
if (0 === cell || "base" === cell) {
|
||||
const method = data[0] === true ? "uncheckBy" : "checkBy"; // fck javascript
|
||||
table.bootstrapTable(method, {field: "id", values: [data.id]});
|
||||
} else showPackageInfo(data.id);
|
||||
});
|
||||
table.on("created-controls.bs.table", () => {
|
||||
const pickerInput = $(".bootstrap-table-filter-control-timestamp");
|
||||
pickerInput.daterangepicker({
|
||||
autoUpdateInput: false,
|
||||
locale: {
|
||||
cancelLabel: "Clear",
|
||||
},
|
||||
});
|
||||
|
||||
pickerInput.on("apply.daterangepicker", (event, picker) => {
|
||||
pickerInput.val(`${picker.startDate.format("YYYY-MM-DD")} - ${picker.endDate.format("YYYY-MM-DD")}`);
|
||||
table.bootstrapTable("triggerSearch");
|
||||
});
|
||||
|
||||
pickerInput.on("cancel.daterangepicker", () => {
|
||||
pickerInput.val("");
|
||||
table.bootstrapTable("triggerSearch");
|
||||
});
|
||||
});
|
||||
|
||||
statusBadge.popover();
|
||||
selectRepository();
|
||||
});
|
||||
</script>
|
||||
</script>
|
||||
|
@ -102,25 +102,6 @@ SigLevel = Database{% if has_repo_signed %}Required{% else %}Never{% endif %} Pa
|
||||
|
||||
<script>
|
||||
const table = $("#packages");
|
||||
table.on("created-controls.bs.table", () => {
|
||||
const pickerInput = $(".bootstrap-table-filter-control-timestamp");
|
||||
pickerInput.daterangepicker({
|
||||
autoUpdateInput: false,
|
||||
locale: {
|
||||
cancelLabel: "Clear",
|
||||
},
|
||||
});
|
||||
|
||||
pickerInput.on("apply.daterangepicker", (event, picker) => {
|
||||
pickerInput.val(`${picker.startDate.format("YYYY-MM-DD")} - ${picker.endDate.format("YYYY-MM-DD")}`);
|
||||
table.bootstrapTable("triggerSearch");
|
||||
});
|
||||
|
||||
pickerInput.on("cancel.daterangepicker", () => {
|
||||
pickerInput.val("");
|
||||
table.bootstrapTable("triggerSearch");
|
||||
});
|
||||
});
|
||||
|
||||
const pacmanConf = $("#pacman-conf");
|
||||
const pacmanConfCopyButton = $("#copy-btn");
|
||||
@ -141,6 +122,28 @@ SigLevel = Database{% if has_repo_signed %}Required{% else %}Never{% endif %} Pa
|
||||
function filterListLicenses() {
|
||||
return extractDataList(table.bootstrapTable("getData"), "licenses");
|
||||
}
|
||||
|
||||
$(() => {
|
||||
table.on("created-controls.bs.table", () => {
|
||||
const pickerInput = $(".bootstrap-table-filter-control-timestamp");
|
||||
pickerInput.daterangepicker({
|
||||
autoUpdateInput: false,
|
||||
locale: {
|
||||
cancelLabel: "Clear",
|
||||
},
|
||||
});
|
||||
|
||||
pickerInput.on("apply.daterangepicker", (event, picker) => {
|
||||
pickerInput.val(`${picker.startDate.format("YYYY-MM-DD")} - ${picker.endDate.format("YYYY-MM-DD")}`);
|
||||
table.bootstrapTable("triggerSearch");
|
||||
});
|
||||
|
||||
pickerInput.on("cancel.daterangepicker", () => {
|
||||
pickerInput.val("");
|
||||
table.bootstrapTable("triggerSearch");
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<script src="https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js" integrity="sha384-1H217gwSVyLSIfaLxHbE7dRb3v4mYCKbpQvzx0cegeju1MVsGrX5xXxAvs/HgeFs" crossorigin="anonymous" type="application/javascript"></script>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/moment@2.29.4/moment.min.js" integrity="sha384-8hHkOkbWN1TLWwet/jpbJ0zbx3FJDeYJgQ8dX1mRrv/vfCfHCqFSFZYCgaMML3z9" crossorigin="anonymous" type="application/javascript"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/daterangepicker@3.1.0/daterangepicker.min.js" integrity="sha384-u4eJN1VWrTf/FnYYQJo2kqJyVxEQf5UmWY4iUcNAoLenOEtEuCkfwc5bKvZOWBi5" crossorigin="anonymous" type="application/javascript"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/moment@2.29.4/moment.min.js" integrity="sha384-4ZTAzTbfB8H7hkWtXbyNDzDvxirmBT7EmURIvfOJ3Foympc+OD9p+bZNNENaJXgW" crossorigin="anonymous" type="application/javascript"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/daterangepicker@3.1.0/daterangepicker.min.js" integrity="sha384-Gn1XZMJEKL3ycoWq97jYAl+FP3vXQYE2ObBgzgcPMKOZdUZdF6ZuyUxbGC2bAnUT" crossorigin="anonymous" type="application/javascript"></script>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/tableexport.jquery.plugin@1.28.0/tableExport.min.js" integrity="sha384-1Rz4Kz/y1rSWw+ZsjTcxB684XgofbO8iizY+UFIzCwFeQ+QUyhBNWBMh/STOyomI" crossorigin="anonymous" type="application/javascript"></script>
|
||||
|
||||
|
@ -596,7 +596,7 @@ _set_new_action() {
|
||||
current_action_nargs=1
|
||||
fi
|
||||
|
||||
current_action_args_start_index=$(( $word_index + 1 ))
|
||||
current_action_args_start_index=$(( $word_index + 1 - $pos_only ))
|
||||
|
||||
current_action_is_positional=$2
|
||||
}
|
||||
@ -623,6 +623,7 @@ _shtab_ahriman() {
|
||||
|
||||
local prefix=_shtab_ahriman
|
||||
local word_index=0
|
||||
local pos_only=0 # "--" delimeter not encountered yet
|
||||
_set_parser_defaults
|
||||
word_index=1
|
||||
|
||||
@ -631,26 +632,30 @@ _shtab_ahriman() {
|
||||
while [ $word_index -ne $COMP_CWORD ]; do
|
||||
local this_word="${COMP_WORDS[$word_index]}"
|
||||
|
||||
if [[ -n $sub_parsers && " ${sub_parsers[@]} " == *" ${this_word} "* ]]; then
|
||||
# valid subcommand: add it to the prefix & reset the current action
|
||||
prefix="${prefix}_$(_shtab_replace_nonword $this_word)"
|
||||
_set_parser_defaults
|
||||
fi
|
||||
if [[ $pos_only = 1 || " $this_word " != " -- " ]]; then
|
||||
if [[ -n $sub_parsers && " ${sub_parsers[@]} " == *" ${this_word} "* ]]; then
|
||||
# valid subcommand: add it to the prefix & reset the current action
|
||||
prefix="${prefix}_$(_shtab_replace_nonword $this_word)"
|
||||
_set_parser_defaults
|
||||
fi
|
||||
|
||||
if [[ " ${current_option_strings[@]} " == *" ${this_word} "* ]]; then
|
||||
# a new action should be acquired (due to recognised option string or
|
||||
# no more input expected from current action);
|
||||
# the next positional action can fill in here
|
||||
_set_new_action $this_word false
|
||||
fi
|
||||
if [[ " ${current_option_strings[@]} " == *" ${this_word} "* ]]; then
|
||||
# a new action should be acquired (due to recognised option string or
|
||||
# no more input expected from current action);
|
||||
# the next positional action can fill in here
|
||||
_set_new_action $this_word false
|
||||
fi
|
||||
|
||||
if [[ "$current_action_nargs" != "*" ]] && \
|
||||
[[ "$current_action_nargs" != "+" ]] && \
|
||||
[[ "$current_action_nargs" != *"..." ]] && \
|
||||
(( $word_index + 1 - $current_action_args_start_index >= \
|
||||
$current_action_nargs )); then
|
||||
$current_action_is_positional && let "completed_positional_actions += 1"
|
||||
_set_new_action "pos_${completed_positional_actions}" true
|
||||
if [[ "$current_action_nargs" != "*" ]] && \
|
||||
[[ "$current_action_nargs" != "+" ]] && \
|
||||
[[ "$current_action_nargs" != *"..." ]] && \
|
||||
(( $word_index + 1 - $current_action_args_start_index - $pos_only >= \
|
||||
$current_action_nargs )); then
|
||||
$current_action_is_positional && let "completed_positional_actions += 1"
|
||||
_set_new_action "pos_${completed_positional_actions}" true
|
||||
fi
|
||||
else
|
||||
pos_only=1 # "--" delimeter encountered
|
||||
fi
|
||||
|
||||
let "word_index+=1"
|
||||
@ -658,7 +663,7 @@ _shtab_ahriman() {
|
||||
|
||||
# Generate the completions
|
||||
|
||||
if [[ "${completing_word}" == -* ]]; then
|
||||
if [[ $pos_only = 0 && "${completing_word}" == -* ]]; then
|
||||
# optional argument started: use option strings
|
||||
COMPREPLY=( $(compgen -W "${current_option_strings[*]}" -- "${completing_word}") )
|
||||
else
|
||||
|
@ -1,4 +1,4 @@
|
||||
.TH AHRIMAN "1" "2024\-02\-10" "ahriman" "Generated Python Manual"
|
||||
.TH AHRIMAN "1" "2024\-05\-05" "ahriman" "Generated Python Manual"
|
||||
.SH NAME
|
||||
ahriman
|
||||
.SH SYNOPSIS
|
||||
|
@ -742,4 +742,12 @@ _shtab_ahriman() {
|
||||
|
||||
|
||||
typeset -A opt_args
|
||||
_shtab_ahriman "$@"
|
||||
|
||||
if [[ $zsh_eval_context[-1] == eval ]]; then
|
||||
# eval/source/. command, register function for later
|
||||
compdef _shtab_ahriman -N ahriman
|
||||
else
|
||||
# autoload from fpath, call function directly
|
||||
_shtab_ahriman "$@"
|
||||
fi
|
||||
|
||||
|
@ -82,6 +82,7 @@ web = [
|
||||
"aiohttp_security",
|
||||
"cryptography",
|
||||
"requests-unixsocket", # required by unix socket support
|
||||
"setuptools", # required by aiohttp-apispec
|
||||
]
|
||||
|
||||
[tool.flit.sdist]
|
||||
|
@ -17,4 +17,4 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
__version__ = "2.13.4"
|
||||
__version__ = "2.13.6"
|
||||
|
@ -68,7 +68,7 @@ class Repo(LazyLogging):
|
||||
path(Path): path to archive to add
|
||||
"""
|
||||
check_output(
|
||||
"repo-add", *self.sign_args, "-R", str(self.repo_path), str(path),
|
||||
"repo-add", *self.sign_args, "--remove", str(self.repo_path), str(path),
|
||||
exception=BuildError.from_process(path.name),
|
||||
cwd=self.paths.repository,
|
||||
logger=self.logger,
|
||||
@ -78,8 +78,13 @@ class Repo(LazyLogging):
|
||||
"""
|
||||
create empty repository database. It just calls add with empty arguments
|
||||
"""
|
||||
check_output("repo-add", *self.sign_args, str(self.repo_path),
|
||||
cwd=self.paths.repository, logger=self.logger, user=self.uid)
|
||||
# since pacman-6.1.0 repo-add doesn't create empty database in case if no packages supplied
|
||||
# this code creates empty files instead
|
||||
if self.repo_path.exists():
|
||||
return # database is already created, skip this part
|
||||
|
||||
self.repo_path.touch(exist_ok=True)
|
||||
(self.paths.repository / f"{self.name}.db").symlink_to(self.repo_path)
|
||||
|
||||
def remove(self, package: str, filename: Path) -> None:
|
||||
"""
|
||||
|
@ -69,7 +69,8 @@ class OAuth(Mapping):
|
||||
Returns:
|
||||
str: login control as html code to insert
|
||||
"""
|
||||
return f"""<a class="nav-link" href="/api/v1/login" title="login via OAuth2"><i class="bi bi-{self.icon}"></i> login</a>"""
|
||||
return f"""<a class="nav-link" href="/api/v1/login" title="login via OAuth2"><i class="bi bi-{
|
||||
self.icon}"></i> login</a>"""
|
||||
|
||||
@staticmethod
|
||||
def get_provider(name: str) -> type[aioauth_client.OAuth2Client]:
|
||||
|
@ -345,5 +345,5 @@ class UnsafeRunError(RuntimeError):
|
||||
root_uid(int): ID of the owner of root directory
|
||||
"""
|
||||
RuntimeError.__init__(self, f"Current UID {current_uid} differs from root owner {root_uid}. "
|
||||
f"Note that for the most actions it is unsafe to run application as different user."
|
||||
f" If you are 100% sure that it must be there try --unsafe option")
|
||||
f"Note that for the most actions it is unsafe to run application as different user."
|
||||
f" If you are 100% sure that it must be there try --unsafe option")
|
||||
|
@ -106,7 +106,7 @@ class RemoteCall(Report):
|
||||
"aur": self.update_aur,
|
||||
"local": self.update_local,
|
||||
"manual": self.update_manual,
|
||||
})
|
||||
})
|
||||
response_json = response.json()
|
||||
|
||||
process_id: str = response_json["process_id"]
|
||||
|
@ -119,7 +119,8 @@ class Executor(PackageInfo, Cleaner):
|
||||
|
||||
# build package list based on user input
|
||||
result = Result()
|
||||
requested = set(packages)
|
||||
packages = set(packages) # remove duplicates
|
||||
requested = packages | {f"{package}-debug" for package in packages} # append debug packages
|
||||
for local in self.packages():
|
||||
if local.base in packages or all(package in requested for package in local.packages):
|
||||
packages_to_remove.update({
|
||||
@ -138,7 +139,7 @@ class Executor(PackageInfo, Cleaner):
|
||||
|
||||
# check for packages which were requested to remove, but weren't found locally
|
||||
# it might happen for example, if there were no success build before
|
||||
for unknown in requested:
|
||||
for unknown in packages:
|
||||
if unknown in packages_to_remove or unknown in bases_to_remove:
|
||||
continue
|
||||
bases_to_remove.append(unknown)
|
||||
|
@ -183,11 +183,12 @@ post_install() {{
|
||||
Returns:
|
||||
str: package() function for PKGBUILD
|
||||
"""
|
||||
# somehow autopep thinks that construction inside contains valid python code and reformats it
|
||||
return f"""{{
|
||||
install -Dm644 "{Path("$srcdir") / f"{self.name}.gpg"}" "{Path("$pkgdir") / "usr" / "share" / "pacman" / "keyrings" / f"{self.name}.gpg"}"
|
||||
install -Dm644 "{Path("$srcdir") / f"{self.name}-revoked"}" "{Path("$pkgdir") / "usr" / "share" / "pacman" / "keyrings" / f"{self.name}-revoked"}"
|
||||
install -Dm644 "{Path("$srcdir") / f"{self.name}-trusted"}" "{Path("$pkgdir") / "usr" / "share" / "pacman" / "keyrings" / f"{self.name}-trusted"}"
|
||||
}}"""
|
||||
}}""" # nopep8
|
||||
|
||||
def sources(self) -> dict[str, Callable[[Path], None]]:
|
||||
"""
|
||||
|
@ -162,7 +162,8 @@ class GitHub(Upload, HttpUpload):
|
||||
Returns:
|
||||
dict[str, Any] | None: GitHub API release object if release found and None otherwise
|
||||
"""
|
||||
url = f"https://api.github.com/repos/{self.github_owner}/{self.github_repository}/releases/tags/{self.github_release_tag}"
|
||||
url = f"https://api.github.com/repos/{self.github_owner}/{
|
||||
self.github_repository}/releases/tags/{self.github_release_tag}"
|
||||
try:
|
||||
response = self.make_request("GET", url)
|
||||
release: dict[str, Any] = response.json()
|
||||
|
@ -349,7 +349,7 @@ def pretty_datetime(timestamp: datetime.datetime | float | int | None) -> str:
|
||||
if timestamp is None:
|
||||
return ""
|
||||
if isinstance(timestamp, (int, float)):
|
||||
timestamp = datetime.datetime.utcfromtimestamp(timestamp)
|
||||
timestamp = datetime.datetime.fromtimestamp(timestamp, datetime.UTC)
|
||||
return timestamp.strftime("%Y-%m-%d %H:%M:%S")
|
||||
|
||||
|
||||
@ -505,7 +505,7 @@ def utcnow() -> datetime.datetime:
|
||||
Returns:
|
||||
datetime.datetime: current time in UTC
|
||||
"""
|
||||
return datetime.datetime.utcnow()
|
||||
return datetime.datetime.now(datetime.UTC)
|
||||
|
||||
|
||||
def walk(directory_path: Path) -> Generator[Path, None, None]:
|
||||
|
@ -137,8 +137,8 @@ class AURPackage:
|
||||
description=package.desc,
|
||||
num_votes=0,
|
||||
popularity=0.0,
|
||||
first_submitted=datetime.datetime.utcfromtimestamp(0),
|
||||
last_modified=datetime.datetime.utcfromtimestamp(package.builddate),
|
||||
first_submitted=datetime.datetime.fromtimestamp(0, datetime.UTC),
|
||||
last_modified=datetime.datetime.fromtimestamp(package.builddate, datetime.UTC),
|
||||
url_path="",
|
||||
url=package.url,
|
||||
out_of_date=None,
|
||||
@ -175,13 +175,11 @@ class AURPackage:
|
||||
description=dump["pkgdesc"],
|
||||
num_votes=0,
|
||||
popularity=0.0,
|
||||
first_submitted=datetime.datetime.utcfromtimestamp(0),
|
||||
last_modified=datetime.datetime.strptime(dump["last_update"], "%Y-%m-%dT%H:%M:%S.%fZ"),
|
||||
first_submitted=datetime.datetime.fromtimestamp(0, datetime.UTC),
|
||||
last_modified=datetime.datetime.fromisoformat(dump["last_update"]),
|
||||
url_path="",
|
||||
url=dump["url"],
|
||||
out_of_date=datetime.datetime.strptime(
|
||||
dump["flag_date"],
|
||||
"%Y-%m-%dT%H:%M:%S.%fZ") if dump["flag_date"] is not None else None,
|
||||
out_of_date=datetime.datetime.fromisoformat(dump["flag_date"]) if dump.get("flag_date") else None,
|
||||
maintainer=next(iter(dump["maintainers"]), None),
|
||||
submitter=None,
|
||||
repository=dump["repo"],
|
||||
@ -208,9 +206,9 @@ class AURPackage:
|
||||
"""
|
||||
identity_mapper: Callable[[Any], Any] = lambda value: value
|
||||
value_mapper: dict[str, Callable[[Any], Any]] = {
|
||||
"out_of_date": lambda value: datetime.datetime.utcfromtimestamp(value) if value is not None else None,
|
||||
"first_submitted": datetime.datetime.utcfromtimestamp,
|
||||
"last_modified": datetime.datetime.utcfromtimestamp,
|
||||
"out_of_date": lambda value: datetime.datetime.fromtimestamp(value, datetime.UTC) if value is not None else None,
|
||||
"first_submitted": lambda value: datetime.datetime.fromtimestamp(value, datetime.UTC),
|
||||
"last_modified": lambda value: datetime.datetime.fromtimestamp(value, datetime.UTC),
|
||||
}
|
||||
|
||||
result: dict[str, Any] = {}
|
||||
|
@ -18,8 +18,8 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from dataclasses import dataclass
|
||||
from elftools.elf.dynamic import DynamicSection # type: ignore[import-untyped]
|
||||
from elftools.elf.elffile import ELFFile # type: ignore[import-untyped]
|
||||
from elftools.elf.dynamic import DynamicSection
|
||||
from elftools.elf.elffile import ELFFile
|
||||
from pathlib import Path
|
||||
from typing import IO
|
||||
|
||||
@ -57,13 +57,19 @@ class PackageArchive:
|
||||
if not PackageArchive.is_elf(binary_file):
|
||||
return []
|
||||
|
||||
elf_file = ELFFile(binary_file)
|
||||
elf_file = ELFFile(binary_file) # type: ignore[no-untyped-call]
|
||||
dynamic_section = next(
|
||||
(section for section in elf_file.iter_sections() if isinstance(section, DynamicSection)), None)
|
||||
(section for section in elf_file.iter_sections() # type: ignore[no-untyped-call]
|
||||
if isinstance(section, DynamicSection)),
|
||||
None)
|
||||
if dynamic_section is None:
|
||||
return []
|
||||
|
||||
return [tag.needed for tag in dynamic_section.iter_tags() if tag.entry.d_tag == "DT_NEEDED"]
|
||||
return [
|
||||
tag.needed
|
||||
for tag in dynamic_section.iter_tags() # type: ignore[no-untyped-call]
|
||||
if tag.entry.d_tag == "DT_NEEDED"
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
def is_elf(content: IO[bytes]) -> bool:
|
||||
|
@ -133,8 +133,8 @@ def aur_package_ahriman() -> AURPackage:
|
||||
description="ArcH linux ReposItory MANager",
|
||||
num_votes=0,
|
||||
popularity=0,
|
||||
first_submitted=datetime.datetime.utcfromtimestamp(1618008285),
|
||||
last_modified=datetime.datetime.utcfromtimestamp(1673826351),
|
||||
first_submitted=datetime.datetime.fromtimestamp(1618008285, datetime.UTC),
|
||||
last_modified=datetime.datetime.fromtimestamp(1673826351, datetime.UTC),
|
||||
url_path="/cgit/aur.git/snapshot/ahriman.tar.gz",
|
||||
url="https://github.com/arcan1s/ahriman",
|
||||
out_of_date=None,
|
||||
@ -200,8 +200,8 @@ def aur_package_akonadi() -> AURPackage:
|
||||
description="PIM layer, which provides an asynchronous API to access all kind of PIM data",
|
||||
num_votes=0,
|
||||
popularity=0.0,
|
||||
first_submitted=datetime.datetime.utcfromtimestamp(0),
|
||||
last_modified=datetime.datetime.utcfromtimestamp(1646555990.610),
|
||||
first_submitted=datetime.datetime.fromtimestamp(0, datetime.UTC),
|
||||
last_modified=datetime.datetime.fromtimestamp(1646555990.610, datetime.UTC),
|
||||
url_path="",
|
||||
url="https://kontact.kde.org",
|
||||
out_of_date=None,
|
||||
|
@ -26,13 +26,28 @@ def test_repo_add(repo: Repo, mocker: MockerFixture) -> None:
|
||||
|
||||
def test_repo_init(repo: Repo, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must call repo-add with empty package list on repo initializing
|
||||
must create empty database files
|
||||
"""
|
||||
check_output_mock = mocker.patch("ahriman.core.alpm.repo.check_output")
|
||||
mocker.patch("pathlib.Path.exists", return_value=False)
|
||||
touch_mock = mocker.patch("pathlib.Path.touch")
|
||||
symlink_mock = mocker.patch("pathlib.Path.symlink_to")
|
||||
|
||||
repo.init()
|
||||
check_output_mock.assert_called_once() # it will be checked later
|
||||
assert check_output_mock.call_args[0][0] == "repo-add"
|
||||
touch_mock.assert_called_once_with(exist_ok=True)
|
||||
symlink_mock.assert_called_once_with(repo.repo_path)
|
||||
|
||||
|
||||
def test_repo_init_skip(repo: Repo, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must do not create files if database already exists
|
||||
"""
|
||||
mocker.patch("pathlib.Path.exists", return_value=True)
|
||||
touch_mock = mocker.patch("pathlib.Path.touch")
|
||||
symlink_mock = mocker.patch("pathlib.Path.symlink_to")
|
||||
|
||||
repo.init()
|
||||
touch_mock.assert_not_called()
|
||||
symlink_mock.assert_not_called()
|
||||
|
||||
|
||||
def test_repo_remove(repo: Repo, mocker: MockerFixture) -> None:
|
||||
|
@ -85,7 +85,7 @@ def test_remote_update(remote_call: RemoteCall, mocker: MockerFixture) -> None:
|
||||
"aur": False,
|
||||
"local": False,
|
||||
"manual": True,
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
def test_remote_wait(remote_call: RemoteCall, mocker: MockerFixture) -> None:
|
||||
|
@ -92,6 +92,28 @@ def test_process_remove_base(executor: Executor, package_ahriman: Package, mocke
|
||||
status_client_mock.assert_called_once_with(package_ahriman.base)
|
||||
|
||||
|
||||
def test_process_remove_with_debug(executor: Executor, package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run remove debug packages too
|
||||
"""
|
||||
package_ahriman.packages = {
|
||||
package_ahriman.base: package_ahriman.packages[package_ahriman.base],
|
||||
f"{package_ahriman.base}-debug": package_ahriman.packages[package_ahriman.base],
|
||||
}
|
||||
mocker.patch("ahriman.core.repository.executor.Executor.packages", return_value=[package_ahriman])
|
||||
mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_clear")
|
||||
mocker.patch("ahriman.core.database.SQLite.package_clear")
|
||||
mocker.patch("ahriman.core.status.client.Client.package_remove")
|
||||
repo_remove_mock = mocker.patch("ahriman.core.alpm.repo.Repo.remove")
|
||||
|
||||
executor.process_remove([package_ahriman.base])
|
||||
# must remove via alpm wrapper
|
||||
repo_remove_mock.assert_has_calls([
|
||||
MockCall(package_ahriman.base, package_ahriman.packages[package_ahriman.base].filepath),
|
||||
MockCall(f"{package_ahriman.base}-debug", package_ahriman.packages[package_ahriman.base].filepath),
|
||||
])
|
||||
|
||||
|
||||
def test_process_remove_base_multiple(executor: Executor, package_python_schedule: Package,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
|
@ -6,7 +6,6 @@ from pytest_mock import MockerFixture
|
||||
from unittest.mock import MagicMock, call as MockCall
|
||||
|
||||
from ahriman.core.support.pkgbuild.pkgbuild_generator import PkgbuildGenerator
|
||||
from ahriman.core.util import utcnow
|
||||
from ahriman.models.pkgbuild_patch import PkgbuildPatch
|
||||
|
||||
|
||||
@ -38,7 +37,7 @@ def test_pkgver(pkgbuild_generator: PkgbuildGenerator, mocker: MockerFixture) ->
|
||||
must implement default version as current date
|
||||
"""
|
||||
mocker.patch("ahriman.core.support.pkgbuild.pkgbuild_generator.utcnow", return_value=datetime.datetime(2002, 3, 11))
|
||||
assert pkgbuild_generator.pkgver == utcnow().strftime("20020311")
|
||||
assert pkgbuild_generator.pkgver == "20020311"
|
||||
|
||||
|
||||
def test_url(pkgbuild_generator: PkgbuildGenerator) -> None:
|
||||
|
Loading…
x
Reference in New Issue
Block a user