fordon_greeman / pkger

feat: support more than just git, guix pkg test, port bs from c to shell Browse files
theidioticdev committed 18d ago parent bee1393 commit c2d1d359152c9157bfcbd2edbedc0f91314b1b0a
Showing 8 changed files with 1403 additions and 253 deletions. UnifiedSplit
+5 −0 TODO new file mode 100644
@@ -0,0 +1,5 @@
1 +TODO:
2 + - ✔ bug fix @done 2026-10-19
3 + - ✔ rename slpkger -> pkger @done 2026-10-19
4 + - ✔ test @done 2026-10-19
5 + - □ add more pkgs out of the box
+0 −99 bs.c deleted file mode 100644
@@ -1,99 +0,0 @@
1 -#include <stdio.h>
2 -#include <unistd.h>
3 -#include <sys/wait.h>
4 -#include <stdlib.h>
5 -#include <string.h>
6 -
7 -#define CC "cc"
8 -#define PROG_NAME "slpkger"
9 -#define DEST "/home/fordon/local/bin"
10 -
11 -/* helper fn for running commands via execvp */
12 -int
13 -runCmd (char *const argv[])
14 -{
15 - pid_t pid = fork();
16 - if (pid == 0)
17 - {
18 - execvp(argv[0], argv);
19 - perror("execvp failed");
20 - _exit(1);
21 - } else if (pid > 0) {
22 - int status;
23 - waitpid(pid, &status, 0);
24 - return WIFEXITED(status) && WEXITSTATUS(status) == 0;
25 - }
26 - return 0;
27 -}
28 -
29 -/* build fn */
30 -int
31 -build (void)
32 -{
33 - char *const buildCmd[] = {
34 - CC, "-Wall", "-Wextra", "slpkger.c", "-o", PROG_NAME, NULL
35 - };
36 -
37 - printf ("[BUILD]: " CC " -Wall -Wextra slpkger.c -o %s\n", PROG_NAME);
38 - if (!runCmd (buildCmd))
39 - {
40 - fprintf (stderr, "[ERROR]: compilation failed\n");
41 - return 0;
42 - }
43 - printf ("[SUCCESS]: compiled successfully\n");
44 - return 1;
45 -}
46 -/* install fn */
47 -int
48 -install (void)
49 -{
50 - if (!build ())
51 - return 0;
52 -
53 - char *const installCmd[] = {
54 - "cp", PROG_NAME, DEST "/" PROG_NAME, NULL
55 - };
56 -
57 - printf ("[INSTALL]: cp %s %s/%s\n", PROG_NAME, DEST, PROG_NAME);
58 - if (!runCmd (installCmd))
59 - {
60 - fprintf (stderr, "[ERROR]: install failed\n");
61 - return 0;
62 - }
63 - printf ("[SUCCESS]: installed successfully\n");
64 - return 1;
65 -}
66 -
67 -/* uninstall fn */
68 -int
69 -uninstall (void)
70 -{
71 - if (remove(DEST "/" PROG_NAME) != 0)
72 - {
73 - fprintf(stderr, "[ERROR]: uninstall failed.\n");
74 - return 0;
75 - }
76 - printf("[SUCCESS]: uninstalled successfully\n");
77 - return 1;
78 -}
79 -
80 -int
81 -main (int argc, char **argv)
82 -{
83 - if (argc < 2 || strcmp(argv[1], "--build-only") == 0)
84 - {
85 - return build() ? 0 : 1;
86 - }
87 -
88 - if (strcmp(argv[1], "--install") == 0)
89 - {
90 - return install() ? 0 : 1;
91 - }
92 -
93 - if (strcmp(argv[1], "--uninstall") == 0)
94 - {
95 - return uninstall() ? 0 : 1;
96 - }
97 - fprintf(stderr, "Unknown argument: %s\n", argv[1]);
98 - return 1;
99 -}
+51 −0 bs.sh new file mode 100755
@@ -0,0 +1,51 @@
1 +#!/bin/sh
2 +
3 +#: [ bs.sh ] BUILD SYSTEM in POSIX SHELL
4 +#: usage:
5 +#: ./bs.sh [build|install|clean|uninstall]
6 +#: ./bs.sh -h
7 +#:
8 +
9 +SRC=$(cd "$(dirname "$0")" && pwd)
10 +TARGET="$HOME/.local/bin"
11 +BUILD_CMD="cc -o pkger pkger.c"
12 +INSTALL_CMD="cp pkger $TARGET/pkger"
13 +UNINSTALL_CMD="rm $TARGET/pkger"
14 +
15 +build() {
16 + printf "[BUILD] $BUILD_CMD\n"
17 + $BUILD_CMD
18 + printf "[BUILD] done\n"
19 +}
20 +ins() {
21 + if [ -f "$SRC/pkger" ]; then
22 + printf "[INSTALL] $INSTALL_CMD\n"
23 + $INSTALL_CMD
24 + printf "[INSTALL] done\n"
25 + else
26 + build
27 + printf "[INSTALL] $INSTALL_CMD\n"
28 + $INSTALL_CMD
29 + printf "[INSTALL] done\n"
30 + fi
31 +}
32 +
33 +clean() {
34 + printf "[CLEAN] rm pkger\n"
35 + rm pkger
36 + printf "[CLEAN] done\n"
37 +}
38 +
39 +unins() {
40 + printf "[UNINST] $UNINSTALL_CMD\n"
41 + $UNINSTALL_CMD
42 + printf "[UNINST] done\n"
43 +}
44 +case "$1" in
45 + install) ins ;;
46 + uninstall) unins ;;
47 + build) build ;;
48 + -h) sed -n 's/^#: //p' "$0" ;;
49 + clean) clean ;;
50 + *) printf "Invalid opt\n"; exit 1 ;;
51 +esac
+1152 −0 install.sh new file mode 100755 Large diff collapsed, click to expand
@@ -0,0 +1,1152 @@
1 +#!/bin/sh
2 +# GNU Guix --- Functional package management for GNU
3 +# Copyright © 2017 sharlatan <sharlatanus@gmail.com>
4 +# Copyright © 2018 Ricardo Wurmus <rekado@elephly.net>
5 +# Copyright © 2018 Efraim Flashner <efraim@flashner.co.il>
6 +# Copyright © 2019–2020, 2022 Tobias Geerinckx-Rice <me@tobias.gr>
7 +# Copyright © 2020 Morgan Smith <Morgan.J.Smith@outlook.com>
8 +# Copyright © 2020 Simon Tournier <zimon.toutoune@gmail.com>
9 +# Copyright © 2020 Daniel Brooks <db48x@db48x.net>
10 +# Copyright © 2021 Jakub Kądziołka <kuba@kadziolka.net>
11 +# Copyright © 2021 Chris Marusich <cmmarusich@gmail.com>
12 +# Copyright © 2021, 2022, 2023 Maxim Cournoyer <maxim@guixotic.coop>
13 +# Copyright © 2022 Prafulla Giri <prafulla.giri@protonmail.com>
14 +# Copyright © 2023 Andrew Tropin <andrew@trop.in>
15 +# Copyright © 2020 David A. Redick <david.a.redick@gmail.com>
16 +# Copyright © 2024 Janneke Nieuwenhuizen <janneke@gnu.org>
17 +# Copyright © 2024 Tomas Volf <~@wolfsden.cz>
18 +# Copyright © 2024 Richard Sent <richard@freakingpenguin.com>
19 +# Copyright © 2025 Denis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org>
20 +# Copyright © 2025 Noé Lopez <noelopez@free.fr>
21 +# Copyright © 2026 Owen T. Heisler <writer@owenh.net>
22 +#
23 +# This file is part of GNU Guix.
24 +#
25 +# GNU Guix is free software; you can redistribute it and/or modify it
26 +# under the terms of the GNU General Public License as published by
27 +# the Free Software Foundation; either version 3 of the License, or (at
28 +# your option) any later version.
29 +#
30 +# GNU Guix is distributed in the hope that it will be useful, but
31 +# WITHOUT ANY WARRANTY; without even the implied warranty of
32 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 +# GNU General Public License for more details.
34 +#
35 +# You should have received a copy of the GNU General Public License
36 +# along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
37 +
38 +# We require Bash but for portability we'd rather not use /bin/bash or
39 +# /usr/bin/env in the shebang, hence this hack.
40 +
41 +# Environment variables
42 +#
43 +# GUIX_BINARY_FILE_NAME
44 +#
45 +# Can be used to override the automatic download mechanism and point
46 +# to a local Guix binary archive filename like
47 +# "/tmp/guix-binary-1.4.0rc2.armhf-linux.tar.xz"
48 +#
49 +# GUIX_ALLOW_OVERWRITE
50 +#
51 +# Instead of aborting to avoid overwriting a previous installations,
52 +# allow copying over /var/guix or /gnu. This can be useful when the
53 +# installation required the user to extract Guix packs under /gnu to
54 +# satisfy its dependencies.
55 +
56 +# shellcheck shell=bash
57 +
58 +# shellcheck disable=2268 # try to support vintage shells
59 +if [ "x$BASH_VERSION" = "x" ]; then
60 + exec bash "$0" "$@"
61 +fi
62 +
63 +set -eo pipefail
64 +
65 +[ "$UID" -eq 0 ] || { echo "This script must be run as root."; exit 1; }
66 +
67 +REQUIRE=(
68 + "dirname"
69 + "readlink"
70 + "wget"
71 + "gpg"
72 + "grep"
73 + "sed"
74 + "sort"
75 + "getent"
76 + "mktemp"
77 + "rm"
78 + "chmod"
79 + "uname"
80 + "groupadd"
81 + "groupdel"
82 + "useradd"
83 + "userdel"
84 + "tail"
85 + "tr"
86 + "xz"
87 +)
88 +
89 +# Add variables using form FOO_INIT_REQUIRE when init system FOO dependencies
90 +# should be checked.
91 +# shellcheck disable=2034 # interpolated by add_init_sys_require
92 +SYSV_INIT_REQUIRE=(
93 + "daemonize"
94 +)
95 +
96 +# Unprivileged guix-daemon requires 'newgidmap'.
97 +SYSTEMD_REQUIRE=(
98 + "newgidmap"
99 +)
100 +
101 +PAS=$'[ \033[32;1mPASS\033[0m ] '
102 +ERR=$'[ \033[31;1mFAIL\033[0m ] '
103 +WAR=$'[ \033[33;1mWARN\033[0m ] '
104 +INF="[ INFO ] "
105 +
106 +DEBUG=0
107 +GNU_URL="https://ftp.gnu.org/gnu/guix/"
108 +
109 +# The following associative array holds set of GPG keys used to sign the
110 +# releases, keyed by their corresponding Codeberg user name.
111 +declare -A GPG_SIGNING_KEYS
112 +GPG_SIGNING_KEYS["civodul"]=3CE464558A84FDC69DB40CFB090B11993D9AEBB5 # ludo
113 +GPG_SIGNING_KEYS["apteryx"]=27D586A4F8900854329FF09F1260E46482E63562 # maxim
114 +GPG_SIGNING_KEYS["efraim"]=A28BF40C3E551372662D14F741AAE7DCCA3D8351 # efraim
115 +PUBLIC_KEYSERVERS="keys.openpgp.org pgpkeys.eu keyserver.ubuntu.com"
116 +
117 +# ------------------------------------------------------------------------------
118 +#+UTILITIES
119 +
120 +_err()
121 +{ # All errors go to stderr.
122 + printf "[%s]: ${ERR}%s\n" "$(date +%s.%3N)" "$1"
123 +}
124 +
125 +_msg()
126 +{ # Default message to stdout.
127 + printf "[%s]: %s\n" "$(date +%s.%3N)" "$1"
128 +}
129 +
130 +_msg_pass()
131 +{
132 + _msg "$PAS$1"
133 +}
134 +
135 +_msg_warn()
136 +{
137 + _msg "$WAR$1"
138 +}
139 +
140 +_msg_info()
141 +{
142 + _msg "$INF$1"
143 +}
144 +
145 +_debug()
146 +{
147 + if [ "${DEBUG}" = '1' ]; then
148 + printf "[%s]: %s\n" "$(date +%s.%3N)" "$1"
149 + fi
150 +}
151 +
152 +die()
153 +{
154 + _err "$*"
155 + exit 1
156 +}
157 +
158 +# Return true if user answered yes, false otherwise. The prompt is
159 +# yes-biased, that is, when the user simply enter newline, it is equivalent to
160 +# answering "yes".
161 +# $1: The prompt question.
162 +prompt_yes_no() {
163 + local -l yn
164 + read -rp "$1 [Y/n]" yn
165 + [[ ! $yn || $yn = y || $yn = yes ]] || return 1
166 +}
167 +
168 +chk_require()
169 +{ # Check that every required command is available.
170 + declare -a warn
171 + local c
172 +
173 + _debug "--- [ ${FUNCNAME[0]} ] ---"
174 +
175 + for c in "$@"; do
176 + command -v "$c" &>/dev/null || warn+=("$c")
177 + done
178 +
179 + [ "${#warn}" -ne 0 ] && die "Missing commands: ${warn[*]}."
180 +
181 + _msg_pass "verification of required commands completed"
182 +}
183 +
184 +add_init_sys_require()
185 +{ # Add the elements of FOO_INIT_SYS to REQUIRE
186 +
187 + # Convert the init system command name captured in INIT_SYS in
188 + # chk_init_sys to uppercase, with hyphens replaced by underscores.
189 + local init_require=${INIT_SYS^^}_REQUIRE[@]
190 + init_require=${init_require//-/_}
191 +
192 + if [[ -n "$init_require" ]]; then
193 + # Have to add piecemeal because ${!foo[@]} performs direct array key
194 + # expansion, not indirect plain array expansion.
195 + for r in "${!init_require}"; do
196 + REQUIRE+=("$r")
197 + done
198 + fi
199 +}
200 +
201 +chk_gpg_keyring()
202 +{ # Check whether the Guix release signing public key is present.
203 + _debug "--- [ ${FUNCNAME[0]} ] ---"
204 + local user_id
205 + local gpg_key_id
206 + local exit_flag
207 +
208 + for user_id in "${!GPG_SIGNING_KEYS[@]}"; do
209 + gpg_key_id=${GPG_SIGNING_KEYS[$user_id]}
210 + codeberg_username=$user_id
211 + # Without --dry-run this command will create a ~/.gnupg owned by root on
212 + # systems where gpg has never been used, causing errors and confusion.
213 + if gpg --dry-run --list-keys "$gpg_key_id" >/dev/null 2>&1; then
214 + continue
215 + fi
216 + if prompt_yes_no "${INF}The following OpenPGP public key is \
217 +required to verify the Guix binary signature: $gpg_key_id.
218 +Would you like me to fetch it for you?"; then
219 + if wget "https://codeberg.org/$codeberg_username.gpg" \
220 + --tries=1 --timeout=30 --no-verbose -O- | gpg --import -; then
221 + continue
222 + fi
223 +
224 + key_obtained=false
225 + # Try to fetch keys from an available keyserver
226 + for key_server in $PUBLIC_KEYSERVERS; do
227 + if gpg --keyserver $key_server --recv-key $gpg_key_id; then
228 + key_obtained=true
229 + break
230 + fi
231 + done
232 +
233 + if $key_obtained; then
234 + continue
235 + fi
236 + fi
237 + # If we reach this point, the key is (still) missing. Report further
238 + # missing keys, if any, but then abort the installation.
239 + _err "Missing OpenPGP public key ($gpg_key_id).
240 +Fetch it with codeberg username:
241 +
242 + wget \"https://codeberg.org/$codeberg_username.gpg\" -O - | \
243 +sudo -i gpg --import -
244 +
245 +If this fails, try to fetch it via a keyserver:
246 +
247 + for key_server in $PUBLIC_KEYSERVERS; do
248 + if sudo -i gpg --keyserver $key_server --recv-key $gpg_key_id; then
249 + break
250 + fi
251 + done"
252 + exit_flag=yes
253 + done
254 + if [ "$exit_flag" = yes ]; then
255 + exit 1
256 + fi
257 +}
258 +
259 +chk_term()
260 +{ # Check for ANSI terminal for color printing.
261 + if [ -t 2 ]; then
262 + if [ "${TERM+set}" = 'set' ]; then
263 + case "$TERM" in
264 + xterm*|rxvt*|urxvt*|linux*|vt*|eterm*|screen*)
265 + ;;
266 + *)
267 + ERR="[ FAIL ] "
268 + PAS="[ PASS ] "
269 + WAR="[ WARN ] "
270 + ;;
271 + esac
272 + fi
273 + fi
274 +}
275 +
276 +chk_init_sys()
277 +{ # Return init system type name.
278 + if [[ $(/sbin/init --version 2>/dev/null) =~ upstart ]]; then
279 + _msg_info "init system is: upstart"
280 + INIT_SYS="upstart"
281 + return 0
282 + elif [[ $(systemctl 2>/dev/null) =~ -\.mount ]]; then
283 + _msg_info "init system is: systemd"
284 + INIT_SYS="systemd"
285 + return 0
286 + elif [[ -f /etc/init.d/cron && ! -h /etc/init.d/cron ]]; then
287 + _msg_info "init system is: sysv-init"
288 + INIT_SYS="sysv-init"
289 + return 0
290 + elif [[ $(openrc --version 2>/dev/null) =~ \(OpenRC ]]; then
291 + _msg_info "init system is: OpenRC"
292 + INIT_SYS="openrc"
293 + return 0
294 + else
295 + INIT_SYS="NA"
296 + _err "Init system could not be detected."
297 + fi
298 +}
299 +
300 +chk_sys_arch()
301 +{ # Check for operating system and architecture type.
302 + local os
303 + local arch
304 +
305 + os="$(uname -s)"
306 + arch="$(uname -m)"
307 +
308 + case "$arch" in
309 + i386 | i486 | i686 | i786 | x86)
310 + local arch=i686
311 + ;;
312 + x86_64 | x86-64 | x64 | amd64)
313 + local arch=x86_64
314 + ;;
315 + aarch64)
316 + local arch=aarch64
317 + ;;
318 + armv7l)
319 + local arch=armhf
320 + ;;
321 + ppc64le | powerpc64le)
322 + local arch=powerpc64le
323 + ;;
324 + riscv64)
325 + local arch=riscv64
326 + ;;
327 + *)
328 + die "Unsupported CPU type: ${arch}"
329 + esac
330 +
331 + case "$os" in
332 + Linux | linux)
333 + local os=linux
334 + ;;
335 + *)
336 + die "Your operation system (${os}) is not supported."
337 + esac
338 +
339 + ARCH_OS="${arch}-${os}"
340 +}
341 +
342 +chk_sys_nscd()
343 +{ # Check if nscd is up and suggest to start it or install it
344 + if [ "$(type -P pidof)" ]; then
345 + if [ ! "$(pidof nscd)" ]; then
346 + _msg_warn "We recommend installing and/or starting your distribution 'nscd' service"
347 + _msg_warn "Please read 'info guix \"Application Setup\"' about \"Name Service Switch\""
348 + fi
349 + else
350 + _msg_info "We cannot determine if your distribution 'nscd' service is running"
351 + _msg_info "Please read 'info guix \"Application Setup\"' about \"Name Service Switch\""
352 + fi
353 +}
354 +
355 +chk_existing()
356 +{ # Avoid clobbering existing installations.
357 + _debug "--- [ ${FUNCNAME[0]} ] ---"
358 +
359 + if [[ -e /var/guix && -e /gnu ]]; then
360 + if [ -n "$GUIX_ALLOW_OVERWRITE" ]; then
361 + _msg_warn "Overwriting existing installation!"
362 + else
363 + die "A previous Guix installation was found. Refusing to overwrite."
364 + fi
365 + fi
366 +}
367 +
368 +# Configure substitute discovery according to user's preferences.
369 +# $1 is the installed service file to edit.
370 +configure_substitute_discovery() {
371 + if grep -q -- '--discover=no' "$1" && \
372 + prompt_yes_no "Would you like the Guix daemon to automatically \
373 +discover substitute servers on the local network?"; then
374 + sed -i 's/--discover=no/--discover=yes/' "$1"
375 + fi
376 +}
377 +
378 +# ------------------------------------------------------------------------------
379 +#+MAIN
380 +
381 +guix_get_bin_list()
382 +{ # Scan GNU archive and save list of binaries
383 + local gnu_url="$1"
384 + local -a bin_ver_ls
385 + local latest_ver
386 + local default_ver
387 +
388 + _debug "--- [ ${FUNCNAME[0]} ] ---"
389 +
390 + # Filter only version and architecture
391 + bin_ver_ls=("$(wget "$gnu_url" --no-verbose -O- \
392 + | sed -n -e 's/.*guix-binary-\([0-9.]*[a-z0-9]*\)\..*.tar.xz.*/\1/p' \
393 + | sort -Vu)")
394 +
395 + latest_ver="$(echo "${bin_ver_ls[0]}" \
396 + | grep -oE "([0-9]{1,2}\.){2}[0-9]{1,2}[a-z0-9]*" \
397 + | tail -n1)"
398 +
399 + default_ver="guix-binary-${latest_ver}.${ARCH_OS}"
400 +
401 + if [[ "${#bin_ver_ls}" -ne "0" ]]; then
402 + _msg_pass "Release for your system: ${default_ver}"
403 + else
404 + die "Could not obtain list of Guix releases."
405 + fi
406 +
407 + # Use default to download according to the list and local ARCH_OS.
408 + BIN_VER="${default_ver}"
409 +}
410 +
411 +guix_get_bin()
412 +{ # Download and verify binary package.
413 + local url="$1"
414 + local bin_ver="$2"
415 + local dl_path="$3"
416 + local wget_args=()
417 +
418 + _debug "--- [ ${FUNCNAME[0]} ] ---"
419 +
420 + _msg_info "Downloading Guix release archive"
421 +
422 + wget --help | grep -q '\--show-progress' \
423 + && wget_args=("--no-verbose" "--show-progress")
424 +
425 + if wget "${wget_args[@]}" -P "$dl_path" \
426 + "${url}/${bin_ver}.tar.xz" "${url}/${bin_ver}.tar.xz.sig"; then
427 + _msg_pass "download completed."
428 + else
429 + die "could not download ${url}/${bin_ver}.tar.xz."
430 + fi
431 +
432 + pushd "${dl_path}" >/dev/null
433 + if gpg --verify "${bin_ver}.tar.xz.sig" >/dev/null 2>&1; then
434 + _msg_pass "Signature is valid."
435 + popd >/dev/null
436 + else
437 + die "could not verify the signature."
438 + fi
439 +}
440 +
441 +sys_create_store()
442 +{ # Unpack and install /gnu/store and /var/guix
443 + local pkg="$1"
444 + local tmp_path="$2"
445 +
446 + cd "$tmp_path"
447 + _msg_info "Installing /var/guix and /gnu..."
448 + # Strip (skip) the leading ‘.’ component, which fails on read-only ‘/’.
449 + #
450 + # TODO: Eventually extract with ‘--owner=guix-daemon’ when installing
451 + # and unprivileged guix-daemon service; for now, this script may install
452 + # from both an old release that does not support unprivileged guix-daemon
453 + # and a new release that does, so ‘chown -R’ later if needed.
454 + tar --extract --strip-components=1 --file "$pkg" -C /
455 +
456 + _msg_info "Linking the root user's profile"
457 + mkdir -p ~root/.config/guix
458 + ln -sf /var/guix/profiles/per-user/root/current-guix \
459 + ~root/.config/guix/current
460 +
461 + GUIX_PROFILE=~root/.config/guix/current
462 + # The profile just prepends to search paths, which is not needed for
463 + # effective linting.
464 + # shellcheck disable=SC1091
465 + source "${GUIX_PROFILE}/etc/profile"
466 + _msg_pass "activated root profile at ${GUIX_PROFILE}"
467 +}
468 +
469 +sys_delete_store()
470 +{
471 + _msg_info "removing /var/guix"
472 + rm -rf /var/guix
473 +
474 + _msg_info "removing /gnu"
475 + rm -rf /gnu
476 +
477 + _msg_info "removing ~root/.config/guix"
478 + rm -rf ~root/.config/guix
479 +}
480 +
481 +create_account()
482 +{
483 + local user="$1"
484 + local group="$2"
485 + local supplementary_groups="$3"
486 + local comment="$4"
487 +
488 + if id "$user" &>/dev/null; then
489 + _msg_info "user '$user' is already in the system, reset"
490 + usermod -g "$group" -G "$supplementary_groups" \
491 + -d /var/empty -s "$(command -v nologin)" \
492 + -c "$comment" "$user"
493 + else
494 + useradd -g "$group" -G "$supplementary_groups" \
495 + -d /var/empty -s "$(command -v nologin)" \
496 + -c "$comment" --system "$user"
497 + _msg_pass "user added <$user>"
498 + fi
499 +}
500 +
501 +install_unprivileged_daemon()
502 +{ # Return true when installing guix-daemon running without privileges.
503 + [ "$INIT_SYS" = systemd ] && \
504 + grep -q "User=guix-daemon" \
505 + ~root/.config/guix/current/lib/systemd/system/guix-daemon.service
506 +}
507 +
508 +sys_create_build_user()
509 +{ # Create the group and user accounts for build users.
510 +
511 + _debug "--- [ ${FUNCNAME[0]} ] ---"
512 +
513 + if getent group kvm > /dev/null; then
514 + _msg_info "group kvm exists and build users will be added to it"
515 + local KVMGROUP=,kvm
516 + fi
517 +
518 + if install_unprivileged_daemon
519 + then
520 + _msg_info "installing guix-daemon to run as an unprivileged user"
521 +
522 + # Installing guix-daemon to run as a non-root user requires
523 + # unprivileged user namespaces.
524 + if [ -f /proc/sys/kernel/unprivileged_userns_clone ] \
525 + && [ "$(cat /proc/sys/kernel/unprivileged_userns_clone)" -ne 1 ]
526 + then
527 + echo 1 > /proc/sys/kernel/unprivileged_userns_clone || \
528 + _err "failed to enable unprivileged user namespaces"
529 +
530 + _msg_warn "Unprivileged user namespaces were disabled and have been enabled now."
531 + _msg_warn "This Linux feature is required by guix-daemon. To enable it permanently, run:"
532 + _msg_warn ' echo 1 > /proc/sys/kernel/unprivileged_userns_clone'
533 + _msg_warn "from the relevant startup script."
534 + fi
535 +
536 +
537 + if getent group guix-daemon > /dev/null; then
538 + _msg_info "group guix-daemon exists"
539 + else
540 + groupadd --system guix-daemon
541 + _msg_pass "group guix-daemon created"
542 + fi
543 +
544 + create_account guix-daemon guix-daemon \
545 + guix-daemon"$KVMGROUP" \
546 + "Unprivileged Guix Daemon User"
547 +
548 + if getent group kvm > /dev/null; then
549 + # Allow 'newgidmap' to map the "kvm" group.
550 + local kvmgid="$(getent group kvm | cut -f3 -d:)"
551 + _msg_info "allowing kvm mapping (GID $kvmgid) for unprivileged guix-daemon"
552 + echo "guix-daemon:$kvmgid:1" >> /etc/subgid
553 + fi
554 +
555 + # ‘tar xf’ creates root:root files. Change that.
556 + chown -R guix-daemon:guix-daemon /gnu /var/guix
557 + chown -R root:root /var/guix/profiles/per-user/root
558 +
559 + # The unprivileged daemon cannot create the log directory by itself.
560 + mkdir -p /var/log/guix
561 + chown guix-daemon:guix-daemon /var/log/guix
562 + chmod 755 /var/log/guix
563 + else
564 + if getent group guixbuild > /dev/null; then
565 + _msg_info "group guixbuild exists"
566 + else
567 + groupadd --system guixbuild
568 + _msg_pass "group <guixbuild> created"
569 + fi
570 +
571 + for i in $(seq -w 1 10); do
572 + create_account "guixbuilder${i}" "guixbuild" \
573 + "guixbuild${KVMGROUP}" \
574 + "Guix build user $i"
575 + done
576 + fi
577 +}
578 +
579 +sys_delete_build_user()
580 +{
581 + for i in $(seq -w 1 10); do
582 + if id -u "guixbuilder${i}" &>/dev/null; then
583 + userdel -f guixbuilder"$i"
584 + fi
585 + done
586 +
587 + _msg_info "delete group guixbuild"
588 + if getent group guixbuild &>/dev/null; then
589 + groupdel -f guixbuild
590 + fi
591 +
592 + _msg_info "remove guix-daemon user"
593 + if id guix-daemon &>/dev/null; then
594 + userdel -f guix-daemon
595 + fi
596 + if getent group guix-daemon &>/dev/null; then
597 + groupdel -f guix-daemon
598 + fi
599 +}
600 +
601 +sys_enable_guix_daemon()
602 +{ # Run the daemon, and set it to automatically start on boot.
603 +
604 + local info_path
605 + local local_bin
606 + local var_guix
607 +
608 + _debug "--- [ ${FUNCNAME[0]} ] ---"
609 +
610 + info_path="/usr/local/share/info"
611 + local_bin="/usr/local/bin"
612 + var_guix="/var/guix/profiles/per-user/root/current-guix"
613 +
614 + case "$INIT_SYS" in
615 + upstart)
616 + { initctl reload-configuration;
617 + cp ~root/.config/guix/current/lib/upstart/system/guix-daemon.conf \
618 + /etc/init/ &&
619 + configure_substitute_discovery /etc/init/guix-daemon.conf &&
620 + start guix-daemon; } &&
621 + _msg_pass "enabled Guix daemon via upstart"
622 + ;;
623 + systemd)
624 + { install_unit()
625 + {
626 + local dest="/etc/systemd/system/$1"
627 + rm -f "$dest"
628 + cp ~root/.config/guix/current/lib/systemd/system/"$1" "$dest"
629 + chmod 664 "$dest"
630 + systemctl daemon-reload
631 + systemctl enable "$1"
632 + }
633 +
634 + install_unit guix-daemon.service
635 +
636 + configure_substitute_discovery \
637 + /etc/systemd/system/guix-daemon.service
638 +
639 + # Install after guix-daemon.service to avoid a harmless warning.
640 + # systemd .mount units must be named after the target directory.
641 + install_unit gnu-store.mount
642 +
643 + systemctl daemon-reload &&
644 + systemctl start guix-daemon &&
645 + systemctl start gnu-store.mount; } &&
646 + _msg_pass "enabled Guix daemon via systemd"
647 + ;;
648 + sysv-init)
649 + { mkdir -p /etc/init.d;
650 + cp ~root/.config/guix/current/etc/init.d/guix-daemon \
651 + /etc/init.d/guix-daemon;
652 + chmod 775 /etc/init.d/guix-daemon;
653 +
654 + configure_substitute_discovery /etc/init.d/guix-daemon
655 +
656 + update-rc.d guix-daemon defaults &&
657 + update-rc.d guix-daemon enable &&
658 + service guix-daemon start; } &&
659 + _msg_pass "enabled Guix daemon via sysv"
660 + ;;
661 + openrc)
662 + { mkdir -p /etc/init.d;
663 + cp ~root/.config/guix/current/etc/openrc/guix-daemon \
664 + /etc/init.d/guix-daemon;
665 + chmod 775 /etc/init.d/guix-daemon;
666 +
667 + configure_substitute_discovery /etc/init.d/guix-daemon
668 +
669 + rc-update add guix-daemon default &&
670 + rc-service guix-daemon start; } &&
671 + _msg_pass "enabled Guix daemon via OpenRC"
672 + ;;
673 + NA|*)
674 + _err "unsupported init system; run the daemon manually:"
675 + echo " ~root/.config/guix/current/bin/guix-daemon --build-users-group=guixbuild"
676 + ;;
677 + esac
678 +
679 + _msg_info "making the guix command available to other users"
680 +
681 + [ -e "$local_bin" ] || mkdir -p "$local_bin"
682 + ln -sf "${var_guix}/bin/guix" "$local_bin"
683 +
684 + [ -e "$info_path" ] || mkdir -p "$info_path"
685 + for i in "${var_guix}"/share/info/*; do
686 + ln -sf "$i" "$info_path"
687 + done
688 +}
689 +
690 +sys_delete_guix_daemon()
691 +{ # Disabled, stop and remove the various guix daemons.
692 +
693 + local info_path
694 + local local_bin
695 + local var_guix
696 +
697 + _debug "--- [ ${FUNCNAME[0]} ] ---"
698 +
699 + info_path="/usr/local/share/info"
700 + local_bin="/usr/local/bin"
701 +
702 +
703 + case "$INIT_SYS" in
704 + upstart)
705 + _msg_info "stopping guix-daemon"
706 + stop guix-daemon
707 + _msg_info "removing guix-daemon"
708 + rm /etc/init/guix-daemon.conf
709 + ;;
710 +
711 + systemd)
712 + if [ -f /etc/systemd/system/guix-daemon.service ]; then
713 + _msg_info "disabling guix-daemon"
714 + systemctl disable guix-daemon
715 + _msg_info "stopping guix-daemon"
716 + systemctl stop guix-daemon
717 + _msg_info "removing guix-daemon"
718 + rm -f /etc/systemd/system/guix-daemon.service
719 + fi
720 +
721 + if [ -f /etc/systemd/system/gnu-store.mount ]; then
722 + _msg_info "disabling gnu-store.mount"
723 + systemctl disable gnu-store.mount
724 + _msg_info "stopping gnu-store.mount"
725 + systemctl stop gnu-store.mount
726 + _msg_info "removing gnu-store.mount"
727 + rm -f /etc/systemd/system/gnu-store.mount
728 + fi
729 + systemctl daemon-reload
730 + ;;
731 +
732 + sysv-init)
733 + update-rc.d guix-daemon disable
734 + service guix-daemon stop
735 + rm -rf /etc/init.d/guix-daemon
736 + ;;
737 + NA|*)
738 + _err "unsupported init system; disable, stop and remove the daemon manually:"
739 + echo " ~root/.config/guix/current/bin/guix-daemon --build-users-group=guixbuild"
740 + ;;
741 + esac
742 +
743 +
744 + _msg_info "removing $local_bin/guix"
745 + rm -f "$local_bin"/guix
746 +
747 + _msg_info "removing $info_path/guix*"
748 + rm -f "$info_path"/guix*
749 +}
750 +
751 +sys_authorize_build_farms()
752 +{ # authorize the public key(s) of the build farm(s)
753 + local hosts=(
754 + bordeaux.guix.gnu.org
755 + ci.guix.gnu.org
756 + )
757 +
758 + if prompt_yes_no "Permit downloading pre-built package binaries from the \
759 +project's build farms?"; then
760 + for host in "${hosts[@]}"; do
761 + local key=~root/.config/guix/current/share/guix/$host.pub
762 + [ -f "$key" ] \
763 + && guix archive --authorize < "$key" \
764 + && _msg_pass "Authorized public key for $host"
765 + done
766 + if id guix-daemon &>/dev/null; then
767 + # /etc/guix/acl must be readable by the unprivileged guix-daemon.
768 + chown -R guix-daemon:guix-daemon /etc/guix
769 + fi
770 + else
771 + _msg_info "Skipped authorizing build farm public keys"
772 + fi
773 +}
774 +
775 +sys_create_init_profile()
776 +{ # Define for better desktop integration
777 + # This will not take effect until the next shell or desktop session!
778 + [ -d "/etc/profile.d" ] || mkdir /etc/profile.d # Just in case
779 + cat <<"EOF" > /etc/profile.d/zzz-guix.sh
780 +# Explicitly initialize XDG base directory variables to ease compatibility
781 +# with Guix System: see <https://issues.guix.gnu.org/56050#3>.
782 +export XCURSOR_PATH="${XCURSOR_PATH:-$HOME/.local/share/icons:$HOME/.icons:/usr/local/share/icons:/usr/share/icons}"
783 +export XDG_DATA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}"
784 +export XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"
785 +export XDG_STATE_HOME="${XDG_STATE_HOME:-$HOME/.local/state}"
786 +export XDG_DATA_DIRS="${XDG_DATA_DIRS:-/usr/local/share/:/usr/share/}"
787 +export XDG_CONFIG_DIRS="${XDG_CONFIG_DIRS:-/etc/xdg}"
788 +export XDG_CACHE_HOME="${XDG_CACHE_HOME:-$HOME/.cache}"
789 +# no default for XDG_RUNTIME_DIR (depends on foreign distro for semantics)
790 +
791 +# `guix pull` profile
792 +GUIX_PROFILE="$HOME/.config/guix/current"
793 +export PATH="$GUIX_PROFILE/bin${PATH:+:}$PATH"
794 +# Add to INFOPATH and MANPATH so the latest Guix documentation is available to
795 +# info and man readers. When INFOPATH is unset, add a trailing colon so Emacs
796 +# searches 'Info-default-directory-list'. When MANPATH is unset, add a
797 +# trailing colon so the system default search path is used.
798 +export INFOPATH="$GUIX_PROFILE/share/info:${INFOPATH:-}"
799 +export MANPATH="$GUIX_PROFILE/share/man:${MANPATH:-}"
800 +# Expose the latest Guix modules to Guile so guix shell and repls spawned by
801 +# e.g. Geiser work out of the box.
802 +export GUILE_LOAD_PATH="$GUIX_PROFILE/share/guile/site/3.0${GUILE_LOAD_PATH:+:$GUILE_LOAD_PATH}"
803 +export GUILE_LOAD_COMPILED_PATH="$GUIX_PROFILE/lib/guile/3.0/site-ccache${GUILE_LOAD_COMPILED_PATH:+:$GUILE_LOAD_COMPILED_PATH}"
804 +
805 +# User's default profile, if it exists
806 +GUIX_PROFILE="$HOME/.guix-profile"
807 +if [ -f "$GUIX_PROFILE/etc/profile" ]; then
808 + . "$GUIX_PROFILE/etc/profile"
809 +
810 + # see info '(guix) Application Setup'
811 + export GUIX_LOCPATH="$GUIX_PROFILE/lib/locale${GUIX_LOCPATH:+:}$GUIX_LOCPATH"
812 +
813 + # Documentation search paths may be handled by $GUIX_PROFILE/etc/profile if
814 + # the user installs info and man readers via Guix. If the user doesn’t,
815 + # explicitly add to them so documentation for software from ‘guix install’
816 + # is available to the system info and man readers.
817 + case $INFOPATH in
818 + *$GUIX_PROFILE/share/info*) ;;
819 + *) export INFOPATH="$GUIX_PROFILE/share/info:$INFOPATH" ;;
820 + esac
821 + case $MANPATH in
822 + *$GUIX_PROFILE/share/man*) ;;
823 + *) export MANPATH="$GUIX_PROFILE/share/man:$MANPATH"
824 + esac
825 +
826 + case $XDG_DATA_DIRS in
827 + *$GUIX_PROFILE/share*) ;;
828 + *) export XDG_DATA_DIRS="$GUIX_PROFILE/share:$XDG_DATA_DIRS"
829 + esac
830 +fi
831 +
832 +# NOTE: Guix Home handles its own profile initialization in ~/.profile. See
833 +# info '(guix) Configuring the Shell'.
834 +
835 +# Clean up after ourselves.
836 +unset GUIX_PROFILE
837 +EOF
838 +}
839 +
840 +sys_create_shell_completion()
841 +{ # Symlink supported shell completions system-wide
842 +
843 + var_guix=/var/guix/profiles/per-user/root/current-guix
844 + bash_completion=/etc/bash_completion.d
845 + zsh_completion=/usr/share/zsh/site-functions
846 + fish_completion=/usr/share/fish/vendor_completions.d
847 +
848 + { # Just in case
849 + for dir_shell in $bash_completion $zsh_completion $fish_completion; do
850 + [ -d "$dir_shell" ] || mkdir -p "$dir_shell"
851 + done;
852 +
853 + # Don't use globing here as we also need to delete the files when
854 + # uninstalling Guix
855 + ln -sf ${var_guix}/etc/bash_completion.d/guix "$bash_completion";
856 + ln -sf ${var_guix}/etc/bash_completion.d/guix-daemon "$bash_completion";
857 + ln -sf ${var_guix}/share/zsh/site-functions/_guix "$zsh_completion";
858 + ln -sf ${var_guix}/share/fish/vendor_completions.d/guix.fish "$fish_completion"; } &&
859 + _msg_pass "installed shell completion"
860 +}
861 +
862 +sys_delete_shell_completion()
863 +{ # Symlink supported shell completions system-wide
864 +
865 + var_guix=/var/guix/profiles/per-user/root/current-guix
866 + bash_completion=/etc/bash_completion.d
867 + zsh_completion=/usr/share/zsh/site-functions
868 + fish_completion=/usr/share/fish/vendor_completions.d
869 +
870 + _msg_info "removing shell completion"
871 +
872 + rm -f "$bash_completion"/guix;
873 + rm -f "$bash_completion"/guix-daemon;
874 + rm -f "$zsh_completion"/_guix;
875 + rm -f "$fish_completion"/guix.fish;
876 +}
877 +
878 +sys_customize_bashrc()
879 +{
880 + prompt_yes_no "Customize users Bash shell prompt for Guix?" || return 0
881 +
882 + for bashrc in /home/*/.bashrc /root/.bashrc; do
883 + test -f "$bashrc" || continue
884 + # shellcheck disable=SC2016 # intended search for variable reference
885 + grep -Fq '$GUIX_ENVIRONMENT' "$bashrc" && continue
886 + cp "${bashrc}" "${bashrc}.bak"
887 + # shellcheck disable=SC2016,SC2028 # intended literal shell output
888 + echo '
889 +# Automatically added by the Guix install script.
890 +if [ -n "$GUIX_ENVIRONMENT" ]; then
891 + if [[ $PS1 =~ (.*)"\\$" ]]; then
892 + PS1="${BASH_REMATCH[1]} [env]\\\$ "
893 + fi
894 +fi
895 +' >> "$bashrc"
896 + done
897 + _msg_pass "Bash shell prompt successfully customized for Guix"
898 +}
899 +
900 +sys_maybe_setup_selinux()
901 +{
902 + if ! [ -f /sys/fs/selinux/policy ]
903 + then
904 + return
905 + fi
906 +
907 + local c
908 + for c in semodule restorecon
909 + do
910 + if ! command -v "$c" &>/dev/null
911 + then
912 + return
913 + fi
914 + done
915 +
916 + prompt_yes_no "Install SELinux policy that might be required to run guix-daemon?" \
917 + || return 0
918 +
919 + local var_guix=/var/guix/profiles/per-user/root/current-guix
920 + semodule -i "${var_guix}/share/selinux/guix-daemon.cil"
921 + restorecon -R /gnu /var/guix
922 +}
923 +
924 +sys_maybe_setup_apparmor()
925 +{
926 + if ! [ -f /sys/module/apparmor/parameters/enabled ]
927 + then
928 + return
929 + fi
930 +
931 + if ! command -v apparmor_parser &> /dev/null
932 + then
933 + return
934 + fi
935 +
936 + prompt_yes_no "Install AppArmor profile that might be required to run guix-daemon?" \
937 + || return 0
938 +
939 + local var_guix=/var/guix/profiles/per-user/root/current-guix
940 + local apparmor_sources="${var_guix}/etc/apparmor.d/"
941 +
942 + if ! [ -d "$apparmor_sources" ]
943 + then
944 + _err "This version of Guix doesn’t contain AppArmor profiles."
945 + return
946 + fi
947 +
948 + cp -f -t /etc/apparmor.d/tunables "$apparmor_sources/tunables/guix"
949 + cp -f -t /etc/apparmor.d "$apparmor_sources/guix-daemon"
950 + cp -f -t /etc/apparmor.d "$apparmor_sources/guix"
951 + apparmor_parser --warn=all -r /etc/apparmor.d/guix-daemon
952 + apparmor_parser --warn=all -r /etc/apparmor.d/guix
953 +
954 + _msg_pass "apparmor profiles installed and loaded"
955 +}
956 +
957 +sys_delete_apparmor_profiles()
958 +{
959 + # Not a big deal if the apparmor_parser commands fail as they only apply
960 + # for the current boot, we still want to go on and remove the files.
961 + if [ -f "/etc/apparmor.d/guix" ]
962 + then
963 + _msg_info "removing /etc/apparmor.d/guix"
964 + apparmor_parser -R /etc/apparmor.d/guix || true
965 + rm -f "/etc/apparmor.d/guix"
966 + fi
967 +
968 + if [ -f "/etc/apparmor.d/guix-daemon" ]
969 + then
970 + _msg_info "removing /etc/apparmor.d/guix-daemon"
971 + apparmor_parser -R /etc/apparmor.d/guix-daemon || true
972 + rm -f "/etc/apparmor.d/guix-daemon"
973 + fi
974 +
975 + if [ -f "/etc/apparmor.d/tunables/guix" ]
976 + then
977 + _msg_info "removing /etc/apparmor.d/tunables/guix"
978 + rm -f "/etc/apparmor.d/tunables/guix"
979 + fi
980 +}
981 +
982 +sys_delete_init_profile()
983 +{
984 + _msg_info "removing /etc/profile.d/zzz-guix.sh"
985 + rm -f /etc/profile.d/zzz-guix.sh
986 +}
987 +
988 +sys_delete_user_profiles()
989 +{
990 + _msg_info "removing ~root/.guix-profile"
991 + rm -f ~root/.guix-profile
992 + rm -rf ~root/.cache/guix
993 +
994 + _msg_info "removing .guix-profile, .cache/guix and .config/guix of all /home users"
995 + rm -rf /home/*/{.guix-profile,{.cache,.config}/guix}
996 +}
997 +
998 +welcome()
999 +{
1000 + local uninstall_flag="$1"
1001 + local char
1002 + cat<<"EOF"
1003 + ��������� ���������
1004 + ��������������������������������������� ���������������������������������������
1005 + ������������������������������������������ ���������������������������������������
1006 + ��������������������������������� ������������������������������
1007 + ������������������ ������������������
1008 + ��������������� ������������������
1009 + ��������������� ���������������
1010 + ������������������ ���������������
1011 + ��������������� ���������������
1012 + ��������������� ���������������
1013 + ���������������������������������
1014 + ���������������������������
1015 + ���������������������
1016 + _____ _ _ _ _ _____ _
1017 + / ____| \ | | | | | / ____| (_)
1018 + | | __| \| | | | | | | __ _ _ ___ __
1019 + | | |_ | . ' | | | | | | |_ | | | | \ \/ /
1020 + | |__| | |\ | |__| | | |__| | |_| | |> <
1021 + \_____|_| \_|\____/ \_____|\__,_|_/_/\_\
1022 +
1023 +https://www.gnu.org/software/guix/
1024 +EOF
1025 +
1026 + if [ '--uninstall' = "$uninstall_flag" ]; then
1027 + echo "${WARN}This script will uninstall GNU Guix from your system"
1028 + echo "To install, run this script with no parameters."
1029 + else
1030 + echo "This script installs GNU Guix on your system"
1031 + echo "To uninstall, pass in the '--uninstall' parameter."
1032 + fi
1033 +
1034 + # Don't use ‘read -p’ here! It won't display when run non-interactively.
1035 + echo -n "Press return to continue..."$'\r'
1036 + if ! read -r char; then
1037 + echo
1038 + die "Can't read standard input. Hint: don't pipe scripts into a shell."
1039 + fi
1040 + if [ "$char" ]; then
1041 + echo
1042 + echo "...that ($char) was not a return!"
1043 + _msg_warn "Use newlines to automate installation, e.g.: yes '' | ${0##*/}"
1044 + _msg_warn "Any other method is unsupported and likely to break in future."
1045 + fi
1046 +}
1047 +
1048 +main_install()
1049 +{
1050 + local tmp_path
1051 + welcome
1052 +
1053 + _msg "Starting installation ($(date))"
1054 +
1055 + chk_term
1056 + chk_init_sys
1057 + add_init_sys_require
1058 + chk_require "${REQUIRE[@]}"
1059 + chk_sys_arch
1060 + chk_sys_nscd
1061 + chk_existing
1062 +
1063 + _msg_info "system is ${ARCH_OS}"
1064 +
1065 + umask 0022
1066 + tmp_path="$(mktemp -t -d guix.XXXXXX)"
1067 +
1068 + if [ -z "${GUIX_BINARY_FILE_NAME}" ]; then
1069 + chk_gpg_keyring
1070 + guix_get_bin_list "${GNU_URL}"
1071 + guix_get_bin "${GNU_URL}" "${BIN_VER}" "$tmp_path"
1072 + GUIX_BINARY_FILE_NAME=${BIN_VER}.tar.xz
1073 + else
1074 + if ! [[ $GUIX_BINARY_FILE_NAME =~ $ARCH_OS ]]; then
1075 + _err "$ARCH_OS not in ${GUIX_BINARY_FILE_NAME}; aborting"
1076 + fi
1077 + _msg_info "Using manually provided binary ${GUIX_BINARY_FILE_NAME}"
1078 + GUIX_BINARY_FILE_NAME=$(realpath "$GUIX_BINARY_FILE_NAME")
1079 + fi
1080 +
1081 + sys_create_store "${GUIX_BINARY_FILE_NAME}" "${tmp_path}"
1082 + sys_create_build_user
1083 + sys_maybe_setup_selinux
1084 + sys_maybe_setup_apparmor
1085 + sys_enable_guix_daemon
1086 + sys_authorize_build_farms
1087 + sys_create_init_profile
1088 + sys_create_shell_completion
1089 + sys_customize_bashrc
1090 +
1091 + _msg_info "cleaning up ${tmp_path}"
1092 + rm -r "${tmp_path}"
1093 +
1094 + _msg_pass "Guix has successfully been installed!"
1095 + _msg_info "Run 'info guix' to read the manual."
1096 +
1097 + # Required to source /etc/profile in desktop environments.
1098 + _msg_info "Please log out and back in to complete the installation."
1099 + }
1100 +
1101 +main_uninstall()
1102 +{
1103 + welcome --uninstall
1104 + _msg "Starting uninstall process ($(date))"
1105 +
1106 + chk_term
1107 + chk_require "${REQUIRE[@]}"
1108 + # it's ok to leave the gpg key
1109 + chk_init_sys
1110 + chk_sys_arch
1111 +
1112 + _msg_info "system is ${ARCH_OS}"
1113 +
1114 + # stop the build, package system.
1115 + sys_delete_guix_daemon
1116 + # stop people from accessing their profiles.
1117 + sys_delete_user_profiles
1118 + sys_delete_apparmor_profiles
1119 + # kill guix off all the guts of guix
1120 + sys_delete_store
1121 + # clean up the system
1122 + sys_delete_init_profile
1123 + sys_delete_build_user
1124 + sys_delete_shell_completion
1125 +
1126 + # these directories are created on the fly during usage.
1127 + _msg_info "removing /etc/guix"
1128 + rm -rf /etc/guix
1129 + _msg_info "removing /var/log/guix"
1130 + rm -rf /var/log/guix
1131 +
1132 + _msg_pass "Guix has successfully been uninstalled!"
1133 +}
1134 +
1135 +main()
1136 +{
1137 + # expect no parameters
1138 + # or '--uninstall'
1139 + if [ 0 -eq $# ]; then
1140 + main_install
1141 + else
1142 + local uninstall_flag="$1"
1143 + if [ '--uninstall' = "${uninstall_flag}" ]; then
1144 + main_uninstall
1145 + else
1146 + echo "unsupported parameters: $*"
1147 + exit 1
1148 + fi
1149 + fi
1150 +}
1151 +
1152 +main "$@"
+139 −0 pkger.c new file mode 100644
@@ -0,0 +1,139 @@
1 +#include <stdio.h>
2 +#include <stdlib.h>
3 +#include <string.h>
4 +#include <unistd.h>
5 +#include <sys/wait.h>
6 +#include <sys/stat.h>
7 +#include <dirent.h>
8 +#include <errno.h>
9 +#include "repos.h"
10 +
11 +int
12 +run_cmd (char *const argv[])
13 +{
14 + pid_t pid = fork ();
15 + if (pid == 0)
16 + {
17 + execvp (argv[0], argv);
18 + perror ("execvp failed");
19 + _exit (1);
20 + }
21 + else if (pid > 0)
22 + {
23 + int status;
24 + waitpid (pid, &status, 0);
25 + return WIFEXITED (status) && WEXITSTATUS (status) == 0;
26 + }
27 + return 0;
28 +}
29 +
30 +int
31 +run_shell_string (const char *cmd)
32 +{
33 + if (!cmd || strlen (cmd) == 0)
34 + return 1;
35 +
36 + if (strcmp (cmd, "true") == 0)
37 + return 1;
38 +
39 + printf ("[EXEC] %s\n", cmd);
40 + char *const argv[] = { "/bin/sh", "-c", (char *) cmd, NULL };
41 + return run_cmd (argv);
42 +}
43 +
44 +void
45 +install_repo (const Repository *repo)
46 +{
47 + printf ("=== Installing %s ===\n", repo->name);
48 +
49 + char repo_dir[256];
50 + snprintf (repo_dir, sizeof (repo_dir), "/tmp/pkger-%s", repo->name);
51 +
52 + char fetch_str[512];
53 + snprintf (fetch_str, sizeof (fetch_str), repo->fetchFmt, repo->fetchCmd, repo->url, repo_dir);
54 + if (!run_shell_string (fetch_str))
55 + {
56 + fprintf (stderr, "[ERROR] Failed to fetch package.\n");
57 + return;
58 + }
59 +
60 + if (chdir (repo_dir) != 0)
61 + {
62 + perror ("[ERROR] chdir failed");
63 + return;
64 + }
65 +
66 + if (!run_shell_string (repo->buildCmd))
67 + {
68 + fprintf (stderr, "Build failed.\n");
69 + return;
70 + }
71 +
72 + if (!run_shell_string (repo->installCmd))
73 + {
74 + fprintf (stderr, "Install failed.\n");
75 + return;
76 + }
77 +
78 + printf ("Successfully installed %s!\n", repo->name);
79 + }
80 +
81 +void
82 +uninstall_repo (const Repository *repo)
83 + {
84 + char repo_dir[256];
85 + snprintf (repo_dir, sizeof (repo_dir), "/tmp/pkger-%s", repo->name);
86 +
87 + if (chdir (repo_dir) != 0)
88 + {
89 + perror ("[ERROR] chdir failed");
90 + return;
91 + }
92 +
93 + printf ("=== Uninstalling %s ===\n", repo->name);
94 + if (!run_shell_string (repo->uninstallCmd))
95 + {
96 + fprintf (stderr, "Uninstall failed.\n");
97 + }
98 + }
99 +
100 +int
101 +main (int argc, char *argv[])
102 + {
103 + if (argc < 3)
104 + {
105 + printf ("Usage: %s <install|uninstall> <repo_name>\n", argv[0]);
106 + printf ("\nAvailable repositories:\n");
107 + for (size_t i = 0; i < REPO_COUNT; i++)
108 + {
109 + printf (" - %s\n", REPOS[i].name);
110 + }
111 + return 1;
112 + }
113 +
114 + const char *action = argv[1];
115 + const char *target = argv[2];
116 +
117 + for (size_t i = 0; i < REPO_COUNT; i++)
118 + {
119 + if (strcmp (REPOS[i].name, target) == 0)
120 + {
121 + if (strcmp (action, "install") == 0)
122 + {
123 + install_repo (&REPOS[i]);
124 + }
125 + else if (strcmp (action, "uninstall") == 0)
126 + {
127 + uninstall_repo (&REPOS[i]);
128 + }
129 + else
130 + {
131 + fprintf (stderr, "Unknown action: %s\n", action);
132 + }
133 + return 0;
134 + }
135 + }
136 +
137 + fprintf (stderr, "Repository '%s' not found.\n", target);
138 + return 1;
139 + }
+26 −0 readme.org new file mode 100644
@@ -0,0 +1,26 @@
1 +#+TITLE: slpkger (small packager)
2 +#+AUTHOR: theidioticdev
3 +x
4 +slpkger is a really unconventional package manager (seriously don't use this for a distro)
5 +it uses a suckless-like approach to installing pkgs by editiing =repos.h= like this
6 +
7 +#+BEGIN_SRC c
8 + static const Repository REPOS[] =
9 + {
10 + /* add your repos here... */
11 + {
12 + .name = "tins",
13 + .url = "https://codeberg.org/theidioticdev/tins",
14 + .buildCmd = "true",
15 + .installCmd =
16 + "install -Dm755 tins /usr/local/bin && install -Dm644 completions/tins-comp.sh /usr/share/bash-completions/completions/tins",
17 + .uninstallCmd =
18 + "rm -f /usr/local/bin/tins /usr/share/bash-completions/completions/tins"},
19 + {
20 + .name = "sfetch",
21 + .url = "https://codeberg.org/theidioticdev/sfetch",
22 + .buildCmd = "./build",
23 + .installCmd = "./build --install",
24 + };
25 +
26 +#+END_SRC
+30 −17 repos.h
@@ -5,30 +5,43 @@ typedef struct
5 { 5 {
6 const char *name; 6 const char *name;
7 const char *url; 7 const char *url;
8 + const char *fetchCmd;
9 + const char *fetchFmt;
8 const char *buildCmd; 10 const char *buildCmd;
9 const char *installCmd; 11 const char *installCmd;
10 const char *uninstallCmd; 12 const char *uninstallCmd;
11 } Repository; 13 } Repository;
12 14
13 15
14 -static const Repository REPOS[] = { 16 +static const Repository REPOS[] =
15 - /* add your repos here... */
16 { 17 {
17 - .name = "tins", 18 + /* add your repos here... */
18 - .url = "https://codeberg.org/theidioticdev/tins", 19 + {
19 - .buildCmd = "true", 20 + .name = "sfetch",
20 - .installCmd = 21 + .url = "https://codeberg.org/theidioticdev/sfetch",
21 - "install -Dm755 tins /usr/local/bin && install -Dm644 completions/tins-comp.sh /usr/share/bash-completions/completions/tins.sh", 22 + .fetchCmd = "git clone",
22 - .uninstallCmd = 23 + /* command repo dir" */
23 - "rm -f /usr/local/bin/tins /usr/share/bash-completions/completions/tins.sh"}, 24 + .fetchFmt = "%s %s %s",
24 - { 25 + .buildCmd = "./build",
25 - .name = "sfetch", 26 + .installCmd = "./build --install",
26 - .url = "https://codeberg.org/theidioticdev/sfetch", 27 + .uninstallCmd = "./build --uninstall"},
27 - .buildCmd = "./build", 28 + {
28 - .installCmd = "./build --install", 29 + .name = "lsa",
29 - .uninstallCmd = "./build --uninstall"} 30 + .url = "https://git.sr.ht/~trondelag__/lsa",
30 - 31 + .fetchCmd = "git clone",
31 -}; 32 + .fetchFmt = "%s %s %s",
33 + .buildCmd = "cc -std=c89 lsa.c -o lsa",
34 + .installCmd = "cp lsa /usr/local/bin/lsa",
35 + .uninstallCmd = "rm lsa /usr/local/bin/lsa"},
36 + {
37 + .name = "guix",
38 + .url = "https://guix.gnu.org/install.sh",
39 + .fetchFmt = "%s %s -P %s",
40 + .fetchCmd = "wget",
41 + .buildCmd = "chmod +x install.sh",
42 + .installCmd = "./install.sh",
43 + .uninstallCmd = "./install.sh --uninstall"}
44 + };
32 45
33 static const size_t REPO_COUNT = sizeof (REPOS) / sizeof (REPOS[0]); 46 static const size_t REPO_COUNT = sizeof (REPOS) / sizeof (REPOS[0]);
34 #endif 47 #endif
+0 −137 slpkger.c deleted file mode 100644
@@ -1,137 +0,0 @@
1 -#include <stdio.h>
2 -#include <stdlib.h>
3 -#include <string.h>
4 -#include <unistd.h>
5 -#include <sys/wait.h>
6 -#include "repos.h"
7 -
8 -int
9 -runCmd (char *const argv[])
10 -{
11 - pid_t pid = fork ();
12 - if (pid == 0)
13 - {
14 - execvp (argv[0], argv);
15 - perror ("execvp failed");
16 - _exit (1);
17 - }
18 - else if (pid > 0)
19 - {
20 - int status;
21 - waitpid (pid, &status, 0);
22 - return WIFEXITED (status) && WEXITSTATUS (status) == 0;
23 - }
24 - return 0;
25 -}
26 -
27 -int
28 -runShellString (const char *cmd)
29 -{
30 - if (!cmd || strlen (cmd) == 0)
31 - return 1;
32 -
33 - if (strcmp (cmd, "true") == 0)
34 - return 1;
35 -
36 - printf ("[EXEC] %s\n", cmd);
37 - char *const argv[] = { "/bin/sh", "-c", (char *) cmd, NULL };
38 - return runCmd (argv);
39 -}
40 -
41 -void
42 -install_repo (const Repository *repo)
43 -{
44 - printf ("=== Installing %s ===\n", repo->name);
45 -
46 - char repoDir[256];
47 - snprintf (repoDir, sizeof (repoDir), "/tmp/slpkg-%s", repo->name);
48 -
49 - char *const cloneArgv[] =
50 - { "git", "clone", (char *) repo->url, repoDir, NULL };
51 - printf ("[EXEC] git clone %s %s\n", repo->url, repoDir);
52 - if (!runCmd (cloneArgv))
53 - {
54 - fprintf (stderr, "Failed to clone repository.\n");
55 - return;
56 - }
57 -
58 - if (chdir (repoDir) != 0)
59 - {
60 - perror ("chdir failed");
61 - return;
62 - }
63 -
64 - if (!runShellString (repo->buildCmd))
65 - {
66 - fprintf (stderr, "Build failed.\n");
67 - return;
68 - }
69 -
70 - if (!runShellString (repo->installCmd))
71 - {
72 - fprintf (stderr, "Install failed.\n");
73 - return;
74 - }
75 -
76 - printf ("Successfully installed %s!\n", repo->name);
77 -}
78 -
79 -void
80 -uninstall_repo (const Repository *repo)
81 -{
82 - char repoDir[256];
83 - snprintf (repoDir, sizeof (repoDir), "/tmp/slpkg-%s", repo->name);
84 -
85 - if (chdir (repoDir) != 0)
86 - {
87 - perror ("chdir failed");
88 - return;
89 - }
90 -
91 - printf ("=== Uninstalling %s ===\n", repo->name);
92 - if (!runShellString (repo->uninstallCmd))
93 - {
94 - fprintf (stderr, "Uninstall failed.\n");
95 - }
96 -}
97 -
98 -int
99 -main (int argc, char *argv[])
100 -{
101 - if (argc < 3)
102 - {
103 - printf ("Usage: %s <install|uninstall> <repo_name>\n", argv[0]);
104 - printf ("\nAvailable repositories:\n");
105 - for (size_t i = 0; i < REPO_COUNT; i++)
106 - {
107 - printf (" - %s\n", REPOS[i].name);
108 - }
109 - return 1;
110 - }
111 -
112 - const char *action = argv[1];
113 - const char *target = argv[2];
114 -
115 - for (size_t i = 0; i < REPO_COUNT; i++)
116 - {
117 - if (strcmp (REPOS[i].name, target) == 0)
118 - {
119 - if (strcmp (action, "install") == 0)
120 - {
121 - install_repo (&REPOS[i]);
122 - }
123 - else if (strcmp (action, "uninstall") == 0)
124 - {
125 - uninstall_repo (&REPOS[i]);
126 - }
127 - else
128 - {
129 - fprintf (stderr, "Unknown action: %s\n", action);
130 - }
131 - return 0;
132 - }
133 - }
134 -
135 - fprintf (stderr, "Repository '%s' not found.\n", target);
136 - return 1;
137 -}