ybox 0.9.8__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ybox/__init__.py +2 -0
- ybox/cmd.py +307 -0
- ybox/conf/completions/ybox.fish +93 -0
- ybox/conf/distros/arch/add-gpg-key.sh +29 -0
- ybox/conf/distros/arch/distro.ini +192 -0
- ybox/conf/distros/arch/init-base.sh +10 -0
- ybox/conf/distros/arch/init-user.sh +35 -0
- ybox/conf/distros/arch/init.sh +82 -0
- ybox/conf/distros/arch/list_fmt_long.py +76 -0
- ybox/conf/distros/arch/pkgdeps.py +276 -0
- ybox/conf/distros/deb-generic/check-package.sh +77 -0
- ybox/conf/distros/deb-generic/distro.ini +190 -0
- ybox/conf/distros/deb-generic/fetch-gpg-key-id.sh +30 -0
- ybox/conf/distros/deb-generic/init-base.sh +11 -0
- ybox/conf/distros/deb-generic/init-user.sh +3 -0
- ybox/conf/distros/deb-generic/init.sh +136 -0
- ybox/conf/distros/deb-generic/list_fmt_long.py +114 -0
- ybox/conf/distros/deb-generic/pkgdeps.py +208 -0
- ybox/conf/distros/deb-oldstable/distro.ini +21 -0
- ybox/conf/distros/deb-stable/distro.ini +21 -0
- ybox/conf/distros/supported.list +5 -0
- ybox/conf/distros/ubuntu2204/distro.ini +21 -0
- ybox/conf/distros/ubuntu2404/distro.ini +21 -0
- ybox/conf/profiles/apps.ini +26 -0
- ybox/conf/profiles/basic.ini +310 -0
- ybox/conf/profiles/dev.ini +25 -0
- ybox/conf/profiles/games.ini +39 -0
- ybox/conf/resources/entrypoint-base.sh +170 -0
- ybox/conf/resources/entrypoint-common.sh +23 -0
- ybox/conf/resources/entrypoint-cp.sh +32 -0
- ybox/conf/resources/entrypoint-root.sh +20 -0
- ybox/conf/resources/entrypoint-user.sh +21 -0
- ybox/conf/resources/entrypoint.sh +249 -0
- ybox/conf/resources/prime-run +13 -0
- ybox/conf/resources/run-in-dir +60 -0
- ybox/conf/resources/run-user-bash-cmd +14 -0
- ybox/config.py +255 -0
- ybox/env.py +205 -0
- ybox/filelock.py +77 -0
- ybox/migrate/0.9.0-0.9.7:0.9.8.py +33 -0
- ybox/pkg/__init__.py +0 -0
- ybox/pkg/clean.py +33 -0
- ybox/pkg/info.py +40 -0
- ybox/pkg/inst.py +638 -0
- ybox/pkg/list.py +191 -0
- ybox/pkg/mark.py +68 -0
- ybox/pkg/repair.py +150 -0
- ybox/pkg/repo.py +251 -0
- ybox/pkg/search.py +52 -0
- ybox/pkg/uninst.py +92 -0
- ybox/pkg/update.py +56 -0
- ybox/print.py +121 -0
- ybox/run/__init__.py +0 -0
- ybox/run/cmd.py +54 -0
- ybox/run/control.py +102 -0
- ybox/run/create.py +1116 -0
- ybox/run/destroy.py +64 -0
- ybox/run/graphics.py +367 -0
- ybox/run/logs.py +57 -0
- ybox/run/ls.py +64 -0
- ybox/run/pkg.py +445 -0
- ybox/schema/0.9.1-added.sql +27 -0
- ybox/schema/0.9.6-added.sql +18 -0
- ybox/schema/init.sql +39 -0
- ybox/schema/migrate/0.9.0:0.9.1.sql +42 -0
- ybox/schema/migrate/0.9.1:0.9.2.sql +8 -0
- ybox/schema/migrate/0.9.2:0.9.3.sql +2 -0
- ybox/schema/migrate/0.9.5:0.9.6.sql +2 -0
- ybox/state.py +914 -0
- ybox/util.py +351 -0
- ybox-0.9.8.dist-info/LICENSE +19 -0
- ybox-0.9.8.dist-info/METADATA +533 -0
- ybox-0.9.8.dist-info/RECORD +76 -0
- ybox-0.9.8.dist-info/WHEEL +5 -0
- ybox-0.9.8.dist-info/entry_points.txt +8 -0
- ybox-0.9.8.dist-info/top_level.txt +1 -0
@@ -0,0 +1,190 @@
|
|
1
|
+
# Configuration specific to each distribution (INI style file)
|
2
|
+
|
3
|
+
# The following environment variables are set when running the init.sh and init-user.sh scripts.
|
4
|
+
# The scripts are required to honor the meaning of the corresponding variables as described in
|
5
|
+
# their comments.
|
6
|
+
# CONFIGURE_FASTEST_MIRRORS: empty or non-empty corresponding to configure_fastest_mirrors below
|
7
|
+
# REQUIRED_PKGS: packages specified in `packages.required` below
|
8
|
+
# REQUIRED_DEPS: packages specified in `packages.required_deps` below
|
9
|
+
# RECOMMENDED_PKGS: packages specified in `packages.recommended` below
|
10
|
+
# RECOMMENDED_DEPS: packages specified in `packages.recommended_deps` below
|
11
|
+
# SUGGESTED_PKGS: packages specified in `packages.suggested` below
|
12
|
+
# SUGGESTED_DEPS: packages specified in `packages.suggested_deps` below
|
13
|
+
# EXTRA_PKGS: packages specified in `packages.extra` below
|
14
|
+
|
15
|
+
|
16
|
+
# Base configuration for the distribution
|
17
|
+
[base]
|
18
|
+
# name is required and should be overridden by distributions using this
|
19
|
+
name = Generic Debian/Ubuntu distribution
|
20
|
+
# Comma separated files to include before applying these settings.
|
21
|
+
# Paths can be absolute or relative to the location of this file.
|
22
|
+
includes =
|
23
|
+
# docker image of the distribution
|
24
|
+
image =
|
25
|
+
# directories which are shared between the containers of a distribution when
|
26
|
+
# `shared_root` is provided in the container configuration
|
27
|
+
shared_root_dirs = /etc,/opt,/usr,/var
|
28
|
+
# the secondary groups of the container user; it requires to include at least the equivalent of
|
29
|
+
# nobody/nogroup to work correctly (the last field in /etc/subgid)
|
30
|
+
secondary_groups = nogroup,sudo,video,input,lp,mail
|
31
|
+
# whether to search for and configure fastest available mirrors for packages
|
32
|
+
configure_fastest_mirrors = false
|
33
|
+
# distribution scripts that need to be copied to the container in $YBOX_TARGET_SCRIPTS_DIR
|
34
|
+
# (should include init.sh, init-base.sh and init-user.sh scripts that are are normally required
|
35
|
+
# for all distributions)
|
36
|
+
# distributions should have relative paths to the scripts from this directory
|
37
|
+
#scripts = init-base.sh,init.sh,init-user.sh,check-package.sh,list_fmt_long.py,fetch-gpg-key-id.sh
|
38
|
+
scripts =
|
39
|
+
|
40
|
+
|
41
|
+
# Initial set of packages to be installed in the distribution image
|
42
|
+
[packages]
|
43
|
+
# packages required for a functional ybox container
|
44
|
+
required = git ed zip dctrl-tools
|
45
|
+
# dependencies of the `required` packages
|
46
|
+
required_deps = less patch openssh-client unzip bash-completion psmisc
|
47
|
+
# recommended packages required for many GUI/CLI apps to work properly
|
48
|
+
recommended = bc man-db manpages pulseaudio-utils bzip2 xz-utils zstd fastjar wget shared-mime-info
|
49
|
+
iso-codes vainfo mesa-utils vulkan-tools iputils-ping iproute2 tzdata distro-info
|
50
|
+
pciutils whiptail python3-pip fonts-liberation2
|
51
|
+
# dependencies of the `recommended` packages
|
52
|
+
recommended_deps = xauth netbase xdg-user-dirs intel-media-va-driver-non-free mesa-va-drivers
|
53
|
+
mesa-vulkan-drivers libfribidi0 fonts-dejavu-core sensible-utils libpam-cap
|
54
|
+
# optional packages for enhanced experience in shell and GUI apps
|
55
|
+
suggested = fonts-cantarell fonts-firacode fonts-noto-core neovim ncdu fd-find bat
|
56
|
+
kitty-terminfo tree autojump
|
57
|
+
# dependencies of the `suggested` packages
|
58
|
+
suggested_deps = xsel xxd
|
59
|
+
|
60
|
+
|
61
|
+
# The commands here will be run as normal userns mapped user, so use sudo if the command
|
62
|
+
# needs to run as root inside the container
|
63
|
+
[pkgmgr]
|
64
|
+
# the variables here are all required ones unless noted otherwise
|
65
|
+
|
66
|
+
# install command does not have a placeholder for {package} since it is also used by
|
67
|
+
# entrypoint scripts to install packages, so this assumes that this command accepts a list of one
|
68
|
+
# or more space-separated packages at the end
|
69
|
+
install = DOWNLOADBEFORE=true /usr/bin/apt-fast {quiet} {opt_dep} install
|
70
|
+
# Show the packages that satisfy the given {package} where latter can be a virtual package
|
71
|
+
# (i.e. "Provides") or an actual package or a combination of both (e.g. some packages provide and
|
72
|
+
# replace another actual package).
|
73
|
+
check_avail = /bin/sh $YBOX_TARGET_SCRIPTS_DIR/check-package.sh available '{package}'
|
74
|
+
# check an installed actual or virtual (i.e. "Provides") package and list them in reverse
|
75
|
+
# install/upgrade time order (i.e. most recently installed/upgraded first)
|
76
|
+
check_install = /bin/sh $YBOX_TARGET_SCRIPTS_DIR/check-package.sh installed '{package}'
|
77
|
+
# proceed quietly without asking questions
|
78
|
+
quiet_flag = -y
|
79
|
+
# this is substituted for `{quiet}` placeholder in `info`, `info_all`, `search` and `search_all`
|
80
|
+
quiet_details_flag = -qq
|
81
|
+
# apt-mark works correctly only if an optional dependency is actually marked to be so in the
|
82
|
+
# deb package, but will cause trouble for cases where user wants to mark a package as an optional
|
83
|
+
# dependency of another even otherwise (e.g. qt5ct as optional dependency of libqt5gui5)
|
84
|
+
opt_dep_flag =
|
85
|
+
# Expected output of the `opt_deps` command is:
|
86
|
+
# {header}
|
87
|
+
# {prefix}<name>{separator}<level>{separator}<installed>{separator}<description>
|
88
|
+
# where
|
89
|
+
# <name>: name of the optional dependency
|
90
|
+
# <level>: level of the dependency i.e. 1 for direct dependency, 2 for dependency of dependency and
|
91
|
+
# so on; resolution of level > 2 is not required since caller currently ignores those
|
92
|
+
# <installed>: true if the dependency already installed and false otherwise
|
93
|
+
opt_deps = /usr/bin/python3 $YBOX_TARGET_SCRIPTS_DIR/pkgdeps.py \
|
94
|
+
-s '{separator}' -p '{prefix}' -H '{header}'
|
95
|
+
# disable unstable API warning for apt
|
96
|
+
apt_no_warn = /usr/bin/apt -o Apt::Cmd::Disable-Script-Warning=true
|
97
|
+
uninstall = /usr/bin/sudo %(apt_no_warn)s {quiet} {purge} {remove_deps} remove {package}
|
98
|
+
purge_flag = --purge
|
99
|
+
remove_deps_flag = --autoremove
|
100
|
+
orphans = /usr/bin/sudo %(apt_no_warn)s --just-print autoremove | /usr/bin/mawk '/^Rem/ { print $2 }'
|
101
|
+
update_meta = DOWNLOADBEFORE=true /usr/bin/apt-fast update
|
102
|
+
update = DOWNLOADBEFORE=true /usr/bin/apt-fast --only-upgrade {quiet} install {packages}
|
103
|
+
update_all = DOWNLOADBEFORE=true /usr/bin/apt-fast {quiet} full-upgrade
|
104
|
+
clean = DOWNLOADBEFORE=true && /usr/bin/apt-fast clean && /usr/bin/sudo /usr/bin/apt clean
|
105
|
+
clean_quiet = %(clean)s
|
106
|
+
mark_explicit = /usr/bin/sudo /usr/bin/apt-mark manual {package}
|
107
|
+
|
108
|
+
info = /usr/bin/dpkg-query -s {packages}
|
109
|
+
info_all = /usr/bin/apt-cache {quiet} show {packages}
|
110
|
+
|
111
|
+
# list and list_all show package name and version separated by {separator}; the list command only
|
112
|
+
# shows explicitly installed packages while the "_all" variant also shows dependents
|
113
|
+
list = PKGS="$(/usr/bin/apt-mark showmanual {packages} | /usr/bin/tr '\n' ' ')" && \
|
114
|
+
/usr/bin/dpkg-query -W -f '${{binary:Package}}{separator}${{Version}}\n' $PKGS
|
115
|
+
# empty {packages} means all packages
|
116
|
+
list_all = /usr/bin/dpkg-query -W -f '${{binary:Package}}{separator}${{Version}}\n' {packages}
|
117
|
+
|
118
|
+
# next two variables are not required ones rather are used for expansion in list variables
|
119
|
+
# to avoid repetition
|
120
|
+
list_fmt_long = /usr/bin/python3 $YBOX_TARGET_SCRIPTS_DIR/list_fmt_long.py '{separator}'
|
121
|
+
list_long_fields = '${{binary:Package}}{separator}${{Version}}{separator}${{Provides}}'`\
|
122
|
+
`'{separator}${{Pre-Depends}}{separator}${{Depends}}{separator}${{Recommends}}'`\
|
123
|
+
`'{separator}${{Suggests}}{separator}${{Description}}\n\n'
|
124
|
+
# list_long and list_all_long show package name, version, dependency-of and description separated
|
125
|
+
# by {separator}; the dependency-of column gives the required and optional dependencies in the
|
126
|
+
# format: req(<pkg> <pkg> ...),opt(<pkg> <pkg> ...); like above the "_all" variant shows all
|
127
|
+
# packages including dependents while other one shows only explicitly installed ones
|
128
|
+
list_long = PKGS="$(/usr/bin/apt-mark showmanual {packages} | /usr/bin/tr '\n' ' ')" && \
|
129
|
+
/usr/bin/dpkg-query -W -f %(list_long_fields)s $PKGS | %(list_fmt_long)s
|
130
|
+
list_all_long = /usr/bin/dpkg-query -W -f %(list_long_fields)s {packages} | %(list_fmt_long)s
|
131
|
+
|
132
|
+
list_files = /usr/bin/dpkg-query -L {package}
|
133
|
+
|
134
|
+
# next variable is not a required one rather are used for expansion in search variables
|
135
|
+
|
136
|
+
# the weird "set ..." subcommand converts space-separated quoted arguments into a
|
137
|
+
# regex i.e. ' one ' 'two' ' three' to " one |two | three" which is accomplished by declaring
|
138
|
+
# those arguments as positional arguments $1, $2 etc, then echo all arguments with IFS as "|"
|
139
|
+
args_re = "{word_start}($(set -- {search}; IFS="|"; echo "$*")){word_end}"
|
140
|
+
|
141
|
+
# search in package names in the repositories
|
142
|
+
search = %(apt_no_warn)s --names-only -q {quiet} {official} search %(args_re)s
|
143
|
+
# search in package names, provides and descriptions in the repositories
|
144
|
+
search_all = /usr/bin/apt-cache {quiet} {official} search %(args_re)s
|
145
|
+
# this is substituted for `{official}` placeholder in `search` and `search_all`
|
146
|
+
search_official_flag =
|
147
|
+
# this is substituted for `{word_start}` placeholder in `search` and `search_all`
|
148
|
+
search_word_start_flag = \b
|
149
|
+
# this is substituted for `{word_end}` placeholder in `search` and `search_all`
|
150
|
+
search_word_end_flag = \b
|
151
|
+
|
152
|
+
# regex pattern matching processes that may be invoked by package manager directly or indirectly
|
153
|
+
# that may need to be terminated for cleanup
|
154
|
+
processes_pattern = \b(apt-get|apt-fast|apt|aptitude|nala|keyboxd|dirmngr)\b
|
155
|
+
# comma separated globs for package manager related lock files (no spaces in names or within)
|
156
|
+
locks_pattern = /var/lib/apt/lists/lock,/var/lib/dpkg/lock*,$HOME/.gnupg/public-keys.d/*.lock
|
157
|
+
repair = /usr/bin/sudo /usr/bin/apt-get --fix-broken {quiet} install
|
158
|
+
# reinstall all packages
|
159
|
+
repair_all = %(repair)s && \
|
160
|
+
MANUAL_PKGS="$(/usr/bin/apt-mark showmanual)" && \
|
161
|
+
PKGS="$(/usr/bin/apt-mark showinstall)" && \
|
162
|
+
/usr/bin/apt-fast --reinstall {quiet} install $PKGS && \
|
163
|
+
/usr/bin/sudo /usr/bin/apt-mark auto $PKGS >/dev/null && \
|
164
|
+
/usr/bin/sudo /usr/bin/apt-mark manual $MANUAL_PKGS >/dev/null && %(clean)s
|
165
|
+
|
166
|
+
|
167
|
+
# Commands related to repository management
|
168
|
+
[repo]
|
169
|
+
conf_dir = /etc/apt/sources.list.d
|
170
|
+
keyring_dir = /etc/apt/keyrings
|
171
|
+
exists = /bin/test -f "%(conf_dir)s/{name}.list"
|
172
|
+
# Ubuntu's keyserver is more reliable than the standard gnupg.net/pgp.net ones
|
173
|
+
default_gpg_key_server = hkps://keyserver.ubuntu.com
|
174
|
+
# output of the `add_key` command should have a line of the form "KEYID=..." that provides the
|
175
|
+
# fingerprints of the registered keys that can be passed to `remove_key`
|
176
|
+
add_key = ( /usr/bin/curl -sSL '{url}' | /usr/bin/gpg --dearmor | \
|
177
|
+
/usr/bin/sudo /usr/bin/tee '%(keyring_dir)s/{name}.gpg' >/dev/null) && \
|
178
|
+
/bin/echo KEYID="$(/usr/bin/gpg --show-keys --with-colons '%(keyring_dir)s/{name}.gpg' | \
|
179
|
+
/usr/bin/sed -n 's/^fpr:*\([^:]*\).*/\1/p' | /usr/bin/tr '\n' ' ')"
|
180
|
+
# add gpg/pgp key given the key ID and key server
|
181
|
+
add_key_id = /usr/bin/sudo /bin/bash $YBOX_TARGET_SCRIPTS_DIR/fetch-gpg-key-id.sh \
|
182
|
+
'{key}' '{server}' '%(keyring_dir)s/{name}.gpg'
|
183
|
+
# additional options if supported should be mentioned using {options} below
|
184
|
+
add = /bin/echo 'deb [signed-by=%(keyring_dir)s/{name}.gpg] {urls} {options}' | \
|
185
|
+
/usr/bin/sudo /usr/bin/tee '%(conf_dir)s/{name}.list'
|
186
|
+
# if source repository is supported, then it should be provided in `add_source` like for `add`
|
187
|
+
add_source = /bin/echo 'deb-src [signed-by=%(keyring_dir)s/{name}.gpg] {urls} {options}' | \
|
188
|
+
/usr/bin/sudo /usr/bin/tee -a '%(conf_dir)s/{name}.list'
|
189
|
+
remove_key = /usr/bin/sudo /bin/rm '%(keyring_dir)s/{name}.gpg'
|
190
|
+
remove = /usr/bin/sudo /bin/rm '%(conf_dir)s/{name}.list'
|
@@ -0,0 +1,30 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
# this script fetches a GPG/PGP key and writes it to an output file given the key ID and key server
|
4
|
+
|
5
|
+
set -e
|
6
|
+
|
7
|
+
# Check if all arguments are provided
|
8
|
+
if [ $# -ne 3 ]; then
|
9
|
+
echo "Usage: $0 <key ID> <key server> <output key file>"
|
10
|
+
exit 1
|
11
|
+
fi
|
12
|
+
|
13
|
+
# ensure that only system paths are searched for all the system utilities
|
14
|
+
export PATH="/usr/sbin:/usr/bin:/sbin:/bin"
|
15
|
+
|
16
|
+
current_user="$(id -un)"
|
17
|
+
export HOME="$(getent passwd "$current_user" | cut -d: -f6)"
|
18
|
+
mkdir -p "$HOME/.gnupg"
|
19
|
+
chmod 0700 "$HOME/.gnupg"
|
20
|
+
|
21
|
+
temp_keyring="$(mktemp /tmp/gpg-keyring-XXXXXXXXXX)"
|
22
|
+
|
23
|
+
trap "rm -f $temp_keyring ${temp_keyring}~" 0 1 2 3 13 15
|
24
|
+
|
25
|
+
# fetch the key from the key server and export to given output key file
|
26
|
+
GPG_CMD="gpg --no-default-keyring --keyring $temp_keyring"
|
27
|
+
$GPG_CMD --keyserver "$2" --recv-key "$1"
|
28
|
+
$GPG_CMD --export --output "$3"
|
29
|
+
|
30
|
+
exit 0
|
@@ -0,0 +1,136 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
set -e
|
4
|
+
|
5
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
6
|
+
|
7
|
+
source "$SCRIPT_DIR/entrypoint-common.sh"
|
8
|
+
|
9
|
+
if [ -f /etc/dpkg/dpkg.cfg.d/excludes ]; then
|
10
|
+
echo_color "$fg_cyan" "Removing dpkg excludes" >> $status_file
|
11
|
+
mv /etc/dpkg/dpkg.cfg.d/excludes /etc/dpkg/dpkg.cfg.d/excludes.dpkg-tmp
|
12
|
+
elif [ -f /etc/dpkg/dpkg.cfg.d/docker ]; then
|
13
|
+
echo_color "$fg_cyan" "Removing dpkg docker excludes" >> $status_file
|
14
|
+
mv /etc/dpkg/dpkg.cfg.d/docker /etc/dpkg/dpkg.cfg.d/docker.dpkg-tmp
|
15
|
+
fi
|
16
|
+
|
17
|
+
echo_color "$fg_cyan" "Configuring apt and updating package list" >> $status_file
|
18
|
+
export HOME=/root
|
19
|
+
export DEBIAN_FRONTEND=noninteractive
|
20
|
+
# don't install recommended and suggested packages by default but keep them if they are
|
21
|
+
# deliberately marked as dependencies
|
22
|
+
cat > /etc/apt/apt.conf.d/10-ybox << EOF
|
23
|
+
APT::Install-Recommends "false";
|
24
|
+
APT::Install-Suggests "false";
|
25
|
+
APT::AutoRemove::RecommendsImportant "true";
|
26
|
+
APT::AutoRemove::SuggestsImportant "true";
|
27
|
+
EOF
|
28
|
+
# allow language translations in apt for non english locales
|
29
|
+
if [[ -n "$LANG" && ! "$LANG" =~ ^C(\..+)?$ && "$LANG" != "POSIX" && ! "$LANG" == en_* ]]; then
|
30
|
+
rm -f /etc/apt/apt.conf.d/docker-no-languages
|
31
|
+
fi
|
32
|
+
|
33
|
+
if [ "$(sed -n 's/^ID=//p' /etc/os-release)" = "ubuntu" ]; then
|
34
|
+
apt_fast_rel="$(sed -n 's/^VERSION_CODENAME=//p' /etc/os-release)"
|
35
|
+
else
|
36
|
+
apt_fast_rel=focal # use focal for apt-fast install which works on all recent Debian releases
|
37
|
+
# enable contrib and non-free repositories for debian
|
38
|
+
if [ -f /etc/apt/sources.list.d/debian.sources ]; then
|
39
|
+
sed -i 's/^Components: main[ ]*$/Components: main contrib non-free non-free-firmware/' \
|
40
|
+
/etc/apt/sources.list.d/debian.sources
|
41
|
+
else
|
42
|
+
sed -i 's/ main[ ]*$/ main contrib non-free/' /etc/apt/sources.list
|
43
|
+
fi
|
44
|
+
fi
|
45
|
+
apt-get update
|
46
|
+
|
47
|
+
echo_color "$fg_cyan" "Setting up apt-fast" >> $status_file
|
48
|
+
apt-get install --install-recommends -y curl gnupg lsb-release
|
49
|
+
keyring_file=/etc/apt/keyrings/apt-fast.gpg
|
50
|
+
rm -f $keyring_file
|
51
|
+
echo -e "deb [signed-by=$keyring_file] http://ppa.launchpad.net/apt-fast/stable/ubuntu $apt_fast_rel main" \
|
52
|
+
> /etc/apt/sources.list.d/apt-fast.list
|
53
|
+
mkdir -p /etc/apt/keyrings
|
54
|
+
bash "$SCRIPT_DIR/fetch-gpg-key-id.sh" 0xBC5934FD3DEBD4DAEA544F791E2824A7F22B44BD \
|
55
|
+
"$DEFAULT_GPG_KEY_SERVER" $keyring_file
|
56
|
+
|
57
|
+
apt-get update
|
58
|
+
apt-get install -y apt-fast
|
59
|
+
# update couple of apt-fast defaults (both conf file and debconf selection need to be changed)
|
60
|
+
sed -i 's/^_APTMGR=.*/_APTMGR=apt/' /etc/apt-fast.conf
|
61
|
+
sed -i 's/^_MAXNUM=.*/_MAXNUM=6/' /etc/apt-fast.conf
|
62
|
+
echo "apt-fast apt-fast/aptmanager select apt" | debconf-set-selections
|
63
|
+
echo "apt-fast apt-fast/maxdownloads select 6" | debconf-set-selections
|
64
|
+
|
65
|
+
echo_color "$fg_cyan" "Upgrading all packages" >> $status_file
|
66
|
+
export DOWNLOADBEFORE=true
|
67
|
+
apt-fast full-upgrade -y --autoremove
|
68
|
+
|
69
|
+
# skip unminimize if not installing any recommended packages which should happen only in testing
|
70
|
+
if [ -n "$RECOMMENDED_PKGS" ]; then
|
71
|
+
unminimize_path="$(type -p unminimize 2>/dev/null || true)"
|
72
|
+
if [ -z "$unminimize_path" ]; then
|
73
|
+
apt-get install -y unminimize 2>/dev/null || true
|
74
|
+
fi
|
75
|
+
unminimize_path="$(type -p unminimize 2>/dev/null || true)"
|
76
|
+
if [ -n "$unminimize_path" ]; then
|
77
|
+
echo_color "$fg_cyan" "Running unminimize" >> $status_file
|
78
|
+
sed -i 's/apt-get/apt-fast/g' "$unminimize_path"
|
79
|
+
yes | "$unminimize_path"
|
80
|
+
apt-get remove --purge -y unminimize 2>/dev/null || true
|
81
|
+
fi
|
82
|
+
fi
|
83
|
+
|
84
|
+
# packages can be marked as manually installed in the base image, so mark most of them as auto
|
85
|
+
apt-mark auto $(apt-mark showinstall) >/dev/null
|
86
|
+
apt-mark manual procps sudo curl gnupg lsb-release apt-fast
|
87
|
+
|
88
|
+
# generate the configured locale and assume it is UTF-8
|
89
|
+
echo_color "$fg_cyan" "Configuring locale" >> $status_file
|
90
|
+
apt-fast install -y locales
|
91
|
+
if [ -n "$LANG" -a "$LANG" != "C.UTF-8" ] && ! grep -q "^$LANG UTF-8" /etc/locale.gen; then
|
92
|
+
echo "$LANG UTF-8" >> /etc/locale.gen
|
93
|
+
# always add en_US.UTF-8 regardless since some apps seem to depend on it
|
94
|
+
if [ "$LANG" != "en_US.UTF-8" ]; then
|
95
|
+
echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen
|
96
|
+
fi
|
97
|
+
if ! locale-gen; then
|
98
|
+
echo_color "$fg_red" "FAILED to generate locale for $LANG, fallback to en_US.UTF-8" >> $status_file
|
99
|
+
export LANG=en_US.UTF-8
|
100
|
+
export LANGUAGE="en_US:en"
|
101
|
+
fi
|
102
|
+
echo "LANG=$LANG" > /etc/default/locale
|
103
|
+
if [ -n "$LANGUAGE" ]; then
|
104
|
+
echo "LANGUAGE=\"$LANGUAGE\"" >> /etc/default/locale
|
105
|
+
fi
|
106
|
+
fi
|
107
|
+
|
108
|
+
echo_color "$fg_cyan" "Installing base set of packages" >> $status_file
|
109
|
+
apt-fast install -y $REQUIRED_PKGS $RECOMMENDED_PKGS $SUGGESTED_PKGS \
|
110
|
+
$REQUIRED_DEPS $RECOMMENDED_DEPS $SUGGESTED_DEPS
|
111
|
+
apt-mark auto $REQUIRED_DEPS $RECOMMENDED_DEPS $SUGGESTED_DEPS
|
112
|
+
apt-fast clean
|
113
|
+
apt clean
|
114
|
+
|
115
|
+
# common environment variables
|
116
|
+
if ! grep -q '^export EDITOR=' /etc/bash.bashrc && dpkg --no-pager -l neovim 2>/dev/null >/dev/null; then
|
117
|
+
echo -e '\nexport EDITOR=nvim\nexport VISUAL=nvim' >> /etc/bash.bashrc
|
118
|
+
fi
|
119
|
+
if ! grep -q '^export LESSOPEN=' /etc/bash.bashrc && dpkg --no-pager -l lesspipe 2>/dev/null >/dev/null; then
|
120
|
+
echo -e '\nexport PAGER="less -RL"' >> /etc/bash.bashrc
|
121
|
+
lesspipe >> /etc/bash.bashrc
|
122
|
+
fi
|
123
|
+
if ! grep -q '^export LANG=' /etc/bash.bashrc && [ -n "$LANG" -a "$LANG" != "C.UTF-8" ]; then
|
124
|
+
echo -e "\nexport LANG=$LANG" >> /etc/bash.bashrc
|
125
|
+
if [ -n "$LANGUAGE" ]; then
|
126
|
+
echo "export LANGUAGE=\"$LANGUAGE\"" >> /etc/bash.bashrc
|
127
|
+
fi
|
128
|
+
fi
|
129
|
+
|
130
|
+
# skip starship if not installing any recommended packages which should happen only in testing
|
131
|
+
if [ -n "$RECOMMENDED_PKGS" ]; then
|
132
|
+
echo_color "$fg_cyan" "Installing starship for fancy bash prompt" >> $status_file
|
133
|
+
curl -sSL https://starship.rs/install.sh -o starship-install.sh && \
|
134
|
+
/bin/sh starship-install.sh -y && rm -f starship-install.sh /tmp/tmp.*
|
135
|
+
echo -e 'eval "$(starship init bash)"' >> /etc/bash.bashrc
|
136
|
+
fi
|
@@ -0,0 +1,114 @@
|
|
1
|
+
"""
|
2
|
+
Format output of `dpkg-query -W -f '${binary:Package}<sep>${Version}<sep>${Provides}<sep>\
|
3
|
+
${Pre-Depends}<sep>${Depends}<sep>${Recommends}<sep>${Suggests}<sep>${Description}\n\n'`
|
4
|
+
into four columns ${binary:Package}<sep>${Version}<sep>${Dependency Of}<sep>${Description}
|
5
|
+
where <sep> is a user provided separator.
|
6
|
+
"""
|
7
|
+
|
8
|
+
import argparse
|
9
|
+
import re
|
10
|
+
import sys
|
11
|
+
from collections import defaultdict
|
12
|
+
from typing import Iterable
|
13
|
+
|
14
|
+
from pkgdeps import PKG_DEP_RE # pylint: disable=no-name-in-module
|
15
|
+
|
16
|
+
_DOT_LINE = re.compile(r"\s+\.\s*")
|
17
|
+
|
18
|
+
|
19
|
+
def parse_separator():
|
20
|
+
"""expect a single argument which will be used as the separator between the fields"""
|
21
|
+
parser = argparse.ArgumentParser(description="Format output of dpkg-query into a table.")
|
22
|
+
parser.add_argument("separator", type=str,
|
23
|
+
help="separator to use between the fields of the output")
|
24
|
+
args = parser.parse_args()
|
25
|
+
return args.separator
|
26
|
+
|
27
|
+
|
28
|
+
def format_dep_of(req_parts: Iterable[str], opt_parts: Iterable[str]) -> str:
|
29
|
+
"""format the `Dependency Of` column to include the required and optional dependencies"""
|
30
|
+
dep_of_parts = [f"req({' '.join(req_parts)})"] if req_parts else []
|
31
|
+
if opt_parts:
|
32
|
+
dep_of_parts.append(f"opt({' '.join(opt_parts)})")
|
33
|
+
return ",".join(dep_of_parts)
|
34
|
+
|
35
|
+
|
36
|
+
def process() -> None:
|
37
|
+
"""process dpkg-query output on stdin to create fields separated by a given separator"""
|
38
|
+
sep = parse_separator()
|
39
|
+
current_pkg = ""
|
40
|
+
desc: list[str] = [] # description can be multiline so accumulate it
|
41
|
+
# map of package name to version and description; required and optional dependencies
|
42
|
+
# have be to looked up in the respective maps using the dependency name so need to build
|
43
|
+
# the full pkg_map first
|
44
|
+
pkg_map: defaultdict[str, list[str]] = defaultdict(lambda: ["", ""])
|
45
|
+
# reverse map of package to list of packages that require it (in their pre-depends or depends)
|
46
|
+
req_map: defaultdict[str, list[str]] = defaultdict(list[str])
|
47
|
+
# reverse map of package to list of packages that require it (in their recommends or suggests)
|
48
|
+
opt_map: defaultdict[str, list[str]] = defaultdict(list[str])
|
49
|
+
# map of package name to list of packages it provides (the reverse maps above can have
|
50
|
+
# either the dependency as the key or one of its provides as the key)
|
51
|
+
provides_map: defaultdict[str, list[str]] = defaultdict(list[str])
|
52
|
+
|
53
|
+
for line in sys.stdin:
|
54
|
+
if not line:
|
55
|
+
continue
|
56
|
+
if line[0].isspace():
|
57
|
+
# continuation of the previous description
|
58
|
+
if _DOT_LINE.fullmatch(line):
|
59
|
+
desc.append(r"\n") # literal \n will be replaced by newline in the table display
|
60
|
+
else:
|
61
|
+
# for simple line breaks in the description, it is just a continuation and can be
|
62
|
+
# appended with a space, but for the case of `_DOT_LINE` as well as the first
|
63
|
+
# description line and details later, it constitutes a new paragraph which are
|
64
|
+
# separated by a literal \n
|
65
|
+
if desc and desc[-1] != r"\n":
|
66
|
+
desc.append(" ")
|
67
|
+
desc.append(line.strip())
|
68
|
+
else:
|
69
|
+
if current_pkg:
|
70
|
+
# indicates start of fields of a new package, so fill in description and clear
|
71
|
+
pkg_map[current_pkg][1] = "".join(desc)
|
72
|
+
desc.clear()
|
73
|
+
current_pkg, version, provides, pre_depends, depends, recommends, suggests, desc_s = \
|
74
|
+
line.split(sep, maxsplit=7)
|
75
|
+
pkg_map[current_pkg][0] = version
|
76
|
+
# Iterate Provides, Pre-Depends, Depends, Recommends, Suggests to fill in their maps.
|
77
|
+
# This does not take care of version comparisons in the dependencies but it should
|
78
|
+
# not be possible for an installed package to fail version dependency check (assuming
|
79
|
+
# the packages are not broken), while virtual packages don't have versions
|
80
|
+
for match in PKG_DEP_RE.finditer(provides):
|
81
|
+
provides_map[current_pkg].append(match.group(1))
|
82
|
+
# fill in reverse mapping of required dependencies
|
83
|
+
for match in PKG_DEP_RE.finditer(pre_depends):
|
84
|
+
req_map[match.group(1)].append(current_pkg)
|
85
|
+
for match in PKG_DEP_RE.finditer(depends):
|
86
|
+
req_map[match.group(1)].append(current_pkg)
|
87
|
+
# fill in reverse mapping of optional dependencies
|
88
|
+
for match in PKG_DEP_RE.finditer(recommends):
|
89
|
+
opt_map[match.group(1)].append(current_pkg)
|
90
|
+
for match in PKG_DEP_RE.finditer(suggests):
|
91
|
+
opt_map[match.group(1)].append(current_pkg)
|
92
|
+
desc.append(desc_s.rstrip())
|
93
|
+
desc.append(r"\n") # literal \n will be replaced by newline in the table display
|
94
|
+
# fill description of the last package
|
95
|
+
if current_pkg and desc:
|
96
|
+
pkg_map[current_pkg][1] = "".join(desc)
|
97
|
+
|
98
|
+
# for each package in pkg_map, find the packages that require it by looking up the
|
99
|
+
# req_map and opt_map reverse maps; it also need to check all entries in the provides
|
100
|
+
# map to get the full list of packages that require the dependency
|
101
|
+
for pkg_name, (version, description) in pkg_map.items():
|
102
|
+
req_parts = set[str]()
|
103
|
+
opt_parts = set[str]()
|
104
|
+
for dep_name in (pkg_name, *provides_map.get(pkg_name, [])):
|
105
|
+
if req_pkg := req_map.get(dep_name):
|
106
|
+
req_parts.update(req_pkg)
|
107
|
+
if opt_pkg := opt_map.get(dep_name):
|
108
|
+
opt_parts.update(opt_pkg)
|
109
|
+
dep_of = format_dep_of(req_parts, opt_parts)
|
110
|
+
print(f"{pkg_name}{sep}{version}{sep}{dep_of}{sep}{description}")
|
111
|
+
|
112
|
+
|
113
|
+
if __name__ == "__main__":
|
114
|
+
process()
|