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.
Files changed (76) hide show
  1. ybox/__init__.py +2 -0
  2. ybox/cmd.py +307 -0
  3. ybox/conf/completions/ybox.fish +93 -0
  4. ybox/conf/distros/arch/add-gpg-key.sh +29 -0
  5. ybox/conf/distros/arch/distro.ini +192 -0
  6. ybox/conf/distros/arch/init-base.sh +10 -0
  7. ybox/conf/distros/arch/init-user.sh +35 -0
  8. ybox/conf/distros/arch/init.sh +82 -0
  9. ybox/conf/distros/arch/list_fmt_long.py +76 -0
  10. ybox/conf/distros/arch/pkgdeps.py +276 -0
  11. ybox/conf/distros/deb-generic/check-package.sh +77 -0
  12. ybox/conf/distros/deb-generic/distro.ini +190 -0
  13. ybox/conf/distros/deb-generic/fetch-gpg-key-id.sh +30 -0
  14. ybox/conf/distros/deb-generic/init-base.sh +11 -0
  15. ybox/conf/distros/deb-generic/init-user.sh +3 -0
  16. ybox/conf/distros/deb-generic/init.sh +136 -0
  17. ybox/conf/distros/deb-generic/list_fmt_long.py +114 -0
  18. ybox/conf/distros/deb-generic/pkgdeps.py +208 -0
  19. ybox/conf/distros/deb-oldstable/distro.ini +21 -0
  20. ybox/conf/distros/deb-stable/distro.ini +21 -0
  21. ybox/conf/distros/supported.list +5 -0
  22. ybox/conf/distros/ubuntu2204/distro.ini +21 -0
  23. ybox/conf/distros/ubuntu2404/distro.ini +21 -0
  24. ybox/conf/profiles/apps.ini +26 -0
  25. ybox/conf/profiles/basic.ini +310 -0
  26. ybox/conf/profiles/dev.ini +25 -0
  27. ybox/conf/profiles/games.ini +39 -0
  28. ybox/conf/resources/entrypoint-base.sh +170 -0
  29. ybox/conf/resources/entrypoint-common.sh +23 -0
  30. ybox/conf/resources/entrypoint-cp.sh +32 -0
  31. ybox/conf/resources/entrypoint-root.sh +20 -0
  32. ybox/conf/resources/entrypoint-user.sh +21 -0
  33. ybox/conf/resources/entrypoint.sh +249 -0
  34. ybox/conf/resources/prime-run +13 -0
  35. ybox/conf/resources/run-in-dir +60 -0
  36. ybox/conf/resources/run-user-bash-cmd +14 -0
  37. ybox/config.py +255 -0
  38. ybox/env.py +205 -0
  39. ybox/filelock.py +77 -0
  40. ybox/migrate/0.9.0-0.9.7:0.9.8.py +33 -0
  41. ybox/pkg/__init__.py +0 -0
  42. ybox/pkg/clean.py +33 -0
  43. ybox/pkg/info.py +40 -0
  44. ybox/pkg/inst.py +638 -0
  45. ybox/pkg/list.py +191 -0
  46. ybox/pkg/mark.py +68 -0
  47. ybox/pkg/repair.py +150 -0
  48. ybox/pkg/repo.py +251 -0
  49. ybox/pkg/search.py +52 -0
  50. ybox/pkg/uninst.py +92 -0
  51. ybox/pkg/update.py +56 -0
  52. ybox/print.py +121 -0
  53. ybox/run/__init__.py +0 -0
  54. ybox/run/cmd.py +54 -0
  55. ybox/run/control.py +102 -0
  56. ybox/run/create.py +1116 -0
  57. ybox/run/destroy.py +64 -0
  58. ybox/run/graphics.py +367 -0
  59. ybox/run/logs.py +57 -0
  60. ybox/run/ls.py +64 -0
  61. ybox/run/pkg.py +445 -0
  62. ybox/schema/0.9.1-added.sql +27 -0
  63. ybox/schema/0.9.6-added.sql +18 -0
  64. ybox/schema/init.sql +39 -0
  65. ybox/schema/migrate/0.9.0:0.9.1.sql +42 -0
  66. ybox/schema/migrate/0.9.1:0.9.2.sql +8 -0
  67. ybox/schema/migrate/0.9.2:0.9.3.sql +2 -0
  68. ybox/schema/migrate/0.9.5:0.9.6.sql +2 -0
  69. ybox/state.py +914 -0
  70. ybox/util.py +351 -0
  71. ybox-0.9.8.dist-info/LICENSE +19 -0
  72. ybox-0.9.8.dist-info/METADATA +533 -0
  73. ybox-0.9.8.dist-info/RECORD +76 -0
  74. ybox-0.9.8.dist-info/WHEEL +5 -0
  75. ybox-0.9.8.dist-info/entry_points.txt +8 -0
  76. ybox-0.9.8.dist-info/top_level.txt +1 -0
ybox/pkg/search.py ADDED
@@ -0,0 +1,52 @@
1
+ """
2
+ Methods for searching packages in the repositories matching given search terms.
3
+ """
4
+
5
+ import argparse
6
+ import sys
7
+ from configparser import SectionProxy
8
+
9
+ from ybox.cmd import PkgMgr, page_command
10
+ from ybox.config import StaticConfiguration
11
+ from ybox.state import RuntimeConfiguration, YboxStateManagement
12
+
13
+
14
+ # noinspection PyUnusedLocal
15
+ def search_packages(args: argparse.Namespace, pkgmgr: SectionProxy, docker_cmd: str,
16
+ conf: StaticConfiguration, runtime_conf: RuntimeConfiguration,
17
+ state: YboxStateManagement) -> int:
18
+ # pylint: disable=unused-argument
19
+ """
20
+ Uninstall package specified by `args.package` on a ybox container with given podman/docker
21
+ command. Additional flags honored are `args.quiet` to bypass user confirmation during
22
+ uninstall, `args.keep_config_files` to keep the system configuration and/or data files
23
+ of the package, `args.skip_deps` to skip removal of all orphaned dependencies of the package
24
+ (including required and optional dependencies).
25
+
26
+ :param args: arguments having `search` and all other attributes passed by the user
27
+ :param pkgmgr: the `[pkgmgr]` section from `distro.ini` configuration file of the distribution
28
+ :param docker_cmd: the podman/docker executable to use
29
+ :param conf: the :class:`StaticConfiguration` for the container
30
+ :param runtime_conf: the `RuntimeConfiguration` of the container
31
+ :param state: instance of `YboxStateManagement` having the state of all ybox containers
32
+ :return: integer exit status of search command where 0 represents success
33
+ """
34
+ quiet_flag = pkgmgr[PkgMgr.QUIET_DETAILS_FLAG.value] if args.quiet else ""
35
+ official = pkgmgr[PkgMgr.SEARCH_OFFICIAL_FLAG.value] if args.official else ""
36
+ word_start = word_end = ""
37
+ if args.word:
38
+ word_start = pkgmgr[PkgMgr.SEARCH_WORD_START_FLAG.value]
39
+ word_end = pkgmgr[PkgMgr.SEARCH_WORD_END_FLAG.value]
40
+ search_terms: list[str] = args.search # there will be at least one search term in the list
41
+ search = pkgmgr[PkgMgr.SEARCH_ALL.value] if args.all else pkgmgr[PkgMgr.SEARCH.value]
42
+ # quote the search terms for bash to properly see the full arguments if they contain spaces
43
+ # or other special characters
44
+ search_cmd = search.format(quiet=quiet_flag, official=official, word_start=word_start,
45
+ word_end=word_end, search="'" + "' '".join(search_terms) + "'")
46
+ docker_args = [docker_cmd, "exec"]
47
+ if sys.stdout.isatty(): # don't act as a terminal if it is being redirected
48
+ docker_args.append("-it")
49
+ docker_args.extend([conf.box_name, "/bin/bash", "-c", search_cmd])
50
+ # empty pager argument is a valid one and indicates no pagination, hence the `is None` check
51
+ pager: str = args.pager if args.pager is not None else conf.pager
52
+ return page_command(docker_args, pager, error_msg="searching repositories")
ybox/pkg/uninst.py ADDED
@@ -0,0 +1,92 @@
1
+ """
2
+ Methods for uninstalling package uninstallation on an active ybox container.
3
+ """
4
+
5
+ import argparse
6
+ from configparser import SectionProxy
7
+
8
+ from ybox.cmd import PkgMgr, build_shell_command, run_command
9
+ from ybox.config import StaticConfiguration
10
+ from ybox.print import print_error, print_info, print_notice
11
+ from ybox.state import RuntimeConfiguration, YboxStateManagement
12
+ from ybox.util import check_package, select_item_from_menu
13
+
14
+
15
+ def uninstall_package(args: argparse.Namespace, pkgmgr: SectionProxy, docker_cmd: str,
16
+ conf: StaticConfiguration, runtime_conf: RuntimeConfiguration,
17
+ state: YboxStateManagement) -> int:
18
+ """
19
+ Uninstall package specified by `args.package` on a ybox container with given podman/docker
20
+ command. Additional flags honored are `args.quiet` to bypass user confirmation during
21
+ uninstall, `args.keep_config_files` to keep the system configuration and/or data files
22
+ of the package, `args.skip_deps` to skip removal of all orphaned dependencies of the package
23
+ (including required and optional dependencies).
24
+
25
+ :param args: arguments having `package` and all other attributes passed by the user
26
+ :param pkgmgr: the `[pkgmgr]` section from `distro.ini` configuration file of the distribution
27
+ :param docker_cmd: the podman/docker executable to use
28
+ :param conf: the :class:`StaticConfiguration` for the container
29
+ :param runtime_conf: the `RuntimeConfiguration` of the container
30
+ :param state: instance of `YboxStateManagement` having the state of all ybox containers
31
+ :return: integer exit status of uninstall command where 0 represents success
32
+ """
33
+ package: str = args.package
34
+ quiet_flag = pkgmgr[PkgMgr.QUIET_FLAG.value] if args.quiet else ""
35
+ purge_flag = "" if args.keep_config_files else pkgmgr[PkgMgr.PURGE_FLAG.value]
36
+ remove_deps_flag = "" if args.skip_deps else pkgmgr[PkgMgr.REMOVE_DEPS_FLAG.value]
37
+ uninstall_cmd = pkgmgr[PkgMgr.UNINSTALL.value].format(
38
+ quiet=quiet_flag, purge=purge_flag, remove_deps=remove_deps_flag, package="{package}")
39
+ check_cmd = pkgmgr[PkgMgr.CHECK_INSTALL.value]
40
+ return _uninstall_package(package, args.skip_deps, uninstall_cmd, check_cmd, docker_cmd, conf,
41
+ runtime_conf, state)
42
+
43
+
44
+ def _uninstall_package(package: str, skip_deps: bool, uninstall_cmd: str, check_cmd: str,
45
+ docker_cmd: str, conf: StaticConfiguration,
46
+ runtime_conf: RuntimeConfiguration, state: YboxStateManagement,
47
+ dep_msg: str = "") -> int:
48
+ """
49
+ Real workhorse of :func:`uninstall_package` that uninstalls given package on a ybox container
50
+ with given podman/docker command.
51
+
52
+ :param package: the package to be uninstalled
53
+ :param skip_deps: true if orphaned dependencies of the package should not be uninstalled
54
+ :param uninstall_cmd: fully formed uninstallation command from the distribution's `distro.ini`
55
+ :param check_cmd: command to check for existence of the package returning the resolved name
56
+ as read from distribution's `distro.ini`; this should have {package}
57
+ placeholder in the string which will be resolved before execution
58
+ :param docker_cmd: the podman/docker executable to use
59
+ :param conf: the :class:`StaticConfiguration` for the container
60
+ :param runtime_conf: the `RuntimeConfiguration` of the container
61
+ :param state: instance of `YboxStateManagement` having the state of all ybox containers
62
+ :param dep_msg: if this is invoked for uninstalling a dependency then the string "dependency "
63
+ to display in messages, defaults to ""
64
+ :return: exit code of the underlying package manager command run using podman/docker
65
+ """
66
+ installed = False
67
+ code, inst_packages = check_package(docker_cmd, check_cmd, package, conf.box_name)
68
+ if code == 0:
69
+ installed = True
70
+ if len(inst_packages) > 1:
71
+ print_notice(f"Multiple packages found for '{package}', select one to uninstall")
72
+ if selected_pkg := select_item_from_menu(inst_packages):
73
+ package = selected_pkg
74
+ else:
75
+ return 1
76
+ else:
77
+ package = inst_packages[0]
78
+ print_info(f"Uninstalling {dep_msg}'{package}' from '{conf.box_name}'")
79
+ code = int(run_command(build_shell_command(
80
+ docker_cmd, conf.box_name, uninstall_cmd.format(package=package)),
81
+ exit_on_error=False, error_msg=f"uninstalling '{package}'"))
82
+ elif not dep_msg: # dependency may have been uninstalled in original package uninstallation
83
+ print_error(f"Package '{package}' is not installed in container '{conf.box_name}'")
84
+ # go ahead with removal from local state and wrappers, even if package was not installed
85
+ if code == 0 or not installed:
86
+ orphans = state.unregister_package(conf.box_name, package, runtime_conf.shared_root)
87
+ if not skip_deps and orphans:
88
+ print_info(f"Uninstalling orphaned dependencies of '{package}' {list(orphans.keys())}")
89
+ for opt_dep in orphans:
90
+ _uninstall_package(opt_dep, skip_deps, uninstall_cmd, check_cmd, docker_cmd, conf,
91
+ runtime_conf, state, dep_msg="dependency ")
92
+ return code
ybox/pkg/update.py ADDED
@@ -0,0 +1,56 @@
1
+ """
2
+ Update some or all packages on an active ybox container.
3
+ """
4
+
5
+ import argparse
6
+ from configparser import SectionProxy
7
+
8
+ from ybox.cmd import PkgMgr, build_shell_command, run_command
9
+ from ybox.config import StaticConfiguration
10
+ from ybox.print import print_warn
11
+ from ybox.state import RuntimeConfiguration, YboxStateManagement
12
+
13
+ # TODO: updating packages can lead to system libraries among others getting updated. At the very
14
+ # least, the container may need to be restarted thereafter. All other containers on the same
15
+ # shared root should also be restarted which can be an issue for the user. This is also
16
+ # a problem when creating a new container on the same shared root since that too does update.
17
+ # The biggest problem can be that even a new package install can end up updating shared libs.
18
+
19
+
20
+ def update_packages(args: argparse.Namespace, pkgmgr: SectionProxy, docker_cmd: str,
21
+ conf: StaticConfiguration, runtime_conf: RuntimeConfiguration,
22
+ state: YboxStateManagement) -> int:
23
+ """
24
+ Update the mentioned package installed in a container which can include packages not managed
25
+ by `ybox-pkg`, as well as those installed by other containers if the container shares the
26
+ same root directory with other containers.
27
+
28
+ When no package name is provided, then the entire installation is updated. Like above, it will
29
+ end up updating all the containers sharing the same root directory, if any. Note that
30
+ some rolling distributions like Arch Linux recommend always doing a full installation upgrade
31
+ rather than individual packages.
32
+
33
+ :param args: arguments having `packages` and all other attributes passed by the user
34
+ :param pkgmgr: the `[pkgmgr]` section from `distro.ini` configuration file of the distribution
35
+ :param docker_cmd: the podman/docker executable to use
36
+ :param conf: the :class:`StaticConfiguration` for the container
37
+ :param runtime_conf: the `RuntimeConfiguration` of the container
38
+ :param state: instance of `YboxStateManagement` having the state of all ybox containers
39
+ :return: integer exit status of update command where 0 represents success
40
+ """
41
+ quiet_flag = pkgmgr[PkgMgr.QUIET_FLAG.value] if args.quiet else ""
42
+ packages: list[str] = args.packages
43
+ if packages:
44
+ update_meta_cmd = pkgmgr[PkgMgr.UPDATE_META.value]
45
+ update_pkgs_cmd = pkgmgr[PkgMgr.UPDATE.value].format(quiet=quiet_flag,
46
+ packages=' '.join(packages))
47
+ update_cmd = f"{{ {update_meta_cmd}; }} && {{ {update_pkgs_cmd}; }}"
48
+ else:
49
+ update_cmd = pkgmgr[PkgMgr.UPDATE_ALL.value].format(quiet=quiet_flag)
50
+ if shared_containers := state.get_other_shared_containers(conf.box_name,
51
+ runtime_conf.shared_root):
52
+ # show all the containers sharing the same shared root
53
+ print_warn("The operation will also update packages in other containers having the same "
54
+ f"shared root directory: {', '.join(shared_containers)}")
55
+ return int(run_command(build_shell_command(docker_cmd, conf.box_name, update_cmd),
56
+ exit_on_error=False, error_msg="updating packages"))
ybox/print.py ADDED
@@ -0,0 +1,121 @@
1
+ """
2
+ Utility classes and methods to print in color on terminal/console.
3
+ """
4
+
5
+ import os
6
+ import shutil
7
+ import sys
8
+ from dataclasses import dataclass
9
+ from typing import IO, Optional
10
+
11
+
12
+ # define color names for printing in terminal
13
+ @dataclass(frozen=True)
14
+ class TermColors:
15
+ """basic ASCII color strings for terminals"""
16
+ black: str
17
+ red: str
18
+ green: str
19
+ orange: str
20
+ blue: str
21
+ purple: str
22
+ cyan: str
23
+ lightgray: str
24
+ reset: str
25
+ bold: str
26
+ disable: str
27
+
28
+
29
+ # foreground colors in the terminal
30
+ fgcolor = TermColors(
31
+ "\033[30m", "\033[31m", "\033[32m", "\033[33m", "\033[34m", "\033[35m", "\033[36m",
32
+ "\033[37m", "\033[00m", "\033[01m", "\033[02m")
33
+ # background colors in the terminal
34
+ bgcolor = TermColors(
35
+ "\033[40m", "\033[41m", "\033[42m", "\033[43m", "\033[44m", "\033[45m", "\033[46m",
36
+ "\033[47m", "\033[00m", "\033[01m", "\033[02m")
37
+
38
+
39
+ def get_terminal_width() -> int:
40
+ """
41
+ Get the best estimate of the width of the current terminal.
42
+ This may not work well if the output is piped, for example.
43
+ """
44
+ # Use stderr for the terminal width since stdout can be piped to pager.
45
+ try:
46
+ return os.get_terminal_size(sys.stderr.fileno()).columns
47
+ except OSError:
48
+ return shutil.get_terminal_size().columns
49
+
50
+
51
+ def print_color(msg: str, fg: Optional[str] = None,
52
+ bg: Optional[str] = None, end: str = "\n", file: Optional[IO[str]] = None) -> None:
53
+ """
54
+ Display given string to standard output with foreground and background colors, if provided.
55
+ The colors will show up as expected on most known Linux terminals and console though
56
+ some colors may look different on different terminal implementation
57
+ (e.g. orange could be more like yellow).
58
+
59
+ :param msg: the string to be displayed
60
+ :param fg: the foreground color of the string
61
+ :param bg: the background color of the string
62
+ :param end: the terminating string which is newline by default (or can be empty for example)
63
+ :param file: the text-mode file object to use for writing (defaults to `sys.stdout`)
64
+ """
65
+ if fg:
66
+ if bg:
67
+ full_msg = f"{fg}{bg}{msg}{bgcolor.reset}{fgcolor.reset}"
68
+ else:
69
+ full_msg = f"{fg}{msg}{fgcolor.reset}"
70
+ elif bg:
71
+ full_msg = f"{bg}{msg}{bgcolor.reset}"
72
+ else:
73
+ full_msg = msg
74
+ # force flush the output if it doesn't end in a newline
75
+ print(full_msg, end=end, file=file, flush=end != "\n")
76
+
77
+
78
+ def print_error(msg: str, end: str = "\n", file: Optional[IO[str]] = None) -> None:
79
+ """
80
+ Display an error string in red foreground (and no background change).
81
+
82
+ :param msg: the string to be displayed
83
+ :param end: the terminating string which is newline by default (or can be empty for example)
84
+ :param file: the text-mode file object to use for writing (defaults to `sys.stderr`)
85
+ """
86
+ if not file:
87
+ file = sys.stderr
88
+ print_color(msg, fg=fgcolor.red, end=end, file=file)
89
+
90
+
91
+ def print_warn(msg: str, end: str = "\n", file: Optional[IO[str]] = None):
92
+ """
93
+ Display a warning string in purple foreground (and no background change).
94
+
95
+ :param msg: the string to be displayed
96
+ :param end: the terminating string which is newline by default (or can be empty for example)
97
+ :param file: the text-mode file object to use for writing (defaults to `sys.stdout`)
98
+ """
99
+ print_color(msg, fg=fgcolor.purple, end=end, file=file)
100
+
101
+
102
+ def print_notice(msg: str, end: str = "\n", file: Optional[IO[str]] = None):
103
+ """
104
+ Display a string in orange foreground (and no background change).
105
+
106
+ :param msg: the string to be displayed
107
+ :param end: the terminating string which is newline by default (or can be empty for example)
108
+ :param file: the text-mode file object to use for writing (defaults to `sys.stdout`)
109
+ """
110
+ print_color(msg, fg=fgcolor.orange, end=end, file=file)
111
+
112
+
113
+ def print_info(msg: str, end: str = "\n", file: Optional[IO[str]] = None):
114
+ """
115
+ Display an informational string in blue foreground (and no background change).
116
+
117
+ :param msg: the string to be displayed
118
+ :param end: the terminating string which is newline by default (or can be empty for example)
119
+ :param file: the text-mode file object to use for writing (defaults to `sys.stdout`)
120
+ """
121
+ print_color(msg, fg=fgcolor.blue, end=end, file=file)
ybox/run/__init__.py ADDED
File without changes
ybox/run/cmd.py ADDED
@@ -0,0 +1,54 @@
1
+ """
2
+ Code for the `ybox-cmd` script that is used to execute programs in an active ybox container.
3
+ """
4
+
5
+ import argparse
6
+ import sys
7
+
8
+ from ybox.cmd import run_command
9
+ from ybox.env import get_docker_command
10
+
11
+
12
+ def main() -> None:
13
+ """main function for `ybox-cmd` script"""
14
+ main_argv(sys.argv[1:])
15
+
16
+
17
+ def main_argv(argv: list[str]) -> None:
18
+ """
19
+ Main entrypoint of `ybox-cmd` that takes a list of arguments which are usually the
20
+ command-line arguments of the `main()` function. Pass ["-h"]/["--help"] to see all the
21
+ available arguments with help message for each.
22
+
23
+ :param argv: arguments to the function (main function passes `sys.argv[1:]`)
24
+ """
25
+ args = parse_args(argv)
26
+ docker_cmd = get_docker_command()
27
+ container_name = args.container_name
28
+
29
+ docker_args = [docker_cmd, "exec"]
30
+ if not args.skip_terminal:
31
+ docker_args.append("-it")
32
+ docker_args.append(container_name)
33
+ if isinstance(args.command, str):
34
+ docker_args.append(args.command)
35
+ else:
36
+ docker_args.extend(args.command)
37
+ run_command(docker_args, error_msg=f"{args.command} execution on '{container_name}'")
38
+
39
+
40
+ def parse_args(argv: list[str]) -> argparse.Namespace:
41
+ """
42
+ Parse command-line arguments for the program and return the result :class:`argparse.Namespace`.
43
+
44
+ :param argv: the list of arguments to be parsed
45
+ :return: the result of parsing using the `argparse` library as a :class:`argparse.Namespace`
46
+ """
47
+ parser = argparse.ArgumentParser(description="Run a command on an active ybox container")
48
+ parser.add_argument("-s", "--skip-terminal", action="store_true",
49
+ help="skip interactive pseudo-terminal for the command "
50
+ "(i.e. skip -it options to podman/docker)")
51
+ parser.add_argument("container_name", type=str, help="name of the active ybox")
52
+ parser.add_argument("command", nargs="*", default="/bin/bash",
53
+ help="run the given command (default is /bin/bash)")
54
+ return parser.parse_args(argv)
ybox/run/control.py ADDED
@@ -0,0 +1,102 @@
1
+ """
2
+ Code for the `ybox-control` script that is used to start/stop/restart a ybox container.
3
+ """
4
+
5
+ import argparse
6
+ import sys
7
+ import time
8
+
9
+ from ybox.cmd import check_active_ybox, get_ybox_state, run_command
10
+ from ybox.config import StaticConfiguration
11
+ from ybox.env import Environ, get_docker_command
12
+ from ybox.print import fgcolor, print_color, print_error
13
+ from ybox.util import wait_for_ybox_container
14
+
15
+
16
+ def main() -> None:
17
+ """main function for `ybox-control` script"""
18
+ main_argv(sys.argv[1:])
19
+
20
+
21
+ def start_container(docker_cmd: str, container_name: str):
22
+ """
23
+ Start an existing ybox container.
24
+
25
+ :param docker_cmd: the podman/docker executable to use
26
+ :param container_name: name of the container
27
+ """
28
+ if status := get_ybox_state(docker_cmd, container_name, (), exit_on_error=False):
29
+ if status[0] == "running":
30
+ print_color(f"Ybox container '{container_name}' already active", fg=fgcolor.cyan)
31
+ else:
32
+ print_color(f"Starting ybox container '{container_name}'", fg=fgcolor.cyan)
33
+ run_command([docker_cmd, "container", "start", container_name],
34
+ error_msg="container start")
35
+ conf = StaticConfiguration(Environ(docker_cmd), status[1], container_name)
36
+ wait_for_ybox_container(docker_cmd, conf)
37
+ else:
38
+ print_error(f"No ybox container '{container_name}' found")
39
+ sys.exit(1)
40
+
41
+
42
+ def stop_container(docker_cmd: str, container_name: str, fail_on_error: bool):
43
+ """
44
+ Stop a ybox container.
45
+
46
+ :param docker_cmd: the podman/docker executable to use
47
+ :param container_name: name of the container
48
+ :param fail_on_error: if True then show error message on failure to stop else ignore
49
+ """
50
+ if check_active_ybox(docker_cmd, container_name):
51
+ print_color(f"Stopping ybox container '{container_name}'", fg=fgcolor.cyan)
52
+ run_command([docker_cmd, "container", "stop", container_name], error_msg="container stop")
53
+ for _ in range(120):
54
+ time.sleep(0.5)
55
+ if get_ybox_state(docker_cmd, container_name, ("exited", "stopped"),
56
+ exit_on_error=False, state_msg=" stopped"):
57
+ return
58
+ print_error(f"Failed to stop ybox container '{container_name}'")
59
+ elif fail_on_error:
60
+ print_error(f"No active ybox container '{container_name}' found")
61
+ sys.exit(1)
62
+ else:
63
+ print_color(f"No active ybox container '{container_name}' found", fg=fgcolor.cyan)
64
+
65
+
66
+ def main_argv(argv: list[str]) -> None:
67
+ """
68
+ Main entrypoint of `ybox-control` that takes a list of arguments which are usually the
69
+ command-line arguments of the `main()` function. Pass ["-h"]/["--help"] to see all the
70
+ available arguments with help message for each.
71
+
72
+ :param argv: arguments to the function (main function passes `sys.argv[1:]`)
73
+ """
74
+ args = parse_args(argv)
75
+ docker_cmd = get_docker_command()
76
+ container_name = args.container_name
77
+ if args.action == "start":
78
+ start_container(docker_cmd, container_name)
79
+ elif args.action == "stop":
80
+ stop_container(docker_cmd, container_name, fail_on_error=True)
81
+ elif args.action == "restart":
82
+ stop_container(docker_cmd, container_name, fail_on_error=False)
83
+ start_container(docker_cmd, container_name)
84
+ elif args.action == "status":
85
+ if status := get_ybox_state(docker_cmd, container_name, (), exit_on_error=False):
86
+ print(status[0])
87
+ else:
88
+ print_error(f"No ybox container '{container_name}' found")
89
+
90
+
91
+ def parse_args(argv: list[str]) -> argparse.Namespace:
92
+ """
93
+ Parse command-line arguments for the program and return the result :class:`argparse.Namespace`.
94
+
95
+ :param argv: the list of arguments to be parsed
96
+ :return: the result of parsing using the `argparse` library as a :class:`argparse.Namespace`
97
+ """
98
+ parser = argparse.ArgumentParser(description="control ybox containers")
99
+ parser.add_argument("action", choices=["start", "stop", "restart", "status"],
100
+ help="action to perform")
101
+ parser.add_argument("container_name", help="name of the ybox")
102
+ return parser.parse_args(argv)