ybox 0.9.9__py3-none-any.whl → 0.9.10__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 +1 -1
- ybox/cmd.py +17 -1
- ybox/conf/completions/ybox.fish +2 -0
- ybox/conf/distros/arch/init-user.sh +2 -2
- ybox/conf/distros/arch/init.sh +1 -0
- ybox/conf/distros/arch/pkgdeps.py +2 -0
- ybox/conf/distros/deb-generic/pkgdeps.py +2 -1
- ybox/conf/profiles/basic.ini +29 -16
- ybox/conf/profiles/dev.ini +0 -6
- ybox/conf/resources/entrypoint-root.sh +1 -0
- ybox/conf/resources/entrypoint-user.sh +5 -3
- ybox/conf/resources/entrypoint.sh +22 -13
- ybox/conf/resources/prime-run +0 -2
- ybox/conf/resources/run-in-dir +4 -0
- ybox/conf/resources/run-user-bash-cmd +17 -1
- ybox/conf/resources/ybox-systemd.template +22 -0
- ybox/config.py +9 -1
- ybox/pkg/clean.py +1 -7
- ybox/pkg/info.py +1 -7
- ybox/pkg/inst.py +20 -14
- ybox/pkg/list.py +1 -6
- ybox/pkg/repair.py +4 -0
- ybox/pkg/search.py +1 -7
- ybox/run/cmd.py +2 -1
- ybox/run/control.py +91 -24
- ybox/run/create.py +186 -48
- ybox/run/destroy.py +67 -4
- ybox/run/logs.py +2 -1
- ybox/run/ls.py +2 -1
- ybox/run/pkg.py +46 -4
- ybox/state.py +22 -3
- ybox/util.py +5 -5
- {ybox-0.9.9.dist-info → ybox-0.9.10.dist-info}/METADATA +35 -12
- {ybox-0.9.9.dist-info → ybox-0.9.10.dist-info}/RECORD +38 -37
- {ybox-0.9.9.dist-info → ybox-0.9.10.dist-info}/WHEEL +1 -1
- {ybox-0.9.9.dist-info → ybox-0.9.10.dist-info}/LICENSE +0 -0
- {ybox-0.9.9.dist-info → ybox-0.9.10.dist-info}/entry_points.txt +0 -0
- {ybox-0.9.9.dist-info → ybox-0.9.10.dist-info}/top_level.txt +0 -0
ybox/run/destroy.py
CHANGED
@@ -3,11 +3,15 @@ Code for the `ybox-destroy` script that is used to destroy an active or stopped
|
|
3
3
|
"""
|
4
4
|
|
5
5
|
import argparse
|
6
|
+
import os
|
7
|
+
import shutil
|
6
8
|
import sys
|
7
9
|
|
8
|
-
from ybox.cmd import check_ybox_exists, run_command
|
10
|
+
from ybox.cmd import check_ybox_exists, parser_version_check, run_command
|
11
|
+
from ybox.config import Consts
|
9
12
|
from ybox.env import Environ
|
10
|
-
from ybox.print import fgcolor, print_color, print_error,
|
13
|
+
from ybox.print import (fgcolor, print_color, print_error, print_notice,
|
14
|
+
print_warn)
|
11
15
|
from ybox.state import YboxStateManagement
|
12
16
|
|
13
17
|
|
@@ -31,9 +35,21 @@ def main_argv(argv: list[str]) -> None:
|
|
31
35
|
|
32
36
|
check_ybox_exists(docker_cmd, container_name, exit_on_error=True)
|
33
37
|
print_color(f"Stopping ybox container '{container_name}'", fg=fgcolor.cyan)
|
38
|
+
# check if there is a systemd service for the container
|
39
|
+
systemd_dir = f"{env.home}/.config/systemd/user"
|
40
|
+
ybox_svc = f"ybox-{container_name}.service"
|
41
|
+
ybox_svc_path = ""
|
42
|
+
if (systemctl := shutil.which("systemctl", path=os.pathsep.join(Consts.sys_bin_dirs()))) and \
|
43
|
+
not os.access(ybox_svc_path := f"{systemd_dir}/{ybox_svc}", os.R_OK):
|
44
|
+
ybox_svc_path = ""
|
45
|
+
|
34
46
|
# continue even if this fails since the container may already be in stopped state
|
35
|
-
|
36
|
-
|
47
|
+
if systemctl and ybox_svc_path:
|
48
|
+
run_command([systemctl, "--user", "stop", ybox_svc],
|
49
|
+
exit_on_error=False, error_msg=f"stopping '{container_name}'")
|
50
|
+
else:
|
51
|
+
run_command([docker_cmd, "container", "stop", container_name],
|
52
|
+
exit_on_error=False, error_msg=f"stopping '{container_name}'")
|
37
53
|
|
38
54
|
print_warn(f"Removing ybox container '{container_name}'")
|
39
55
|
rm_args = [docker_cmd, "container", "rm"]
|
@@ -42,12 +58,28 @@ def main_argv(argv: list[str]) -> None:
|
|
42
58
|
rm_args.append(container_name)
|
43
59
|
run_command(rm_args, error_msg=f"removing '{container_name}'")
|
44
60
|
|
61
|
+
# remove systemd service file and reload daemon
|
62
|
+
if systemctl and ybox_svc_path:
|
63
|
+
print_color(f"Removing systemd service '{ybox_svc}' and reloading daemon", fg=fgcolor.cyan)
|
64
|
+
run_command([systemctl, "--user", "disable", ybox_svc], exit_on_error=False)
|
65
|
+
os.unlink(ybox_svc_path)
|
66
|
+
try:
|
67
|
+
os.unlink(f"{systemd_dir}/.ybox-{container_name}.env")
|
68
|
+
except OSError:
|
69
|
+
pass
|
70
|
+
run_command([systemctl, "--user", "daemon-reload"], exit_on_error=False)
|
71
|
+
|
72
|
+
# check and remove any dangling container references in state database
|
73
|
+
valid_containers = set(get_all_containers(docker_cmd))
|
74
|
+
|
45
75
|
# remove the state from the database
|
46
76
|
print_warn(f"Clearing ybox state for '{container_name}'")
|
47
77
|
with YboxStateManagement(env) as state:
|
78
|
+
state.begin_transaction()
|
48
79
|
if not state.unregister_container(container_name):
|
49
80
|
print_error(f"No entry found for '{container_name}' in the state database")
|
50
81
|
sys.exit(1)
|
82
|
+
remove_orphans_from_db(valid_containers, state)
|
51
83
|
|
52
84
|
|
53
85
|
def parse_args(argv: list[str]) -> argparse.Namespace:
|
@@ -61,4 +93,35 @@ def parse_args(argv: list[str]) -> argparse.Namespace:
|
|
61
93
|
parser.add_argument("-f", "--force", action="store_true",
|
62
94
|
help="force destroy the container using SIGKILL if required")
|
63
95
|
parser.add_argument("container_name", type=str, help="name of the active ybox")
|
96
|
+
parser_version_check(parser, argv)
|
64
97
|
return parser.parse_args(argv)
|
98
|
+
|
99
|
+
|
100
|
+
def get_all_containers(docker_cmd: str) -> list[str]:
|
101
|
+
"""
|
102
|
+
Get all the valid containers as known to the container manager.
|
103
|
+
|
104
|
+
:param docker_cmd: the podman/docker executable to use
|
105
|
+
:return: list of valid container names
|
106
|
+
"""
|
107
|
+
result = run_command([docker_cmd, "container", "ls", "--all", "--format={{ .Names }}"],
|
108
|
+
capture_output=True, exit_on_error=False, error_msg="listing containers")
|
109
|
+
return [] if isinstance(result, int) else result.splitlines()
|
110
|
+
|
111
|
+
|
112
|
+
def remove_orphans_from_db(valid_containers: set[str], state: YboxStateManagement) -> None:
|
113
|
+
"""
|
114
|
+
Unregister orphan container entries from the state database. This takes the output of
|
115
|
+
:func:`get_all_containers` as argument and should be invoked inside `YboxStateManagement`
|
116
|
+
context manager (i.e. with state database as locked), while the call to `get_all_containers`
|
117
|
+
can be outside the lock.
|
118
|
+
|
119
|
+
:param valid_containers: set of valid container names from :func:`get_all_containers`
|
120
|
+
:param state: instance of `YboxStateManagement` having the state of all ybox containers
|
121
|
+
"""
|
122
|
+
if not os.environ.get("YBOX_TESTING"):
|
123
|
+
orphans = set(state.get_containers()) - valid_containers
|
124
|
+
if orphans:
|
125
|
+
print_notice(f"Removing orphan container entries from database: {', '.join(orphans)}")
|
126
|
+
for orphan in orphans:
|
127
|
+
state.unregister_container(orphan)
|
ybox/run/logs.py
CHANGED
@@ -6,7 +6,7 @@ ybox container.
|
|
6
6
|
import argparse
|
7
7
|
import sys
|
8
8
|
|
9
|
-
from ybox.cmd import check_ybox_exists, run_command
|
9
|
+
from ybox.cmd import check_ybox_exists, parser_version_check, run_command
|
10
10
|
from ybox.env import get_docker_command
|
11
11
|
from ybox.print import print_info
|
12
12
|
|
@@ -54,4 +54,5 @@ def parse_args(argv: list[str]) -> argparse.Namespace:
|
|
54
54
|
parser.add_argument("-f", "--follow", action="store_true",
|
55
55
|
help="follow log output like 'tail -f'")
|
56
56
|
parser.add_argument("container_name", type=str, help="name of the running ybox")
|
57
|
+
parser_version_check(parser, argv)
|
57
58
|
return parser.parse_args(argv)
|
ybox/run/ls.py
CHANGED
@@ -5,7 +5,7 @@ Code for the `ybox-ls` script that is used to show the active or stopped ybox co
|
|
5
5
|
import argparse
|
6
6
|
import sys
|
7
7
|
|
8
|
-
from ybox.cmd import YboxLabel, run_command
|
8
|
+
from ybox.cmd import YboxLabel, parser_version_check, run_command
|
9
9
|
from ybox.env import get_docker_command
|
10
10
|
|
11
11
|
|
@@ -61,4 +61,5 @@ def parse_args(argv: list[str]) -> argparse.Namespace:
|
|
61
61
|
"https://docs.docker.com/reference/cli/docker/container/ls)")
|
62
62
|
parser.add_argument("-l", "--long-format", action="store_true",
|
63
63
|
help="display extended information without truncating fields")
|
64
|
+
parser_version_check(parser, argv)
|
64
65
|
return parser.parse_args(argv)
|
ybox/run/pkg.py
CHANGED
@@ -7,7 +7,8 @@ import argparse
|
|
7
7
|
import sys
|
8
8
|
from typing import cast
|
9
9
|
|
10
|
-
from ybox.cmd import YboxLabel, check_active_ybox,
|
10
|
+
from ybox.cmd import (YboxLabel, check_active_ybox, parser_version_check,
|
11
|
+
run_command)
|
11
12
|
from ybox.config import Consts, StaticConfiguration
|
12
13
|
from ybox.env import Environ
|
13
14
|
from ybox.pkg.clean import clean_cache
|
@@ -61,6 +62,29 @@ def main_argv(argv: list[str]) -> None:
|
|
61
62
|
elif not containers:
|
62
63
|
print_error("No active ybox container found!")
|
63
64
|
sys.exit(1)
|
65
|
+
elif args.group_by_shared_root:
|
66
|
+
with YboxStateManagement(env) as state:
|
67
|
+
entries = state.get_containers_grouped_by_shared_root(containers)
|
68
|
+
if not entries:
|
69
|
+
print_error(f"No containers in state database for: {', '.join(containers)}")
|
70
|
+
sys.exit(1)
|
71
|
+
if len(entries) == 1:
|
72
|
+
# select the first container in the list for the shared_root
|
73
|
+
container_name = entries[0][0][0]
|
74
|
+
elif args.quiet:
|
75
|
+
msg = "\n ".join([", ".join(t[0]) + (" on " + t[1] if t[1] else " (not shared)")
|
76
|
+
for t in entries])
|
77
|
+
print_error(
|
78
|
+
f"Expected one activate container or shared root but found:\n {msg}")
|
79
|
+
sys.exit(1)
|
80
|
+
else:
|
81
|
+
# display as container names grouped by distribution and shared_root
|
82
|
+
selection_list = [" / ".join(t[0]) + " : distro '" + t[2] +
|
83
|
+
("' on " + t[1] if t[1] else "' (not shared)") for t in entries]
|
84
|
+
print_info("Please select the container to use:", file=sys.stderr)
|
85
|
+
if (selection := select_item_from_menu(selection_list)) is None:
|
86
|
+
sys.exit(1)
|
87
|
+
container_name = selection[:selection.index(" ")]
|
64
88
|
elif args.quiet:
|
65
89
|
print_error(
|
66
90
|
f"Expected one active ybox container but found: {', '.join(containers)}")
|
@@ -73,6 +97,7 @@ def main_argv(argv: list[str]) -> None:
|
|
73
97
|
if not args.quiet:
|
74
98
|
print_info(f"Running the operation on '{container_name}'", file=sys.stderr)
|
75
99
|
|
100
|
+
code = 0
|
76
101
|
with YboxStateManagement(env) as state:
|
77
102
|
# ensure that all state database changes are done as a single transaction and only applied
|
78
103
|
# if there were no failures (commit/rollback are automatic at the end of `with`)
|
@@ -93,10 +118,14 @@ def main_argv(argv: list[str]) -> None:
|
|
93
118
|
if args.is_repo_cmd:
|
94
119
|
code = args.func(args, pkgmgr, distro_config["repo"], docker_cmd, conf,
|
95
120
|
runtime_conf, state)
|
96
|
-
|
121
|
+
elif args.needs_state:
|
97
122
|
code = args.func(args, pkgmgr, docker_cmd, conf, runtime_conf, state)
|
98
|
-
|
99
|
-
|
123
|
+
|
124
|
+
# when "state" is not needed then run the command outside the with block to release the db lock
|
125
|
+
if not args.is_repo_cmd and not args.needs_state:
|
126
|
+
code = args.func(args, pkgmgr, docker_cmd, conf)
|
127
|
+
if code != 0:
|
128
|
+
sys.exit(code) # state will be automatically rolled back for exceptions
|
100
129
|
|
101
130
|
|
102
131
|
def parse_args(argv: list[str]) -> argparse.Namespace:
|
@@ -129,6 +158,7 @@ def parse_args(argv: list[str]) -> argparse.Namespace:
|
|
129
158
|
"mark a package as a dependency or an explicitly installed package"))
|
130
159
|
add_repair(add_subparser(operations, "repair",
|
131
160
|
"try to repair state after a failed operation or an interrupt/kill"))
|
161
|
+
parser_version_check(parser, argv)
|
132
162
|
return parser.parse_args(argv)
|
133
163
|
|
134
164
|
|
@@ -146,6 +176,10 @@ def add_subparser(operations, name: str, hlp: str) -> argparse.ArgumentParser:
|
|
146
176
|
add_common_args(subparser)
|
147
177
|
# by default set the flag for repository command as false
|
148
178
|
subparser.set_defaults(is_repo_cmd=False)
|
179
|
+
# set the flag to require state database by default
|
180
|
+
subparser.set_defaults(needs_state=True)
|
181
|
+
# don't group by shared_root by default
|
182
|
+
subparser.set_defaults(group_by_shared_root=False)
|
149
183
|
return subparser
|
150
184
|
|
151
185
|
|
@@ -245,6 +279,7 @@ def add_update(subparser: argparse.ArgumentParser) -> None:
|
|
245
279
|
help="the packages to update if provided, else update the entire "
|
246
280
|
"installation of the container (which will end up updating all "
|
247
281
|
"other containers sharing the same root if configured)")
|
282
|
+
subparser.set_defaults(group_by_shared_root=True)
|
248
283
|
subparser.set_defaults(func=update_packages)
|
249
284
|
|
250
285
|
|
@@ -291,6 +326,7 @@ def add_list_files(subparser: argparse.ArgumentParser) -> None:
|
|
291
326
|
"""
|
292
327
|
add_pager_arg(subparser)
|
293
328
|
subparser.add_argument("package", type=str, help="list files of this package")
|
329
|
+
subparser.set_defaults(needs_state=False)
|
294
330
|
subparser.set_defaults(func=list_files)
|
295
331
|
|
296
332
|
|
@@ -310,6 +346,8 @@ def add_search(subparser: argparse.ArgumentParser) -> None:
|
|
310
346
|
"(e.g. skip AUR repository on Arch Linux)")
|
311
347
|
add_pager_arg(subparser)
|
312
348
|
subparser.add_argument("search", nargs="+", help="one or more search terms")
|
349
|
+
subparser.set_defaults(needs_state=False)
|
350
|
+
subparser.set_defaults(group_by_shared_root=True)
|
313
351
|
subparser.set_defaults(func=search_packages)
|
314
352
|
|
315
353
|
|
@@ -326,6 +364,7 @@ def add_info(subparser: argparse.ArgumentParser) -> None:
|
|
326
364
|
"otherwise search only among the installed packages")
|
327
365
|
add_pager_arg(subparser)
|
328
366
|
subparser.add_argument("packages", nargs="+", help="one or more packages")
|
367
|
+
subparser.set_defaults(needs_state=False)
|
329
368
|
subparser.set_defaults(func=info_packages)
|
330
369
|
|
331
370
|
|
@@ -337,6 +376,8 @@ def add_clean(subparser: argparse.ArgumentParser) -> None:
|
|
337
376
|
|
338
377
|
:param subparser: the :class:`argparse.ArgumentParser` object for the sub-command
|
339
378
|
"""
|
379
|
+
subparser.set_defaults(needs_state=False)
|
380
|
+
subparser.set_defaults(group_by_shared_root=True)
|
340
381
|
subparser.set_defaults(func=clean_cache)
|
341
382
|
|
342
383
|
|
@@ -372,6 +413,7 @@ def add_repair(subparser: argparse.ArgumentParser) -> None:
|
|
372
413
|
help="repair thoroughly by reinstalling all packages; CAUTION: use "
|
373
414
|
"this only if the normal repair fails and the system cannot be "
|
374
415
|
"recovered otherwise")
|
416
|
+
subparser.set_defaults(group_by_shared_root=True)
|
375
417
|
subparser.set_defaults(func=repair_package_state)
|
376
418
|
|
377
419
|
|
ybox/state.py
CHANGED
@@ -344,9 +344,8 @@ class YboxStateManagement:
|
|
344
344
|
if self._version == old_version:
|
345
345
|
return
|
346
346
|
# run appropriate SQL migration scripts for product version change
|
347
|
-
|
348
|
-
|
349
|
-
return
|
347
|
+
scripts = self._filter_and_sort_files_by_version(
|
348
|
+
files("ybox").joinpath("migrate").iterdir(), old_version, self._version, ".py")
|
350
349
|
for script in scripts:
|
351
350
|
print_color(f"Running migration script '{script}' for container version upgrade from "
|
352
351
|
f"{old_version} to {self._version}")
|
@@ -559,6 +558,26 @@ class YboxStateManagement:
|
|
559
558
|
pass
|
560
559
|
return shared_containers
|
561
560
|
|
561
|
+
def get_containers_grouped_by_shared_root(self, containers: list[str]) -> list[
|
562
|
+
tuple[list[str], str, str]]:
|
563
|
+
"""
|
564
|
+
Get the containers grouped by their `shared_root`s, if present, else as separate entries.
|
565
|
+
|
566
|
+
:param containers: list of containers to include, or empty to include all containers
|
567
|
+
:return: list of tuple of (container list, shared_root, distribution) matching given
|
568
|
+
containers (or all containers if empty list provided)
|
569
|
+
"""
|
570
|
+
in_list = "name IN (" + ("?, " * (len(containers) - 1)) + "?) AND " if containers else ""
|
571
|
+
# using default "," to separate container names since a container name cannot have it
|
572
|
+
# (see the regex check in ybox.run.create.process_args)
|
573
|
+
with closing(cursor := self._conn.execute(
|
574
|
+
f"""SELECT STRING_AGG(name, ','), shared_root, MIN(distribution) FROM containers
|
575
|
+
WHERE {in_list}NOT destroyed
|
576
|
+
GROUP BY CASE WHEN length(shared_root) = 0 THEN name ELSE shared_root END""",
|
577
|
+
containers)):
|
578
|
+
rows = cursor.fetchall()
|
579
|
+
return [(str(row[0]).split(","), str(row[1]), str(row[2])) for row in rows]
|
580
|
+
|
562
581
|
def register_package(self, container_name: str, package: str, local_copies: list[str],
|
563
582
|
copy_type: CopyType, app_flags: dict[str, str], shared_root: str,
|
564
583
|
dep_type: Optional[DependencyType], dep_of: str,
|
ybox/util.py
CHANGED
@@ -220,7 +220,7 @@ def get_ybox_version(conf: StaticConfiguration) -> str:
|
|
220
220
|
return ""
|
221
221
|
|
222
222
|
|
223
|
-
def wait_for_ybox_container(docker_cmd: str, conf: StaticConfiguration) -> None:
|
223
|
+
def wait_for_ybox_container(docker_cmd: str, conf: StaticConfiguration, timeout: int) -> None:
|
224
224
|
"""
|
225
225
|
Wait for container created with `create.start_container` to finish all its initialization.
|
226
226
|
This depends on the specific entrypoint script used by `create.start_container` to write
|
@@ -229,10 +229,10 @@ def wait_for_ybox_container(docker_cmd: str, conf: StaticConfiguration) -> None:
|
|
229
229
|
|
230
230
|
:param docker_cmd: the podman/docker executable to use
|
231
231
|
:param conf: the :class:`StaticConfiguration` for the container
|
232
|
+
:param timeout: seconds to wait for container to start before exiting with failure code 1
|
232
233
|
"""
|
233
234
|
sys.stdout.flush()
|
234
235
|
box_name = conf.box_name
|
235
|
-
max_wait_secs = 600
|
236
236
|
status_line = "" # keeps the last valid line read from status file
|
237
237
|
with open(conf.status_file, "r", encoding="utf-8") as status_fd:
|
238
238
|
|
@@ -251,7 +251,7 @@ def wait_for_ybox_container(docker_cmd: str, conf: StaticConfiguration) -> None:
|
|
251
251
|
print(line, end="") # line already includes the terminating newline
|
252
252
|
return False
|
253
253
|
|
254
|
-
for _ in range(
|
254
|
+
for _ in range(timeout):
|
255
255
|
# check the container status first which may be running or stopping
|
256
256
|
# in which case sleep and retry (if stopped, then read_lines should succeed)
|
257
257
|
if get_ybox_state(docker_cmd, box_name, expected_states=("running", "stopping")):
|
@@ -267,8 +267,8 @@ def wait_for_ybox_container(docker_cmd: str, conf: StaticConfiguration) -> None:
|
|
267
267
|
# using simple poll per second rather than inotify or similar because the
|
268
268
|
# initialization can take a good amount of time and second granularity is enough
|
269
269
|
time.sleep(1)
|
270
|
-
# reading did not end after
|
271
|
-
print_error(f"TIMED OUT waiting for ready container after {
|
270
|
+
# reading did not end after timeout
|
271
|
+
print_error(f"TIMED OUT waiting for ready container after {timeout}secs (last status: "
|
272
272
|
f"{status_line}).\nCheck 'ybox-logs -f {box_name}' for more details.")
|
273
273
|
sys.exit(1)
|
274
274
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: ybox
|
3
|
-
Version: 0.9.
|
3
|
+
Version: 0.9.10
|
4
4
|
Summary: Securely run Linux distribution inside a container
|
5
5
|
Author-email: Sumedh Wale <sumwale@yahoo.com>, Vishal Rao <vishalrao@gmail.com>
|
6
6
|
License: Copyright (c) 2024-2025 Sumedh Wale and contributors
|
@@ -35,6 +35,7 @@ Classifier: Programming Language :: Python :: 3.9
|
|
35
35
|
Classifier: Programming Language :: Python :: 3.10
|
36
36
|
Classifier: Programming Language :: Python :: 3.11
|
37
37
|
Classifier: Programming Language :: Python :: 3.12
|
38
|
+
Classifier: Programming Language :: Python :: 3.13
|
38
39
|
Requires-Python: >=3.9
|
39
40
|
Description-Content-Type: text/markdown
|
40
41
|
License-File: LICENSE
|
@@ -54,7 +55,17 @@ of the container including directories to be shared, logging etc.
|
|
54
55
|
|
55
56
|
Special emphasis is given on security where users can choose to lock down
|
56
57
|
or open up the container as required with reasonable defaults out of the
|
57
|
-
box. There is no sharing of HOME or no privileged mode container.
|
58
|
+
box. There is no sharing of HOME or no privileged mode container. This sets
|
59
|
+
it apart from other similar solutions like distrobox/toolbx and the reason
|
60
|
+
for starting this project since those other solutions don't care about
|
61
|
+
security/sandboxing at all and share the entire HOME while running the
|
62
|
+
containers in privileged mode. The other problem with those solutions is that
|
63
|
+
the shared HOME means that the user's configuration dot files also get shared
|
64
|
+
and can cause all kinds of trouble where container apps can overwrite
|
65
|
+
with their own versions (especially for updated apps in the containers)
|
66
|
+
breaking the app in the host system. It is, however, possible to share the
|
67
|
+
entire HOME if user really wants but that needs to be explcitly configured
|
68
|
+
in the ini profile.
|
58
69
|
|
59
70
|
Expected usage is for users to group similar applications in a container
|
60
71
|
and separate out containers depending on different needs like higher/lower
|
@@ -144,10 +155,11 @@ require you to install in a custom virtual environment which can be done manuall
|
|
144
155
|
fish: `python3 -m venv ybox-venv && source ybox-env/bin/activate.fish`)
|
145
156
|
or automatically using `pipx`. Alternatively you can add `--break-system-packages`
|
146
157
|
flag to the `pip` command above or add it globally for all future packages using
|
147
|
-
`python3 -m pip config set global.break-system-packages true`.
|
148
|
-
approach works well for `ybox` which has a very minimal set of dependencies
|
149
|
-
|
150
|
-
|
158
|
+
`python3 -m pip config set global.break-system-packages true`. This alternative
|
159
|
+
approach works well for `ybox` which has a very minimal set of dependencies which will
|
160
|
+
not conflict with system packages (rather work with whatever system version is installed),
|
161
|
+
but if you prefer keeping the installation separate then use `pipx` or
|
162
|
+
a manual virtual environment.
|
151
163
|
|
152
164
|
Now you can run the `ybox-create` and other utilities that are normally installed
|
153
165
|
in your `~/.local/bin` directory which should be in PATH for modern Linux distributions.
|
@@ -209,7 +221,9 @@ does not run properly as root, then you cannot run it when using docker unless y
|
|
209
221
|
`sudo/su` to the host user in the container command. However, running as host user when running
|
210
222
|
rootless docker will map to a different user ID in the host (as specified in `/etc/subuid` on the
|
211
223
|
host) so files shared with the host, including devices like those in `/dev/dri`, will cause
|
212
|
-
permission issues that can hinder or break the application.
|
224
|
+
permission issues that can hinder or break the application. Hence it is recommended to
|
225
|
+
just install podman (even if you already have docker installed) which works out of the
|
226
|
+
box in rootless mode in all tested distributions.
|
213
227
|
|
214
228
|
|
215
229
|
### Package management: install/uninstall/list/search/...
|
@@ -448,8 +462,8 @@ systemctl --user enable container-ybox-arch_apps.service
|
|
448
462
|
|
449
463
|
Virtual environment setup have been provided for consistent development, test and build
|
450
464
|
with multiple python versions. The minimum python version required is 3.9 and tests are
|
451
|
-
run against all major python versions higher than that (i.e. 3.10, 3.11, 3.12 and
|
452
|
-
in future).
|
465
|
+
run against all major python versions higher than that (i.e. 3.10, 3.11, 3.12, 3.13 and
|
466
|
+
others in future).
|
453
467
|
|
454
468
|
The setup uses pyenv with venv which can be used for development with IDEA/PyCharm/VSCode
|
455
469
|
or in terminal, running tests against all supported python versions using `tox` etc.
|
@@ -476,14 +490,23 @@ Next you can install the required python versions and venv environment:
|
|
476
490
|
pyenv/setup-venv.sh
|
477
491
|
```
|
478
492
|
|
479
|
-
Finally, you can activate it
|
493
|
+
Finally, you can activate it.
|
494
|
+
|
495
|
+
bash:
|
496
|
+
|
497
|
+
```sh
|
498
|
+
source pyenv/activate.bash
|
499
|
+
source .venv/bin/activate
|
500
|
+
```
|
501
|
+
|
502
|
+
zsh:
|
480
503
|
|
481
504
|
```sh
|
482
|
-
source pyenv/activate.
|
505
|
+
source pyenv/activate.zsh
|
483
506
|
source .venv/bin/activate
|
484
507
|
```
|
485
508
|
|
486
|
-
|
509
|
+
fish:
|
487
510
|
|
488
511
|
```
|
489
512
|
source pyenv/activate.fish
|
@@ -1,20 +1,20 @@
|
|
1
|
-
ybox/__init__.py,sha256=
|
2
|
-
ybox/cmd.py,sha256=
|
3
|
-
ybox/config.py,sha256=
|
1
|
+
ybox/__init__.py,sha256=jQDT4EtS19JjBbrvOVG5G0Vzpcw9ZsATD9wt6wNRr1s,97
|
2
|
+
ybox/cmd.py,sha256=RaNZ7LBqUNwpqQkitR29WLoItjkMfZmaFEeryLTR_tM,14962
|
3
|
+
ybox/config.py,sha256=inmuUhlAZb6EKLGYWdymsqoHggtiLd58kc125l25ACA,9943
|
4
4
|
ybox/env.py,sha256=vfHuvTOpApR4fLx1vePWRrTYxzo50c-7dFcnm1-vDHo,8738
|
5
5
|
ybox/filelock.py,sha256=nWBp3jvbtrNziRzNcWm6FVVA_lhMccLwgLCVT2IDK5c,3185
|
6
6
|
ybox/print.py,sha256=hAQjTb6JmtjWh0sF4GdZHcKRph5iMKP5x23s8LE85q4,4343
|
7
|
-
ybox/state.py,sha256=
|
8
|
-
ybox/util.py,sha256=
|
9
|
-
ybox/conf/completions/ybox.fish,sha256=
|
7
|
+
ybox/state.py,sha256=QSAfa4LGy7oDZVe6muBXFIylKB7CMalv3OgEQ3VtmAo,50174
|
8
|
+
ybox/util.py,sha256=D4OgNCH0LXyHR9x0dCXCgkLFGvfgy--mqUbDbZRPobg,16520
|
9
|
+
ybox/conf/completions/ybox.fish,sha256=zTfCb0XvTzzZUbYuIxV1BNSSpUZ1qbkbA5L4SfReLhc,6035
|
10
10
|
ybox/conf/distros/supported.list,sha256=KAN7lbNfbRqF20KqEd0-BzF8U5uPx4n9h0W9zVh9z5o,52
|
11
11
|
ybox/conf/distros/arch/add-gpg-key.sh,sha256=kLMCT15hYadjhInYwQiiyF4u6rJl8n4gGfzEKuMKvTg,644
|
12
12
|
ybox/conf/distros/arch/distro.ini,sha256=NlCnhU4mmO9nE08BcO7hEQ83osMbHgIhLYybGG5rCNc,11026
|
13
13
|
ybox/conf/distros/arch/init-base.sh,sha256=eqdVzrMqP0hP52S_xxYZJ8n1lStlPn-eSP2e4DpHvWc,311
|
14
|
-
ybox/conf/distros/arch/init-user.sh,sha256=
|
15
|
-
ybox/conf/distros/arch/init.sh,sha256=
|
14
|
+
ybox/conf/distros/arch/init-user.sh,sha256=tb_NX4xNRU2pSuuVf2jSb7019uLfxBDbKI7ZyOtzSA4,1127
|
15
|
+
ybox/conf/distros/arch/init.sh,sha256=7f96YVjgQnOWItaxDjllgOl4LD9ibqzuhSk2QbDutvU,3578
|
16
16
|
ybox/conf/distros/arch/list_fmt_long.py,sha256=Ws9Mt9CKInxqUSn98P6-Csik2QqEjyBHp5NyUHlbcoU,2825
|
17
|
-
ybox/conf/distros/arch/pkgdeps.py,sha256=
|
17
|
+
ybox/conf/distros/arch/pkgdeps.py,sha256=Y77N1xHmHZRyZ9_diFVvoqBd44lZXIIJ2ipX7YVlrT8,14081
|
18
18
|
ybox/conf/distros/deb-generic/check-package.sh,sha256=bMiOi6Cp_UrtXm_sXOWBq4Xng2EwXYerqBuRLtGYIlo,2621
|
19
19
|
ybox/conf/distros/deb-generic/distro.ini,sha256=ZDWJG-cvx1BuI2RwynIvDwxzuzvVaYNv68PD-J57t84,11361
|
20
20
|
ybox/conf/distros/deb-generic/fetch-gpg-key-id.sh,sha256=sTsLWILZosYJcGV1u8qBdczQAFBda2Zlsp1xbpy8nzo,836
|
@@ -22,45 +22,46 @@ ybox/conf/distros/deb-generic/init-base.sh,sha256=rim7UckGos0phyOAiNYbIjOVG9C4gK
|
|
22
22
|
ybox/conf/distros/deb-generic/init-user.sh,sha256=RDt9sZuv6cSX1WBaRGcLMq2ZTBhVZmZVWD1t0wjvizU,20
|
23
23
|
ybox/conf/distros/deb-generic/init.sh,sha256=KW0a76BJm75VHDaLPCE4MdLThcy__NpE6Z8pLB0Q7IM,5748
|
24
24
|
ybox/conf/distros/deb-generic/list_fmt_long.py,sha256=66sOC0Uzv5nuTRaQQ_9R-GFJju4PSPXNlXv_eHmx57k,5701
|
25
|
-
ybox/conf/distros/deb-generic/pkgdeps.py,sha256=
|
25
|
+
ybox/conf/distros/deb-generic/pkgdeps.py,sha256=CKIJbftIjicGoGoYqScqb9zPZuKqT3r-gL9CRyraNbk,10571
|
26
26
|
ybox/conf/distros/deb-oldstable/distro.ini,sha256=lr7140ftndEvs3Liavf3hg3v0qHHWAn0RRm_HAQTw8M,1103
|
27
27
|
ybox/conf/distros/deb-stable/distro.ini,sha256=xyQ31mLOpj3Z1MK-UYuc_9NfEkb7Gy10MdDKXMgnqDo,1100
|
28
28
|
ybox/conf/distros/ubuntu2204/distro.ini,sha256=3Pw1Q30USyKMUcHp_cvlqhwyU0FPo8O2AHWkgd0cdE4,1105
|
29
29
|
ybox/conf/distros/ubuntu2404/distro.ini,sha256=ra4_EteDsHrw9UcehP4qLGTn98gAHc4JCb56CDzz1Wo,1102
|
30
30
|
ybox/conf/profiles/apps.ini,sha256=9GCZJvdB5yOfx-mXyti3M-YQjeLnugrhOp43sQQvqQ0,1001
|
31
|
-
ybox/conf/profiles/basic.ini,sha256=
|
32
|
-
ybox/conf/profiles/dev.ini,sha256=
|
31
|
+
ybox/conf/profiles/basic.ini,sha256=mQuksPFcIoi1K-tsZxIpKhbNGe8Ltjquo0MacPoUUwE,18952
|
32
|
+
ybox/conf/profiles/dev.ini,sha256=joSqLKrtokX4Tabn-EcxB4t7YhXlIV6ZnX3imCAPGaI,755
|
33
33
|
ybox/conf/profiles/games.ini,sha256=FiBILNFOMpjKhrIR9nPbPj9QDUeI5h9wZaNXIb6Z7dc,1792
|
34
34
|
ybox/conf/resources/entrypoint-base.sh,sha256=hcW8ZLHM-jlHx7McoKTo8HIFz_VBBPD0I3WqlX7LjHs,4890
|
35
35
|
ybox/conf/resources/entrypoint-common.sh,sha256=fMopKBLeGuVV0ukANXh_ZHGTR1yGq108CTN_M2MNPyQ,461
|
36
36
|
ybox/conf/resources/entrypoint-cp.sh,sha256=4R1UA2YLcKH_tUcyiioHSJA5B_t7GT1Z9gVFnCMi2a0,813
|
37
|
-
ybox/conf/resources/entrypoint-root.sh,sha256=
|
38
|
-
ybox/conf/resources/entrypoint-user.sh,sha256=
|
39
|
-
ybox/conf/resources/entrypoint.sh,sha256=
|
40
|
-
ybox/conf/resources/prime-run,sha256=
|
41
|
-
ybox/conf/resources/run-in-dir,sha256=
|
42
|
-
ybox/conf/resources/run-user-bash-cmd,sha256=
|
37
|
+
ybox/conf/resources/entrypoint-root.sh,sha256=YhCftc4hYh3qKw0uEgYhHgitGY-KFGfHCxrHIMw9lHA,703
|
38
|
+
ybox/conf/resources/entrypoint-user.sh,sha256=Tps_UyQGyGn30LbgKm3gpzZtjOHnJpnlKx-px2GAd7A,698
|
39
|
+
ybox/conf/resources/entrypoint.sh,sha256=jD4_C-2YtGwJ4pe2KfxfOtJll2Kv3F4YBU0WuhFQg9w,8716
|
40
|
+
ybox/conf/resources/prime-run,sha256=en8wEspc2Hzod9rq8KKnPQrjIPTLjUk44TqmtX-g0sw,339
|
41
|
+
ybox/conf/resources/run-in-dir,sha256=WyYwCE56yuaMqoI1wGeil6UzycnlI6xxfy2iC92LDt4,1934
|
42
|
+
ybox/conf/resources/run-user-bash-cmd,sha256=LMlPoHtzYNDcOI885ouBha9xGRnQ6AWCFVsSu2dxy10,1065
|
43
|
+
ybox/conf/resources/ybox-systemd.template,sha256=-6Ui-J3GgW0VGoBdHlL7KCcGIrIgylXSKQvyzrKk7yE,647
|
43
44
|
ybox/migrate/0.9.0-0.9.7:0.9.8.py,sha256=N7O7HtoMh_l404v2bHG5Od-_4fCDFMUBZ1SeT1P9F4M,1582
|
44
45
|
ybox/pkg/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
45
|
-
ybox/pkg/clean.py,sha256=
|
46
|
-
ybox/pkg/info.py,sha256=
|
47
|
-
ybox/pkg/inst.py,sha256=
|
48
|
-
ybox/pkg/list.py,sha256=
|
46
|
+
ybox/pkg/clean.py,sha256=UlsrJLfZOyKg-7BE8s9xPvAyuUXSwvU5x-E7MMjGJSE,1219
|
47
|
+
ybox/pkg/info.py,sha256=HoEsiAi-iPEnAOWBMy9SsA4TOfyqHonRURU8k5EeAWA,1607
|
48
|
+
ybox/pkg/inst.py,sha256=MxOfkY166En8vzyBN1FysXlpopxb4_0u5bAdmL7jgmw,36046
|
49
|
+
ybox/pkg/list.py,sha256=Sk5THAmF132HKEZxJVDlqLLR8Z2w1wRA_E-gBsxlesQ,10097
|
49
50
|
ybox/pkg/mark.py,sha256=cdTOKpo7Vb8j8lM0oZxdvAsJpIktnskyHWd6vEt-pG0,3748
|
50
|
-
ybox/pkg/repair.py,sha256=
|
51
|
+
ybox/pkg/repair.py,sha256=rCwXXJbilJYU73feIIVWGFdbkh6SDcquxgiEnYV6pNs,8080
|
51
52
|
ybox/pkg/repo.py,sha256=25gQgGMPeHgX83iqqWXyG6V6rIZ4i_KEnIbNG-CrxTk,13677
|
52
|
-
ybox/pkg/search.py,sha256=
|
53
|
+
ybox/pkg/search.py,sha256=GKfonxCLHtH-kojZpRJlRfe0qf768wUehVv20nM4lKY,2526
|
53
54
|
ybox/pkg/uninst.py,sha256=ndqZ_WYr9HE5jVL1tQ_tTmSPyTFM6OJRCTLLmG-Qm4w,5338
|
54
55
|
ybox/pkg/update.py,sha256=M-1MC8oh-baTHdSPWUUSTU_AhN3eu2nTCSge3bb6GmI,3269
|
55
56
|
ybox/run/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
56
|
-
ybox/run/cmd.py,sha256=
|
57
|
-
ybox/run/control.py,sha256=
|
58
|
-
ybox/run/create.py,sha256=
|
59
|
-
ybox/run/destroy.py,sha256=
|
57
|
+
ybox/run/cmd.py,sha256=a77RMC14Vovx2NV3LgdAzXVZXStC1TucgjcHPz4x03A,2105
|
58
|
+
ybox/run/control.py,sha256=9-ETodWye6A6eUNGKYWrXtNGCHz0eC452N_ZQNXiIiI,7006
|
59
|
+
ybox/run/create.py,sha256=DXEs1bXlC7tDK4PKNI2_O8PzRaDwuwmgN9Hy0CFDSV4,70109
|
60
|
+
ybox/run/destroy.py,sha256=nbF0dvjTqqepFo2c3a0IlUxDuLrBtFqPqP-z96eRMH4,5467
|
60
61
|
ybox/run/graphics.py,sha256=635Ry0sXIKCpM14ZPDHsQfw-xHNARbvaaAFNDpx3oo4,18991
|
61
|
-
ybox/run/logs.py,sha256=
|
62
|
-
ybox/run/ls.py,sha256=
|
63
|
-
ybox/run/pkg.py,sha256=
|
62
|
+
ybox/run/logs.py,sha256=pIdMWgNBNl-MgixArbMryUuBNNbi5JvDFP62IZ7jwr8,2050
|
63
|
+
ybox/run/ls.py,sha256=7ylyxOOYEsVWK8baM0GaZcUlVQBwpdGiF7EhU09xf2s,2787
|
64
|
+
ybox/run/pkg.py,sha256=dmv0iW-0KmcG400lRCcxQ1QCiiWJTda2kGJ1dRwyP_k,27219
|
64
65
|
ybox/schema/0.9.1-added.sql,sha256=1rGp2DczZmmC_xwjmheeZNPSbDpFzasu6LO3tpTy3zI,1049
|
65
66
|
ybox/schema/0.9.6-added.sql,sha256=Qcho6dP5OUpPUW3IBWl_kv88agMPHzueUAKqnZPnt3U,809
|
66
67
|
ybox/schema/init.sql,sha256=fei8lPvjb-EIjm5zuA_XkEdjsIE3vtROhgRPt7QMlSs,1599
|
@@ -68,9 +69,9 @@ ybox/schema/migrate/0.9.0:0.9.1.sql,sha256=e9JGwrjFZXdWKGv2JQZlKcWz8DmOuUARpToSs
|
|
68
69
|
ybox/schema/migrate/0.9.1:0.9.2.sql,sha256=X5J3unDS0eLeVvYKxQgx-iUBoAOk9T2suO34pWlQ-lE,362
|
69
70
|
ybox/schema/migrate/0.9.2:0.9.3.sql,sha256=Y7GeBSuEEs7Hs9hh-KYDARgeeMgwQwercvTB5P_-k6I,102
|
70
71
|
ybox/schema/migrate/0.9.5:0.9.6.sql,sha256=wqYhmputlUQzBI5zfP7O5kqIFWAbZQ05kolyHK4714A,70
|
71
|
-
ybox-0.9.
|
72
|
-
ybox-0.9.
|
73
|
-
ybox-0.9.
|
74
|
-
ybox-0.9.
|
75
|
-
ybox-0.9.
|
76
|
-
ybox-0.9.
|
72
|
+
ybox-0.9.10.dist-info/LICENSE,sha256=7GbFgERMXSwD1VyLA5bo_XHvJipmNEUhDW5Sy51TFeY,1077
|
73
|
+
ybox-0.9.10.dist-info/METADATA,sha256=oRc9oG6OSP28XaYhfRtp3sAXXqjkPKDEamSCtU-NHLk,24759
|
74
|
+
ybox-0.9.10.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
|
75
|
+
ybox-0.9.10.dist-info/entry_points.txt,sha256=xDlI_84Hl3ytYO_ERyt0rkJ4ioUF8Z1r49Hx1xL28Rk,243
|
76
|
+
ybox-0.9.10.dist-info/top_level.txt,sha256=DYX7jvndHcBaJXLJ8vDyKrq0_KWoSeXXFq8r0d5L6Nk,5
|
77
|
+
ybox-0.9.10.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|