pyinfra 3.1.1__py2.py3-none-any.whl → 3.3__py2.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 (104) hide show
  1. pyinfra/api/arguments.py +9 -2
  2. pyinfra/api/arguments_typed.py +4 -5
  3. pyinfra/api/command.py +22 -3
  4. pyinfra/api/config.py +5 -2
  5. pyinfra/api/deploy.py +4 -2
  6. pyinfra/api/facts.py +3 -0
  7. pyinfra/api/host.py +15 -7
  8. pyinfra/api/operation.py +2 -1
  9. pyinfra/api/state.py +1 -1
  10. pyinfra/connectors/base.py +34 -8
  11. pyinfra/connectors/chroot.py +7 -2
  12. pyinfra/connectors/docker.py +24 -8
  13. pyinfra/connectors/dockerssh.py +7 -2
  14. pyinfra/connectors/local.py +7 -2
  15. pyinfra/connectors/ssh.py +9 -2
  16. pyinfra/connectors/sshuserclient/client.py +42 -14
  17. pyinfra/connectors/sshuserclient/config.py +2 -0
  18. pyinfra/connectors/terraform.py +1 -1
  19. pyinfra/connectors/util.py +13 -9
  20. pyinfra/context.py +9 -2
  21. pyinfra/facts/apk.py +8 -1
  22. pyinfra/facts/apt.py +68 -0
  23. pyinfra/facts/brew.py +13 -0
  24. pyinfra/facts/bsdinit.py +3 -0
  25. pyinfra/facts/cargo.py +5 -0
  26. pyinfra/facts/choco.py +6 -0
  27. pyinfra/facts/crontab.py +195 -0
  28. pyinfra/facts/deb.py +10 -0
  29. pyinfra/facts/dnf.py +5 -0
  30. pyinfra/facts/docker.py +16 -0
  31. pyinfra/facts/efibootmgr.py +113 -0
  32. pyinfra/facts/files.py +112 -7
  33. pyinfra/facts/flatpak.py +7 -0
  34. pyinfra/facts/freebsd.py +75 -0
  35. pyinfra/facts/gem.py +5 -0
  36. pyinfra/facts/git.py +12 -2
  37. pyinfra/facts/gpg.py +7 -0
  38. pyinfra/facts/hardware.py +13 -0
  39. pyinfra/facts/iptables.py +9 -1
  40. pyinfra/facts/launchd.py +5 -0
  41. pyinfra/facts/lxd.py +5 -0
  42. pyinfra/facts/mysql.py +9 -2
  43. pyinfra/facts/npm.py +5 -0
  44. pyinfra/facts/openrc.py +8 -0
  45. pyinfra/facts/opkg.py +245 -0
  46. pyinfra/facts/pacman.py +9 -1
  47. pyinfra/facts/pip.py +5 -0
  48. pyinfra/facts/pipx.py +82 -0
  49. pyinfra/facts/pkg.py +4 -0
  50. pyinfra/facts/pkgin.py +5 -0
  51. pyinfra/facts/podman.py +54 -0
  52. pyinfra/facts/postgres.py +10 -2
  53. pyinfra/facts/rpm.py +11 -0
  54. pyinfra/facts/runit.py +7 -0
  55. pyinfra/facts/selinux.py +16 -0
  56. pyinfra/facts/server.py +87 -79
  57. pyinfra/facts/snap.py +7 -0
  58. pyinfra/facts/systemd.py +5 -0
  59. pyinfra/facts/sysvinit.py +4 -0
  60. pyinfra/facts/upstart.py +5 -0
  61. pyinfra/facts/util/__init__.py +4 -1
  62. pyinfra/facts/util/units.py +30 -0
  63. pyinfra/facts/vzctl.py +5 -0
  64. pyinfra/facts/xbps.py +6 -1
  65. pyinfra/facts/yum.py +5 -0
  66. pyinfra/facts/zfs.py +41 -21
  67. pyinfra/facts/zypper.py +5 -0
  68. pyinfra/local.py +3 -2
  69. pyinfra/operations/apt.py +36 -22
  70. pyinfra/operations/crontab.py +189 -0
  71. pyinfra/operations/docker.py +61 -56
  72. pyinfra/operations/files.py +65 -1
  73. pyinfra/operations/freebsd/__init__.py +12 -0
  74. pyinfra/operations/freebsd/freebsd_update.py +70 -0
  75. pyinfra/operations/freebsd/pkg.py +219 -0
  76. pyinfra/operations/freebsd/service.py +116 -0
  77. pyinfra/operations/freebsd/sysrc.py +92 -0
  78. pyinfra/operations/git.py +23 -7
  79. pyinfra/operations/opkg.py +88 -0
  80. pyinfra/operations/pip.py +3 -2
  81. pyinfra/operations/pipx.py +90 -0
  82. pyinfra/operations/postgres.py +114 -27
  83. pyinfra/operations/runit.py +2 -0
  84. pyinfra/operations/server.py +9 -181
  85. pyinfra/operations/util/docker.py +44 -22
  86. pyinfra/operations/zfs.py +3 -3
  87. {pyinfra-3.1.1.dist-info → pyinfra-3.3.dist-info}/LICENSE.md +1 -1
  88. {pyinfra-3.1.1.dist-info → pyinfra-3.3.dist-info}/METADATA +25 -25
  89. pyinfra-3.3.dist-info/RECORD +187 -0
  90. pyinfra_cli/exceptions.py +5 -0
  91. pyinfra_cli/inventory.py +26 -9
  92. pyinfra_cli/log.py +3 -0
  93. pyinfra_cli/main.py +9 -8
  94. pyinfra_cli/prints.py +19 -4
  95. pyinfra_cli/util.py +3 -0
  96. pyinfra_cli/virtualenv.py +1 -1
  97. tests/test_cli/test_cli_deploy.py +15 -13
  98. tests/test_cli/test_cli_inventory.py +53 -0
  99. tests/test_connectors/test_ssh.py +302 -182
  100. tests/test_connectors/test_sshuserclient.py +68 -1
  101. pyinfra-3.1.1.dist-info/RECORD +0 -172
  102. {pyinfra-3.1.1.dist-info → pyinfra-3.3.dist-info}/WHEEL +0 -0
  103. {pyinfra-3.1.1.dist-info → pyinfra-3.3.dist-info}/entry_points.txt +0 -0
  104. {pyinfra-3.1.1.dist-info → pyinfra-3.3.dist-info}/top_level.txt +0 -0
@@ -1,12 +1,14 @@
1
1
  """
2
- Manager Docker Containers, Volumes and Networks
2
+ Manager Docker containers, volumes and networks. These operations allow you to manage Docker from
3
+ the view of the current inventory host. See the :doc:`../connectors/docker` to use Docker containers
4
+ as inventory directly.
3
5
  """
4
6
 
5
7
  from pyinfra import host
6
8
  from pyinfra.api import operation
7
9
  from pyinfra.facts.docker import DockerContainer, DockerNetwork, DockerVolume
8
10
 
9
- from .util.docker import handle_docker
11
+ from .util.docker import ContainerSpec, handle_docker
10
12
 
11
13
 
12
14
  @operation()
@@ -30,9 +32,9 @@ def container(
30
32
  + networks: network list to attach on container
31
33
  + ports: port list to expose
32
34
  + volumes: volume list to map on container
33
- + env_vars: environment varible list to inject on container
35
+ + env_vars: environment variable list to inject on container
34
36
  + pull_always: force image pull
35
- + force: remove a contaner with same name and create a new one
37
+ + force: remove a container with same name and create a new one
36
38
  + present: whether the container should be up and running
37
39
  + start: start or stop the container
38
40
 
@@ -68,56 +70,60 @@ def container(
68
70
  )
69
71
  """
70
72
 
73
+ want_spec = ContainerSpec(
74
+ image,
75
+ ports or list(),
76
+ networks or list(),
77
+ volumes or list(),
78
+ env_vars or list(),
79
+ pull_always,
80
+ )
71
81
  existent_container = host.get_fact(DockerContainer, object_id=container)
72
82
 
73
- if force:
74
- if existent_container:
75
- yield handle_docker(
76
- resource="container",
77
- command="remove",
78
- container=container,
79
- )
83
+ container_spec_changes = want_spec.diff_from_inspect(existent_container)
80
84
 
81
- if present:
82
- if not existent_container or force:
83
- yield handle_docker(
84
- resource="container",
85
- command="create",
86
- container=container,
87
- image=image,
88
- ports=ports,
89
- networks=networks,
90
- volumes=volumes,
91
- env_vars=env_vars,
92
- pull_always=pull_always,
93
- present=present,
94
- force=force,
95
- start=start,
96
- )
97
-
98
- if existent_container and start:
99
- if existent_container[0]["State"]["Status"] != "running":
100
- yield handle_docker(
101
- resource="container",
102
- command="start",
103
- container=container,
104
- )
105
-
106
- if existent_container and not start:
107
- if existent_container[0]["State"]["Status"] == "running":
108
- yield handle_docker(
109
- resource="container",
110
- command="stop",
111
- container=container,
112
- )
113
-
114
- if existent_container and not present:
85
+ is_running = (
86
+ (existent_container[0]["State"]["Status"] == "running")
87
+ if existent_container and existent_container[0]
88
+ else False
89
+ )
90
+ recreating = existent_container and (force or container_spec_changes)
91
+ removing = existent_container and not present
92
+
93
+ do_remove = recreating or removing
94
+ do_create = (present and not existent_container) or recreating
95
+ do_start = start and (recreating or not is_running)
96
+ do_stop = not start and not removing and is_running
97
+
98
+ if do_remove:
115
99
  yield handle_docker(
116
100
  resource="container",
117
101
  command="remove",
118
102
  container=container,
119
103
  )
120
104
 
105
+ if do_create:
106
+ yield handle_docker(
107
+ resource="container",
108
+ command="create",
109
+ container=container,
110
+ spec=want_spec,
111
+ )
112
+
113
+ if do_start:
114
+ yield handle_docker(
115
+ resource="container",
116
+ command="start",
117
+ container=container,
118
+ )
119
+
120
+ if do_stop:
121
+ yield handle_docker(
122
+ resource="container",
123
+ command="stop",
124
+ container=container,
125
+ )
126
+
121
127
 
122
128
  @operation(is_idempotent=False)
123
129
  def image(image, present=True):
@@ -125,7 +131,7 @@ def image(image, present=True):
125
131
  Manage Docker images
126
132
 
127
133
  + image: Image and tag ex: nginx:alpine
128
- + present: whether the Docker image should be exist
134
+ + present: whether the Docker image should exist
129
135
 
130
136
  **Examples:**
131
137
 
@@ -188,7 +194,7 @@ def volume(volume, driver="", labels=None, present=True):
188
194
  if present:
189
195
 
190
196
  if existent_volume:
191
- host.noop("Volume alredy exist!")
197
+ host.noop("Volume already exists!")
192
198
  return
193
199
 
194
200
  yield handle_docker(
@@ -231,8 +237,8 @@ def network(
231
237
  """
232
238
  Manage docker networks
233
239
 
234
- + network_name: Image name
235
- + driver: Container image and tag ex: nginx:alpine
240
+ + network: Network name
241
+ + driver: Network driver ex: bridge or overlay
236
242
  + gateway: IPv4 or IPv6 Gateway for the master subnet
237
243
  + ip_range: Allocate container ip from a sub-range
238
244
  + ipam_driver: IP Address Management Driver
@@ -251,8 +257,7 @@ def network(
251
257
 
252
258
  # Create Docker network
253
259
  docker.network(
254
- name="Create nginx network",
255
- network_name="nginx",
260
+ network="nginx",
256
261
  attachable=True,
257
262
  present=True,
258
263
  )
@@ -261,7 +266,7 @@ def network(
261
266
 
262
267
  if present:
263
268
  if existent_network:
264
- host.noop("Alredy exist a network with {0} name!".format(network))
269
+ host.noop("Network {0} already exists!".format(network))
265
270
  return
266
271
 
267
272
  yield handle_docker(
@@ -284,12 +289,12 @@ def network(
284
289
 
285
290
  else:
286
291
  if existent_network is None:
287
- host.noop("Ther is not network with {0} name!".format(network))
292
+ host.noop("Network {0} does not exist!".format(network))
288
293
  return
289
294
 
290
295
  yield handle_docker(
291
296
  resource="network",
292
- command="create",
297
+ command="remove",
293
298
  network=network,
294
299
  )
295
300
 
@@ -297,7 +302,7 @@ def network(
297
302
  @operation(is_idempotent=False)
298
303
  def prune(
299
304
  all=False,
300
- volume=False,
305
+ volumes=False,
301
306
  filter="",
302
307
  ):
303
308
  """
@@ -334,6 +339,6 @@ def prune(
334
339
  resource="system",
335
340
  command="prune",
336
341
  all=all,
337
- volume=volume,
342
+ volumes=volumes,
338
343
  filter=filter,
339
344
  )
@@ -51,6 +51,7 @@ from pyinfra.facts.files import (
51
51
  Md5File,
52
52
  Sha1File,
53
53
  Sha256File,
54
+ Sha384File,
54
55
  )
55
56
  from pyinfra.facts.server import Date, Which
56
57
 
@@ -67,6 +68,7 @@ def download(
67
68
  mode: str | None = None,
68
69
  cache_time: int | None = None,
69
70
  force=False,
71
+ sha384sum: str | None = None,
70
72
  sha256sum: str | None = None,
71
73
  sha1sum: str | None = None,
72
74
  md5sum: str | None = None,
@@ -84,6 +86,7 @@ def download(
84
86
  + mode: permissions of the files
85
87
  + cache_time: if the file exists already, re-download after this time (in seconds)
86
88
  + force: always download the file, even if it already exists
89
+ + sha384sum: sha384 hash to checksum the downloaded file against
87
90
  + sha256sum: sha256 hash to checksum the downloaded file against
88
91
  + sha1sum: sha1 hash to checksum the downloaded file against
89
92
  + md5sum: md5 hash to checksum the downloaded file against
@@ -135,6 +138,10 @@ def download(
135
138
  if sha256sum != host.get_fact(Sha256File, path=dest):
136
139
  download = True
137
140
 
141
+ if sha384sum:
142
+ if sha384sum != host.get_fact(Sha384File, path=dest):
143
+ download = True
144
+
138
145
  if md5sum:
139
146
  if md5sum != host.get_fact(Md5File, path=dest):
140
147
  download = True
@@ -211,6 +218,17 @@ def download(
211
218
  QuoteString("SHA256 did not match!"),
212
219
  )
213
220
 
221
+ if sha384sum:
222
+ yield make_formatted_string_command(
223
+ (
224
+ "(( sha384sum {0} 2> /dev/null || shasum -a 384 {0} ) "
225
+ "| grep {1}) || ( echo {2} && exit 1 )"
226
+ ),
227
+ QuoteString(dest),
228
+ sha384sum,
229
+ QuoteString("SHA384 did not match!"),
230
+ )
231
+
214
232
  if md5sum:
215
233
  yield make_formatted_string_command(
216
234
  (
@@ -647,7 +665,7 @@ def sync(
647
665
 
648
666
 
649
667
  @memoize
650
- def show_rsync_warning():
668
+ def show_rsync_warning() -> None:
651
669
  logger.warning("The `files.rsync` operation is in alpha!")
652
670
 
653
671
 
@@ -940,6 +958,9 @@ def template(
940
958
  a dict with arguments that will be passed as keyword args to the jinja2
941
959
  `Environment() <https://jinja.palletsprojects.com/en/3.0.x/api/#jinja2.Environment>`_.
942
960
 
961
+ The ``host``, ``state``, and ``inventory`` objects will be automatically passed to the template
962
+ if not set explicitly.
963
+
943
964
  Notes:
944
965
  Common convention is to store templates in a "templates" directory and
945
966
  have a filename suffix with '.j2' (for jinja2).
@@ -997,6 +1018,21 @@ def template(
997
1018
  foo_dict=foo_dict,
998
1019
  foo_list=foo_list
999
1020
  )
1021
+
1022
+ # Example showing how to use host and inventory in a template file.
1023
+ template = StringIO("""
1024
+ name: "{{ host.name }}"
1025
+ list_contents:
1026
+ {% for entry in inventory.groups.my_servers %}
1027
+ - "{{ entry }}"
1028
+ {% endfor %}
1029
+ """)
1030
+
1031
+ files.template(
1032
+ name="Create a templated file",
1033
+ src=template,
1034
+ dest="/tmp/foo.yml"
1035
+ )
1000
1036
  '''
1001
1037
 
1002
1038
  if not hasattr(src, "read") and state.cwd:
@@ -1051,6 +1087,34 @@ def template(
1051
1087
  )
1052
1088
 
1053
1089
 
1090
+ @operation()
1091
+ def move(src: str, dest: str, overwrite=False):
1092
+ """
1093
+ Move remote file/directory/link into remote directory
1094
+
1095
+ + src: remote file/directory to move
1096
+ + dest: remote directory to move `src` into
1097
+ + overwrite: whether to overwrite dest, if present
1098
+ """
1099
+
1100
+ if host.get_fact(File, src) is None:
1101
+ raise OperationError("src {0} does not exist".format(src))
1102
+
1103
+ if not host.get_fact(Directory, dest):
1104
+ raise OperationError("dest {0} is not an existing directory".format(dest))
1105
+
1106
+ full_dest_path = os.path.join(dest, os.path.basename(src))
1107
+ if host.get_fact(File, full_dest_path) is not None:
1108
+ if overwrite:
1109
+ yield StringCommand("rm", "-rf", QuoteString(full_dest_path))
1110
+ else:
1111
+ raise OperationError(
1112
+ "dest {0} already exists and `overwrite` is unset".format(full_dest_path)
1113
+ )
1114
+
1115
+ yield StringCommand("mv", QuoteString(src), QuoteString(dest))
1116
+
1117
+
1054
1118
  def _validate_path(path):
1055
1119
  try:
1056
1120
  return os.fspath(path)
@@ -0,0 +1,12 @@
1
+ # This file only exists to support:
2
+ # from pyinfra.operations import freebsd
3
+ # freebsd.X.Y
4
+
5
+ from glob import glob
6
+ from os import path
7
+
8
+ module_filenames = glob(path.join(path.dirname(__file__), "*.py"))
9
+ module_names = [path.basename(name)[:-3] for name in module_filenames]
10
+ __all__ = [name for name in module_names if name != "__init__"]
11
+
12
+ from . import * # noqa
@@ -0,0 +1,70 @@
1
+ """
2
+ Fetch and install binary updates to FreeBSD.
3
+ """
4
+
5
+ from __future__ import annotations
6
+
7
+ from typing_extensions import List, Optional, Union
8
+
9
+ from pyinfra.api import QuoteString, StringCommand, operation
10
+
11
+
12
+ @operation()
13
+ def update(
14
+ force: bool = False,
15
+ basedir: Optional[str] = None,
16
+ workdir: Optional[str] = None,
17
+ conffile: Optional[str] = None,
18
+ jail: Optional[str] = None,
19
+ key: Optional[str] = None,
20
+ currently_running: Optional[str] = None,
21
+ server: Optional[str] = None,
22
+ ):
23
+ """
24
+ Based on the currently installed world and the configuration options set, fetch
25
+ all available binary updates and install them.
26
+
27
+ + force: See ``-F`` in ``freebsd-update(8)``.
28
+ + basedir: See ``-b`` in ``freebsd-update(8)``.
29
+ + workdir: See ``-d`` in ``freebsd-update(8)``.
30
+ + conffile: See ``-f`` in ``freebsd-update(8)``.
31
+ + jail: See ``-j`` in ``freebsd-update(8)``.
32
+ + key: See ``-k`` in ``freebsd-update(8)``.
33
+ + currently_running: See ``--currently-running`` in ``freebsd-update(8)``.
34
+ + server: See ``-s`` in ``freebsd-update(8)``.
35
+
36
+ **Example:**
37
+
38
+ .. code:: python
39
+
40
+ freebsd_update.update()
41
+ """
42
+
43
+ args: List[Union[str, "QuoteString"]] = []
44
+
45
+ args.extend(["PAGER=cat", "freebsd-update", "--not-running-from-cron"])
46
+
47
+ if force:
48
+ args.append("-F")
49
+
50
+ if basedir is not None:
51
+ args.extend(["-b", QuoteString(basedir)])
52
+
53
+ if workdir is not None:
54
+ args.extend(["-d", QuoteString(workdir)])
55
+
56
+ if conffile is not None:
57
+ args.extend(["-f", QuoteString(conffile)])
58
+
59
+ if jail is not None:
60
+ args.extend(["-j", QuoteString(jail)])
61
+
62
+ if key is not None:
63
+ args.extend(["-k", QuoteString(key)])
64
+
65
+ if server is not None:
66
+ args.extend(["-s", QuoteString(server)])
67
+
68
+ args.extend(["fetch", "install"])
69
+
70
+ yield StringCommand(*args)
@@ -0,0 +1,219 @@
1
+ """
2
+ Manage FreeBSD packages.
3
+ """
4
+
5
+ from __future__ import annotations
6
+
7
+ from typing_extensions import List, Optional, Union
8
+
9
+ from pyinfra import host
10
+ from pyinfra.api import QuoteString, StringCommand, operation
11
+ from pyinfra.facts.freebsd import PkgPackage
12
+
13
+
14
+ @operation()
15
+ def update(jail: Optional[str] = None, force: bool = False, reponame: Optional[str] = None):
16
+ """
17
+ Update the local catalogues of the enabled package repositories.
18
+
19
+ + jail: See ``-j`` in ``pkg(8)``.
20
+ + force: See ``-f`` in ``pkg-update(8)``.
21
+ + reponame: See ``-r`` in ``pkg-update(8)``
22
+
23
+ **Examples:**
24
+
25
+ .. code:: python
26
+
27
+ # host
28
+ pkg.update()
29
+
30
+ # jail
31
+ pkg.update(
32
+ jail="nginx"
33
+ )
34
+ """
35
+
36
+ args: List[Union[str, "QuoteString"]] = []
37
+
38
+ args.append("pkg")
39
+
40
+ if jail is not None:
41
+ args.extend(["-j", QuoteString(jail)])
42
+
43
+ args.extend(["update"])
44
+
45
+ if force:
46
+ args.append("-f")
47
+
48
+ if reponame is not None:
49
+ args.extend(["-r", QuoteString(reponame)])
50
+
51
+ yield StringCommand(*args)
52
+
53
+
54
+ @operation()
55
+ def upgrade(jail: Optional[str] = None, force: bool = False, reponame: Optional[str] = None):
56
+ """
57
+ Perform upgrades of package software distributions.
58
+
59
+ + jail: See ``-j`` in ``pkg(8)``.
60
+ + force: See ``-f`` in ``pkg-upgrade(8)``.
61
+ + reponame: See ``-r`` in ``pkg-upgrade(8)``.
62
+
63
+ **Examples:**
64
+
65
+ .. code:: python
66
+
67
+ # host
68
+ pkg.upgrade()
69
+
70
+ # jail
71
+ pkg.upgrade(
72
+ jail="nginx"
73
+ )
74
+ """
75
+
76
+ args: List[Union[str, "QuoteString"]] = []
77
+
78
+ args.append("pkg")
79
+
80
+ if jail is not None:
81
+ args.extend(["-j", QuoteString(jail)])
82
+
83
+ args.extend(["upgrade", "-y"])
84
+
85
+ if force:
86
+ args.append("-f")
87
+
88
+ if reponame is not None:
89
+ args.extend(["-r", QuoteString(reponame)])
90
+
91
+ yield StringCommand(*args)
92
+
93
+
94
+ @operation()
95
+ def install(package: str, jail: Optional[str] = None, reponame: Optional[str] = None):
96
+ """
97
+ Install packages from remote packages repositories or local archives.
98
+
99
+ + package: Package to install.
100
+ + jail: See ``-j`` in ``pkg(8)``.
101
+ + reponame: See ``-r`` in ``pkg-install(8)``.
102
+
103
+ **Example:**
104
+
105
+ .. code:: python
106
+
107
+ pkg.install("nginx")
108
+ """
109
+
110
+ if host.get_fact(PkgPackage, package=package, jail=jail):
111
+ host.noop(f"Package '{package}' already installed")
112
+ return
113
+
114
+ args: List[Union[str, "QuoteString"]] = []
115
+
116
+ args.append("pkg")
117
+
118
+ if jail is not None:
119
+ args.extend(["-j", QuoteString(jail)])
120
+
121
+ args.extend(["install", "-y"])
122
+
123
+ if reponame is not None:
124
+ args.extend(["-r", QuoteString(reponame)])
125
+
126
+ args.extend(["--", QuoteString(package)])
127
+
128
+ yield StringCommand(*args)
129
+
130
+
131
+ @operation()
132
+ def remove(package: str, jail: Optional[str] = None):
133
+ """
134
+ Deletes packages from the database and the system.
135
+
136
+ + package: Package to remove.
137
+ + jail: See ``-j`` in ``pkg(8)``.
138
+
139
+ **Example:**
140
+
141
+ .. code:: python
142
+
143
+ pkg.remove("nginx")
144
+ """
145
+
146
+ if not host.get_fact(PkgPackage, package=package, jail=jail):
147
+ host.noop(f"Package '{package}' cannot be found")
148
+ return
149
+
150
+ args: List[Union[str, "QuoteString"]] = []
151
+
152
+ args.append("pkg")
153
+
154
+ if jail is not None:
155
+ args.extend(["-j", QuoteString(jail)])
156
+
157
+ args.extend(["remove", "-y"])
158
+
159
+ args.extend(["--", QuoteString(package)])
160
+
161
+ yield StringCommand(*args)
162
+
163
+
164
+ @operation()
165
+ def autoremove(jail: Optional[str] = None):
166
+ """
167
+ Remove orphan packages.
168
+
169
+ + jail: See ``-j`` in ``pkg(8)``.
170
+
171
+ **Example:**
172
+
173
+ .. code:: python
174
+
175
+ pkg.autoremove()
176
+ """
177
+
178
+ args: List[Union[str, "QuoteString"]] = []
179
+
180
+ args.append("pkg")
181
+
182
+ if jail is not None:
183
+ args.extend(["-j", QuoteString(jail)])
184
+
185
+ args.extend(["autoremove", "-y"])
186
+
187
+ yield StringCommand(*args)
188
+
189
+
190
+ @operation()
191
+ def clean(all_pkg: bool = False, jail: Optional[str] = None):
192
+ """
193
+ Clean the local cache of fetched remote packages.
194
+
195
+ + all_pkg: See ``-a`` in ``pkg-clean(8)``.
196
+ + jail: See ``-j`` in ``pkg(8)``.
197
+
198
+ **Example:**
199
+
200
+ .. code:: python
201
+
202
+ pkg.clean(
203
+ all_pkg=True
204
+ )
205
+ """
206
+
207
+ args: List[Union[str, "QuoteString"]] = []
208
+
209
+ args.append("pkg")
210
+
211
+ if jail is not None:
212
+ args.extend(["-j", QuoteString(jail)])
213
+
214
+ args.extend(["clean", "-y"])
215
+
216
+ if all_pkg:
217
+ args.append("-a")
218
+
219
+ yield StringCommand(*args)