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/run/pkg.py ADDED
@@ -0,0 +1,445 @@
1
+ """
2
+ Code for the `ybox-pkg` script which is a high-level generic package management utility for
3
+ ybox containers.
4
+ """
5
+
6
+ import argparse
7
+ import sys
8
+ from typing import cast
9
+
10
+ from ybox.cmd import YboxLabel, check_active_ybox, run_command
11
+ from ybox.config import Consts, StaticConfiguration
12
+ from ybox.env import Environ
13
+ from ybox.pkg.clean import clean_cache
14
+ from ybox.pkg.info import info_packages
15
+ from ybox.pkg.inst import install_package
16
+ from ybox.pkg.list import list_files, list_packages
17
+ from ybox.pkg.mark import mark_package
18
+ from ybox.pkg.repair import repair_package_state
19
+ from ybox.pkg.repo import repo_add, repo_list, repo_remove
20
+ from ybox.pkg.search import search_packages
21
+ from ybox.pkg.uninst import uninstall_package
22
+ from ybox.pkg.update import update_packages
23
+ from ybox.print import print_error, print_info
24
+ from ybox.state import YboxStateManagement
25
+ from ybox.util import (EnvInterpolation, config_reader, get_ybox_version,
26
+ select_item_from_menu)
27
+
28
+
29
+ def main() -> None:
30
+ """main function for `ybox-pkg` script"""
31
+ main_argv(sys.argv[1:])
32
+
33
+
34
+ def main_argv(argv: list[str]) -> None:
35
+ """
36
+ Main entrypoint of `ybox-pkg` that takes a list of arguments which are usually the
37
+ command-line arguments of the `main()` function. Pass ["-h"]/["--help"] to see all the
38
+ available arguments with help message for each.
39
+
40
+ :param argv: arguments to the function (main function passes `sys.argv[1:]`)
41
+ """
42
+ args = parse_args(argv)
43
+ # --quiet can be specified at most two times
44
+ if args.quiet > 2:
45
+ print_error("Argument -q/--quiet can be specified at most two times")
46
+ sys.exit(1)
47
+ env = Environ()
48
+ docker_cmd = env.docker_cmd
49
+ container_name = args.ybox
50
+
51
+ if container_name:
52
+ check_active_ybox(docker_cmd, container_name, exit_on_error=True)
53
+ else:
54
+ # check active containers
55
+ containers = str(run_command([docker_cmd, "container", "ls", "--format={{ .Names }}",
56
+ f"--filter=label={YboxLabel.CONTAINER_PRIMARY.value}"],
57
+ capture_output=True, error_msg="container ls")).splitlines()
58
+ # use the active container if there is only one of them
59
+ if len(containers) == 1:
60
+ container_name = containers[0]
61
+ elif not containers:
62
+ print_error("No active ybox container found!")
63
+ sys.exit(1)
64
+ elif args.quiet:
65
+ print_error(
66
+ f"Expected one active ybox container but found: {', '.join(containers)}")
67
+ sys.exit(1)
68
+ else:
69
+ print_info("Please select the container to use:", file=sys.stderr)
70
+ if (container_name := select_item_from_menu(containers)) is None:
71
+ sys.exit(1)
72
+
73
+ if not args.quiet:
74
+ print_info(f"Running the operation on '{container_name}'", file=sys.stderr)
75
+
76
+ with YboxStateManagement(env) as state:
77
+ # ensure that all state database changes are done as a single transaction and only applied
78
+ # if there were no failures (commit/rollback are automatic at the end of `with`)
79
+ state.begin_transaction()
80
+ if (runtime_conf := state.get_container_configuration(container_name)) is None:
81
+ print_error(f"No entry for ybox container '{container_name}' found!")
82
+ sys.exit(1)
83
+ conf = StaticConfiguration(env, runtime_conf.distribution, container_name)
84
+ distro_conf_file = args.distribution_config or conf.distribution_config(conf.distribution)
85
+ env_interpolation = EnvInterpolation(env, [])
86
+ distro_config = config_reader(env.search_config_path(
87
+ distro_conf_file, only_sys_conf=True), env_interpolation)
88
+ # if required, migrate the container to work with the latest product
89
+ state.migrate_container(get_ybox_version(conf), conf, distro_config)
90
+ # the "repo_cmd" flag set by the subcommands indicate whether the subcommand was
91
+ # for package management or for repository management
92
+ pkgmgr = distro_config["pkgmgr"]
93
+ if args.is_repo_cmd:
94
+ code = args.func(args, pkgmgr, distro_config["repo"], docker_cmd, conf,
95
+ runtime_conf, state)
96
+ else:
97
+ code = args.func(args, pkgmgr, docker_cmd, conf, runtime_conf, state)
98
+ if code != 0:
99
+ sys.exit(code) # state will be automatically rolled back for exceptions
100
+
101
+
102
+ def parse_args(argv: list[str]) -> argparse.Namespace:
103
+ """
104
+ Parse command-line arguments for the program and return the result :class:`argparse.Namespace`.
105
+
106
+ :param argv: the list of arguments to be parsed
107
+ :return: the result of parsing using the `argparse` library as a :class:`argparse.Namespace`
108
+ """
109
+ parser = argparse.ArgumentParser(description="Package management across ybox containers")
110
+ operations = parser.add_subparsers(title="Operations", required=True, metavar="OPERATION",
111
+ help="DESCRIPTION")
112
+ add_install(add_subparser(operations, "install", "install a package with dependencies"))
113
+ add_uninstall(add_subparser(operations, "uninstall", "uninstall a package and "
114
+ "optionally its dependencies"))
115
+ add_update(add_subparser(operations, "update", "update some or all packages"))
116
+ add_list(add_subparser(operations, "list", "list installed packages"))
117
+ add_repo_add(add_subparser(operations, "repo-add",
118
+ "add a new package repository with a given name and server URL(s)"))
119
+ add_repo_remove(add_subparser(operations, "repo-remove",
120
+ "remove an existing package repository with the given name"))
121
+ add_repo_list(add_subparser(operations, "repo-list",
122
+ "list external repositories registered using 'repo-add'"))
123
+ add_list_files(add_subparser(operations, "list-files", "list files of an installed package"))
124
+ add_search(add_subparser(operations, "search",
125
+ "search repository for packages with matching string"))
126
+ add_info(add_subparser(operations, "info", "show detailed information about given package(s)"))
127
+ add_clean(add_subparser(operations, "clean", "clean package cache and intermediate files"))
128
+ add_mark(add_subparser(operations, "mark",
129
+ "mark a package as a dependency or an explicitly installed package"))
130
+ add_repair(add_subparser(operations, "repair",
131
+ "try to repair state after a failed operation or an interrupt/kill"))
132
+ return parser.parse_args(argv)
133
+
134
+
135
+ def add_subparser(operations, name: str, hlp: str) -> argparse.ArgumentParser: # type: ignore
136
+ """
137
+ Add a sub-command parser to `ybox-pkg` having a given name and help string.
138
+
139
+ :param operations: the sub-parser obtained using :meth:`argparse.ArgumentParser.add_subparsers`
140
+ :param name: name of the sub-command (e.g. `install` for `ybox-pkg install`)
141
+ :param hlp: top-level help string for the sub-command
142
+ :return: the :class:`argparse.ArgumentParser` object for the sub-command
143
+ """
144
+ subparser = cast(argparse.ArgumentParser,
145
+ operations.add_parser(name, help=hlp)) # type: ignore
146
+ add_common_args(subparser)
147
+ # by default set the flag for repository command as false
148
+ subparser.set_defaults(is_repo_cmd=False)
149
+ return subparser
150
+
151
+
152
+ def add_common_args(subparser: argparse.ArgumentParser) -> None:
153
+ """
154
+ Add arguments common to all the `ybox-pkg` sub-commands like `-z/--ybox` for the
155
+ container to use, `-q/--quiet` for quiet operations with minimal user interaction etc.
156
+
157
+ :param subparser: the :class:`argparse.ArgumentParser` object for the sub-command
158
+ """
159
+ subparser.add_argument("-z", "--ybox", type=str,
160
+ help="the ybox container to use for package operations else the user "
161
+ "is prompted to select a container from among the active ones")
162
+ subparser.add_argument("-C", "--distribution-config", type=str,
163
+ help="path to distribution configuration file to use instead of the "
164
+ "`distro.ini` from user/system configuration paths")
165
+ subparser.add_argument("-q", "--quiet", action="count", default=0,
166
+ help="proceed without asking any questions using defaults where "
167
+ "possible; this should usually be used with explicit -z/--ybox "
168
+ "argument for the container else it is assumed that there is only "
169
+ "one active container which is selected else the operation fails; "
170
+ "specifying this flag twice will make it real quiet (e.g. install "
171
+ "will silently override system executables with local ones)")
172
+
173
+
174
+ def add_pager_arg(subparser: argparse.ArgumentParser) -> None:
175
+ """
176
+ Add the `-P/--pager` argument to the sub-command that allows user to change the pager command
177
+ used to show the output one screenful at a time.
178
+
179
+ :param subparser: the :class:`argparse.ArgumentParser` object for the sub-command
180
+ """
181
+ subparser.add_argument("-P", "--pager", type=str,
182
+ help="pager to use to show the output one screenful at a time, "
183
+ "default is YBOX_PAGER environment variable if set else "
184
+ f"'{Consts.default_pager()}'; empty skips pagination; command is "
185
+ "split using shell-like syntax e.g. quoted value is one argument")
186
+
187
+
188
+ def add_install(subparser: argparse.ArgumentParser) -> None:
189
+ """
190
+ Add the arguments required for the `ybox-pkg install` sub-command and set the `func`
191
+ attribute to point to the implementation method for package installation.
192
+
193
+ :param subparser: the :class:`argparse.ArgumentParser` object for the sub-command
194
+ """
195
+ subparser.add_argument("-o", "--skip-opt-deps", action="store_true",
196
+ help="skip installation of optional dependencies (or recommendations)")
197
+ subparser.add_argument("-w", "--with-opt-deps", type=str,
198
+ help="provide comma-separated optional dependencies to install "
199
+ "(in which case user will not be prompted to select them)")
200
+ subparser.add_argument("-f", "--app-flags", type=str,
201
+ help="comma separated key-value pairs for the flags to be used when "
202
+ "invoking the container executables (e.g. 'chromium=...,...'")
203
+ subparser.add_argument("-l", "--add-dep-wrappers", action="store_true",
204
+ help="create local wrapper desktop and executables for the newly "
205
+ "installed package dependencies too (both required and optional)")
206
+ subparser.add_argument("-c", "--check-package", action="store_true",
207
+ help="check for existing package before actual installation")
208
+ subparser.add_argument("-s", "--skip-executables", action="store_true",
209
+ help="skip creating wrappers for invoking executables installed by "
210
+ "the package; default is to create wrapper executables in user's "
211
+ "$HOME/.local/bin directory and link man pages to "
212
+ "$HOME/.local/share/man (or using $PYTHONUSERBASE)")
213
+ subparser.add_argument("-S", "--skip-desktop-files", action="store_true",
214
+ help="skip creating wrapper desktop files for those installed by the "
215
+ "package and its optional dependencies; default is to create "
216
+ "wrapper desktop files in user's $HOME/.local/share/applications "
217
+ "(or using $PYTHONUSERBASE)")
218
+ subparser.add_argument("package", type=str, help="the package to install")
219
+ subparser.set_defaults(func=install_package)
220
+
221
+
222
+ def add_uninstall(subparser: argparse.ArgumentParser) -> None:
223
+ """
224
+ Add the arguments required for the `ybox-pkg uninstall` sub-command and set the `func`
225
+ attribute to point to the implementation method for package uninstallation.
226
+
227
+ :param subparser: the :class:`argparse.ArgumentParser` object for the sub-command
228
+ """
229
+ subparser.add_argument("-k", "--keep-config-files", action="store_true",
230
+ help="keep system configuration and/or data files of the package")
231
+ subparser.add_argument("-s", "--skip-deps", action="store_true",
232
+ help="skip uninstallation of the orphaned dependencies of the package")
233
+ subparser.add_argument("package", type=str, help="the package to uninstall")
234
+ subparser.set_defaults(func=uninstall_package)
235
+
236
+
237
+ def add_update(subparser: argparse.ArgumentParser) -> None:
238
+ """
239
+ Add the arguments required for the `ybox-pkg update` sub-command and set the `func`
240
+ attribute to point to the implementation method for updating one or more packages.
241
+
242
+ :param subparser: the :class:`argparse.ArgumentParser` object for the sub-command
243
+ """
244
+ subparser.add_argument("packages", nargs="*",
245
+ help="the packages to update if provided, else update the entire "
246
+ "installation of the container (which will end up updating all "
247
+ "other containers sharing the same root if configured)")
248
+ subparser.set_defaults(func=update_packages)
249
+
250
+
251
+ def add_list(subparser: argparse.ArgumentParser) -> None:
252
+ """
253
+ Add the arguments required for the `ybox-pkg list` sub-command and set the `func`
254
+ attribute to point to the implementation method for listing installed packages.
255
+
256
+ :param subparser: the :class:`argparse.ArgumentParser` object for the sub-command
257
+ """
258
+ subparser.add_argument("-a", "--all", action="store_true",
259
+ help="show all packages including dependent packages in the output "
260
+ "otherwise only the packages that have been explicitly installed "
261
+ "are shown")
262
+ subparser.add_argument("-o", "--os-pkgs", action="store_true",
263
+ help="list all packages installed in the container including those "
264
+ "not managed by 'ybox-pkg'; when multiple containers share the "
265
+ "same root directory, then it will include packages installed "
266
+ "on other containers; this can be combined with -a/--all "
267
+ "option to list all the packages including dependents")
268
+ subparser.add_argument("-p", "--plain-separator", type=str,
269
+ help="show the output in 'plain' format rather than as a table with "
270
+ "the fields separated by the given string; ; disables default "
271
+ "pager so use explicit -P/--pager for pagination; it will also "
272
+ "skip any truncation of the 'Dependency Of' column; DO NOT USE "
273
+ "a single comma or similar as separator as they can be in output "
274
+ "fields and will break parsing of the output")
275
+ subparser.add_argument("-v", "--verbose", action="store_true",
276
+ help="show some package details including version, description and "
277
+ "whether it is a dependency or a top-level package")
278
+ subparser.add_argument("-N", "--no-trunc", action="store_true",
279
+ help="do not truncate the 'Dependency Of' column values when using "
280
+ "the -v/--verbose option")
281
+ add_pager_arg(subparser)
282
+ subparser.set_defaults(func=list_packages)
283
+
284
+
285
+ def add_list_files(subparser: argparse.ArgumentParser) -> None:
286
+ """
287
+ Add the arguments required for the `ybox-pkg list-files` sub-command and set the `func`
288
+ attribute to point to the implementation method for listing files of an installed package.
289
+
290
+ :param subparser: the :class:`argparse.ArgumentParser` object for the sub-command
291
+ """
292
+ add_pager_arg(subparser)
293
+ subparser.add_argument("package", type=str, help="list files of this package")
294
+ subparser.set_defaults(func=list_files)
295
+
296
+
297
+ def add_search(subparser: argparse.ArgumentParser) -> None:
298
+ """
299
+ Add the arguments required for the `ybox-pkg search` sub-command and set the `func`
300
+ attribute to point to the implementation method for searching among all available packages.
301
+
302
+ :param subparser: the :class:`argparse.ArgumentParser` object for the sub-command
303
+ """
304
+ subparser.add_argument("-w", "--word", action="store_true",
305
+ help="match given search terms as full words")
306
+ subparser.add_argument("-a", "--all", action="store_true",
307
+ help="search in package descriptions in addition to the package names")
308
+ subparser.add_argument("-o", "--official", action="store_true",
309
+ help="search only in the official repositories and not the extra ones "
310
+ "(e.g. skip AUR repository on Arch Linux)")
311
+ add_pager_arg(subparser)
312
+ subparser.add_argument("search", nargs="+", help="one or more search terms")
313
+ subparser.set_defaults(func=search_packages)
314
+
315
+
316
+ def add_info(subparser: argparse.ArgumentParser) -> None:
317
+ """
318
+ Add the arguments required for the `ybox-pkg info` sub-command and set the `func`
319
+ attribute to point to the implementation method for displaying detailed information of one
320
+ or more packages.
321
+
322
+ :param subparser: the :class:`argparse.ArgumentParser` object for the sub-command
323
+ """
324
+ subparser.add_argument("-a", "--all", action="store_true",
325
+ help="search for package information in the repositories, "
326
+ "otherwise search only among the installed packages")
327
+ add_pager_arg(subparser)
328
+ subparser.add_argument("packages", nargs="+", help="one or more packages")
329
+ subparser.set_defaults(func=info_packages)
330
+
331
+
332
+ def add_clean(subparser: argparse.ArgumentParser) -> None:
333
+ """
334
+ Add the arguments required for the `ybox-pkg clean` sub-command and set the `func`
335
+ attribute to point to the implementation method for cleaning package cache and related
336
+ intermediate files.
337
+
338
+ :param subparser: the :class:`argparse.ArgumentParser` object for the sub-command
339
+ """
340
+ subparser.set_defaults(func=clean_cache)
341
+
342
+
343
+ def add_mark(subparser: argparse.ArgumentParser) -> None:
344
+ """
345
+ Add the arguments required for the `ybox-pkg mark` sub-command and set the `func`
346
+ attribute to point to the implementation method for marking package as explicitly installed
347
+ or as a dependency of another package.
348
+
349
+ :param subparser: the :class:`argparse.ArgumentParser` object for the sub-command
350
+ """
351
+ subparser.add_argument("-e", "--explicit", action="store_true",
352
+ help="mark the package as explicitly installed; the package will "
353
+ "henceforth be managed by `ybox-pkg` if not already; "
354
+ "exactly one of -e or -D option must be specified")
355
+ subparser.add_argument("-D", "--dependency-of", type=str,
356
+ help="mark the package as a dependency of given package; both the "
357
+ "packages will henceforth be managed by `ybox-pkg` if not "
358
+ "already; exactly one of -e or -D option must be specified")
359
+ subparser.add_argument("package", type=str, help="the package to be marked")
360
+ subparser.set_defaults(func=mark_package)
361
+
362
+
363
+ def add_repair(subparser: argparse.ArgumentParser) -> None:
364
+ """
365
+ Add the arguments required for the `ybox-pkg repair` sub-command and set the `func`
366
+ attribute to point to the implementation method for repairing system state after a failed
367
+ installation/operation or an interrupt/kill during package operations.
368
+
369
+ :param subparser: the :class:`argparse.ArgumentParser` object for the sub-command
370
+ """
371
+ subparser.add_argument("--extensive", action="store_true",
372
+ help="repair thoroughly by reinstalling all packages; CAUTION: use "
373
+ "this only if the normal repair fails and the system cannot be "
374
+ "recovered otherwise")
375
+ subparser.set_defaults(func=repair_package_state)
376
+
377
+
378
+ def add_repo_add(subparser: argparse.ArgumentParser) -> None:
379
+ """
380
+ Add the arguments required for the `ybox-pkg repo-add` sub-command and set the `func`
381
+ attribute to point to the implementation method for adding a new external package repository.
382
+
383
+ :param subparser: the :class:`argparse.ArgumentParser` object for the sub-command
384
+ """
385
+ subparser.add_argument("-k", "--key", type=str,
386
+ help="key to be registered for verification of the packages (usually "
387
+ "a GPG/PGP signing key); this can be a URL to the key file or a "
388
+ "key ID that can be retrieved from default key server as "
389
+ "configured in the distribution's configuration file or the one "
390
+ "provided by the -s/--key-server option")
391
+ subparser.add_argument("-s", "--key-server", type=str,
392
+ help="URL of the key server to be used for retrieving a key by ID "
393
+ "which will override the default key server configured in the "
394
+ "distribution's configuration file")
395
+ subparser.add_argument("-o", "--options", type=str,
396
+ help="additional options that may be required for the repository "
397
+ "specification; for example debian/ubuntu need '<distribution> "
398
+ "<component...>' in its source specification so that need to be "
399
+ "provided using '--options=stable main' (as an example)")
400
+ subparser.add_argument("-S", "--add-source-repo", action="store_true",
401
+ help="for distributions like debian/ubuntu, this specifies that the "
402
+ "repository for package sources (deb-src) should also be added "
403
+ "using the same specification as the package repository")
404
+ subparser.add_argument("name", type=str,
405
+ help="unique name for the package repository to be added")
406
+ subparser.add_argument("urls", nargs="+",
407
+ help="one or more server URLs of the package repository; "
408
+ "note that the current distribution may only support a single URL "
409
+ "(e.g. Ubuntu/Debian), so providing multiple URLs can fail")
410
+ subparser.set_defaults(is_repo_cmd=True)
411
+ subparser.set_defaults(func=repo_add)
412
+
413
+
414
+ def add_repo_remove(subparser: argparse.ArgumentParser) -> None:
415
+ """
416
+ Add the arguments required for the `ybox-pkg repo-remove` sub-command and set the `func`
417
+ attribute to point to the implementation method for removing an external package repository.
418
+
419
+ :param subparser: the :class:`argparse.ArgumentParser` object for the sub-command
420
+ """
421
+ subparser.add_argument("-f", "--force", action="store_true",
422
+ help="force remove repository registeration even on failure of "
423
+ "removal of key and/or repository details")
424
+ subparser.add_argument("name", type=str, help="name of the package repository to be removed")
425
+ subparser.set_defaults(is_repo_cmd=True)
426
+ subparser.set_defaults(func=repo_remove)
427
+
428
+
429
+ def add_repo_list(subparser: argparse.ArgumentParser) -> None:
430
+ """
431
+ Add the arguments required for the `ybox-pkg repo-list` sub-command and set the `func`
432
+ attribute to point to the implementation method for listing information of registered external
433
+ package repositories.
434
+
435
+ :param subparser: the :class:`argparse.ArgumentParser` object for the sub-command
436
+ """
437
+ subparser.add_argument("-p", "--plain-separator", type=str,
438
+ help="show the output in 'plain' format rather than as a table with "
439
+ "the fields separated by the given string; disables default "
440
+ "pager so use explicit -P/--pager for pagination")
441
+ subparser.add_argument("-v", "--verbose", action="store_true",
442
+ help="show more details of the repositories")
443
+ add_pager_arg(subparser)
444
+ subparser.set_defaults(is_repo_cmd=True)
445
+ subparser.set_defaults(func=repo_list)
@@ -0,0 +1,27 @@
1
+ -- records the version of the whole schema
2
+ CREATE TABLE schema (
3
+ version TEXT NOT NULL PRIMARY KEY
4
+ ) WITHOUT ROWID;
5
+
6
+ -- index on the shared_root column used in lookups
7
+ CREATE INDEX container_roots ON containers(shared_root);
8
+
9
+ -- dependencies of packages are also recorded separately to keep a proper
10
+ -- reference count and remove dependencies only if no package depends on it
11
+ CREATE TABLE package_deps (
12
+ -- name of the package
13
+ name TEXT NOT NULL,
14
+ -- name of the container
15
+ container TEXT NOT NULL,
16
+ -- name of the dependency
17
+ dependency TEXT NOT NULL,
18
+ -- type of the dependency, one of "required", "optional" or "suggestion"
19
+ -- (note that "required" dependencies are handled by underlying package manager
20
+ -- and usually will not be recorded here)
21
+ dep_type TEXT NOT NULL,
22
+ PRIMARY KEY (name, container, dependency)
23
+ ) WITHOUT ROWID;
24
+
25
+ -- index on package_deps for faster lookups and deletes
26
+ CREATE INDEX pkg_deps_containers ON package_deps(container);
27
+ CREATE INDEX pkg_deps_deps ON package_deps(dependency);
@@ -0,0 +1,18 @@
1
+ -- additional package repositories that have been added are tracked display them
2
+ -- and to enable removing the signing key if required
3
+ CREATE TABLE package_repos (
4
+ -- name of the repository
5
+ name TEXT NOT NULL,
6
+ -- name of the container, or shared root directory (if the container is using a shared root)
7
+ -- where the repository is being added
8
+ container_or_shared_root TEXT NOT NULL,
9
+ -- server URL(s) that are comma separated if multiple of them
10
+ urls TEXT NOT NULL,
11
+ -- key used for verifying the packages by the package manager
12
+ key TEXT NOT NULL,
13
+ -- additional options for the repository
14
+ options TEXT NOT NULL,
15
+ -- if source code repository has also been enabled
16
+ with_source_repo BOOL NOT NULL,
17
+ PRIMARY KEY (name, container_or_shared_root)
18
+ ) WITHOUT ROWID;
ybox/schema/init.sql ADDED
@@ -0,0 +1,39 @@
1
+ -- all ybox containers
2
+ CREATE TABLE containers (
3
+ -- name of the container
4
+ name TEXT NOT NULL PRIMARY KEY,
5
+ -- code name for the linux distribution of the container
6
+ distribution TEXT NOT NULL,
7
+ -- shared root directory or empty string if not using shared root
8
+ shared_root TEXT NOT NULL,
9
+ -- configuration of container in INI format string
10
+ configuration TEXT NOT NULL,
11
+ -- if the container has been destroyed but still has packages installed in shared root
12
+ -- then it is retained with a new unique name denoting a destroyed container
13
+ destroyed BOOL NOT NULL
14
+ ) WITHOUT ROWID;
15
+
16
+ -- all packages installed in ybox containers using ybox-pkg including dependencies
17
+ CREATE TABLE packages (
18
+ -- name of the package
19
+ name TEXT NOT NULL,
20
+ -- name of the container that owns this package
21
+ container TEXT NOT NULL,
22
+ -- local wrappers desktop/executables created for the package (array as json)
23
+ local_copies TEXT NOT NULL,
24
+ -- type of local wrappers created which is a bit mask:
25
+ -- 0 for none, 1 for .desktop files, 2 for executables, 3 for both
26
+ local_copy_type INT NOT NULL,
27
+ -- set of flags to append to the executables when invoking from local_copies (dict as json)
28
+ flags TEXT NOT NULL,
29
+ PRIMARY KEY(name, container)
30
+ ) WITHOUT ROWID;
31
+
32
+ -- index on the containers column used in joins and lookups
33
+ CREATE INDEX package_containers ON packages(container);
34
+
35
+ -- include the new tables and indexes added in version 0.9.1
36
+ SOURCE '0.9.1-added.sql';
37
+
38
+ -- include the new 'package_repos' table added in version 0.9.6
39
+ SOURCE '0.9.6-added.sql';
@@ -0,0 +1,42 @@
1
+ -- first create the new tables and index
2
+
3
+ SOURCE '../0.9.1-added.sql';
4
+
5
+ -- add the destroyed_containers table
6
+ CREATE TABLE destroyed_containers (
7
+ name TEXT NOT NULL PRIMARY KEY,
8
+ distribution TEXT NOT NULL,
9
+ shared_root TEXT NOT NULL,
10
+ configuration TEXT NOT NULL
11
+ ) WITHOUT ROWID;
12
+
13
+ -- delete the orphan packages having empty container fields since it is not possible to create
14
+ -- corresponding entries in destroyed_containers due to lack of container configuration information
15
+ DELETE FROM packages WHERE container = '';
16
+
17
+ -- change comma-separated local_copies field to json
18
+ UPDATE packages SET local_copies = JSON_FROM_CSV(local_copies);
19
+
20
+ -- make entries into package_deps reading from packages.type
21
+ INSERT INTO package_deps
22
+ SELECT RTRIM(SUBSTR(type, 10), ')'), container, name, 'optional'
23
+ FROM packages
24
+ WHERE type LIKE 'optional(%)';
25
+
26
+ -- drop the packages.shared_root and packages.type columns
27
+ ALTER TABLE packages DROP COLUMN type;
28
+ ALTER TABLE packages DROP COLUMN shared_root;
29
+
30
+ -- add the local_copy_type column and fill it up guessing from local_copies
31
+ ALTER TABLE packages ADD COLUMN local_copy_type INT NOT NULL DEFAULT 0;
32
+ UPDATE packages SET local_copy_type = (
33
+ CASE WHEN local_copies LIKE '%.desktop%,%bin/%' THEN 3
34
+ WHEN local_copies LIKE '%bin/%,%.desktop%' THEN 3
35
+ WHEN local_copies LIKE '%.desktop%' THEN 1
36
+ WHEN local_copies LIKE '%bin/%' THEN 2
37
+ ELSE 0
38
+ END
39
+ );
40
+
41
+ -- add version entry, since code assumes that a valid entry will be present in the schema table
42
+ INSERT INTO schema VALUES ('0.9.1');
@@ -0,0 +1,8 @@
1
+ -- add the destroyed column to containers
2
+ ALTER TABLE containers ADD COLUMN destroyed BOOL NOT NULL DEFAULT false;
3
+
4
+ -- move the entries from "destroyed_containers" to containers with destroyed column as true
5
+ INSERT OR IGNORE INTO containers SELECT name, distribution, shared_root, configuration, true
6
+ FROM destroyed_containers;
7
+
8
+ DROP TABLE destroyed_containers;
@@ -0,0 +1,2 @@
1
+ -- add the flags column to packages
2
+ ALTER TABLE packages ADD COLUMN flags TEXT NOT NULL DEFAULT '{}';
@@ -0,0 +1,2 @@
1
+ -- include the new 'package_repos' table
2
+ SOURCE '../0.9.6-added.sql';