pyinfra 0.11.dev3__py3-none-any.whl → 3.6__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 (204) hide show
  1. pyinfra/__init__.py +9 -12
  2. pyinfra/__main__.py +4 -0
  3. pyinfra/api/__init__.py +19 -3
  4. pyinfra/api/arguments.py +413 -0
  5. pyinfra/api/arguments_typed.py +79 -0
  6. pyinfra/api/command.py +274 -0
  7. pyinfra/api/config.py +222 -28
  8. pyinfra/api/connect.py +33 -13
  9. pyinfra/api/connectors.py +27 -0
  10. pyinfra/api/deploy.py +65 -66
  11. pyinfra/api/exceptions.py +73 -18
  12. pyinfra/api/facts.py +267 -200
  13. pyinfra/api/host.py +416 -50
  14. pyinfra/api/inventory.py +121 -160
  15. pyinfra/api/metadata.py +69 -0
  16. pyinfra/api/operation.py +432 -262
  17. pyinfra/api/operations.py +273 -260
  18. pyinfra/api/state.py +302 -248
  19. pyinfra/api/util.py +309 -369
  20. pyinfra/connectors/base.py +173 -0
  21. pyinfra/connectors/chroot.py +212 -0
  22. pyinfra/connectors/docker.py +405 -0
  23. pyinfra/connectors/dockerssh.py +297 -0
  24. pyinfra/connectors/local.py +238 -0
  25. pyinfra/connectors/scp/__init__.py +1 -0
  26. pyinfra/connectors/scp/client.py +204 -0
  27. pyinfra/connectors/ssh.py +727 -0
  28. pyinfra/connectors/ssh_util.py +114 -0
  29. pyinfra/connectors/sshuserclient/client.py +309 -0
  30. pyinfra/connectors/sshuserclient/config.py +102 -0
  31. pyinfra/connectors/terraform.py +135 -0
  32. pyinfra/connectors/util.py +417 -0
  33. pyinfra/connectors/vagrant.py +183 -0
  34. pyinfra/context.py +145 -0
  35. pyinfra/facts/__init__.py +7 -6
  36. pyinfra/facts/apk.py +22 -7
  37. pyinfra/facts/apt.py +117 -60
  38. pyinfra/facts/brew.py +100 -15
  39. pyinfra/facts/bsdinit.py +23 -0
  40. pyinfra/facts/cargo.py +37 -0
  41. pyinfra/facts/choco.py +47 -0
  42. pyinfra/facts/crontab.py +195 -0
  43. pyinfra/facts/deb.py +94 -0
  44. pyinfra/facts/dnf.py +48 -0
  45. pyinfra/facts/docker.py +96 -23
  46. pyinfra/facts/efibootmgr.py +113 -0
  47. pyinfra/facts/files.py +629 -58
  48. pyinfra/facts/flatpak.py +77 -0
  49. pyinfra/facts/freebsd.py +70 -0
  50. pyinfra/facts/gem.py +19 -6
  51. pyinfra/facts/git.py +59 -14
  52. pyinfra/facts/gpg.py +150 -0
  53. pyinfra/facts/hardware.py +313 -167
  54. pyinfra/facts/iptables.py +72 -62
  55. pyinfra/facts/launchd.py +44 -0
  56. pyinfra/facts/lxd.py +17 -4
  57. pyinfra/facts/mysql.py +122 -86
  58. pyinfra/facts/npm.py +17 -9
  59. pyinfra/facts/openrc.py +71 -0
  60. pyinfra/facts/opkg.py +246 -0
  61. pyinfra/facts/pacman.py +50 -7
  62. pyinfra/facts/pip.py +24 -7
  63. pyinfra/facts/pipx.py +82 -0
  64. pyinfra/facts/pkg.py +15 -6
  65. pyinfra/facts/pkgin.py +35 -0
  66. pyinfra/facts/podman.py +54 -0
  67. pyinfra/facts/postgres.py +178 -0
  68. pyinfra/facts/postgresql.py +6 -147
  69. pyinfra/facts/rpm.py +105 -0
  70. pyinfra/facts/runit.py +77 -0
  71. pyinfra/facts/selinux.py +161 -0
  72. pyinfra/facts/server.py +762 -285
  73. pyinfra/facts/snap.py +88 -0
  74. pyinfra/facts/systemd.py +139 -0
  75. pyinfra/facts/sysvinit.py +59 -0
  76. pyinfra/facts/upstart.py +35 -0
  77. pyinfra/facts/util/__init__.py +17 -0
  78. pyinfra/facts/util/databases.py +4 -6
  79. pyinfra/facts/util/packaging.py +37 -6
  80. pyinfra/facts/util/units.py +30 -0
  81. pyinfra/facts/util/win_files.py +99 -0
  82. pyinfra/facts/vzctl.py +20 -13
  83. pyinfra/facts/xbps.py +35 -0
  84. pyinfra/facts/yum.py +34 -40
  85. pyinfra/facts/zfs.py +77 -0
  86. pyinfra/facts/zypper.py +42 -0
  87. pyinfra/local.py +45 -83
  88. pyinfra/operations/__init__.py +12 -0
  89. pyinfra/operations/apk.py +99 -0
  90. pyinfra/operations/apt.py +496 -0
  91. pyinfra/operations/brew.py +232 -0
  92. pyinfra/operations/bsdinit.py +59 -0
  93. pyinfra/operations/cargo.py +45 -0
  94. pyinfra/operations/choco.py +61 -0
  95. pyinfra/operations/crontab.py +194 -0
  96. pyinfra/operations/dnf.py +213 -0
  97. pyinfra/operations/docker.py +492 -0
  98. pyinfra/operations/files.py +2014 -0
  99. pyinfra/operations/flatpak.py +95 -0
  100. pyinfra/operations/freebsd/__init__.py +12 -0
  101. pyinfra/operations/freebsd/freebsd_update.py +70 -0
  102. pyinfra/operations/freebsd/pkg.py +219 -0
  103. pyinfra/operations/freebsd/service.py +116 -0
  104. pyinfra/operations/freebsd/sysrc.py +92 -0
  105. pyinfra/operations/gem.py +48 -0
  106. pyinfra/operations/git.py +420 -0
  107. pyinfra/operations/iptables.py +312 -0
  108. pyinfra/operations/launchd.py +45 -0
  109. pyinfra/operations/lxd.py +69 -0
  110. pyinfra/operations/mysql.py +610 -0
  111. pyinfra/operations/npm.py +57 -0
  112. pyinfra/operations/openrc.py +63 -0
  113. pyinfra/operations/opkg.py +89 -0
  114. pyinfra/operations/pacman.py +82 -0
  115. pyinfra/operations/pip.py +206 -0
  116. pyinfra/operations/pipx.py +103 -0
  117. pyinfra/operations/pkg.py +71 -0
  118. pyinfra/operations/pkgin.py +92 -0
  119. pyinfra/operations/postgres.py +437 -0
  120. pyinfra/operations/postgresql.py +30 -0
  121. pyinfra/operations/puppet.py +41 -0
  122. pyinfra/operations/python.py +73 -0
  123. pyinfra/operations/runit.py +184 -0
  124. pyinfra/operations/selinux.py +190 -0
  125. pyinfra/operations/server.py +1100 -0
  126. pyinfra/operations/snap.py +118 -0
  127. pyinfra/operations/ssh.py +217 -0
  128. pyinfra/operations/systemd.py +150 -0
  129. pyinfra/operations/sysvinit.py +142 -0
  130. pyinfra/operations/upstart.py +68 -0
  131. pyinfra/operations/util/__init__.py +12 -0
  132. pyinfra/operations/util/docker.py +407 -0
  133. pyinfra/operations/util/files.py +247 -0
  134. pyinfra/operations/util/packaging.py +338 -0
  135. pyinfra/operations/util/service.py +46 -0
  136. pyinfra/operations/vzctl.py +137 -0
  137. pyinfra/operations/xbps.py +78 -0
  138. pyinfra/operations/yum.py +213 -0
  139. pyinfra/operations/zfs.py +176 -0
  140. pyinfra/operations/zypper.py +193 -0
  141. pyinfra/progress.py +44 -32
  142. pyinfra/py.typed +0 -0
  143. pyinfra/version.py +9 -1
  144. pyinfra-3.6.dist-info/METADATA +142 -0
  145. pyinfra-3.6.dist-info/RECORD +160 -0
  146. {pyinfra-0.11.dev3.dist-info → pyinfra-3.6.dist-info}/WHEEL +1 -2
  147. pyinfra-3.6.dist-info/entry_points.txt +12 -0
  148. {pyinfra-0.11.dev3.dist-info → pyinfra-3.6.dist-info/licenses}/LICENSE.md +1 -1
  149. pyinfra_cli/__init__.py +1 -0
  150. pyinfra_cli/cli.py +793 -0
  151. pyinfra_cli/commands.py +66 -0
  152. pyinfra_cli/exceptions.py +155 -65
  153. pyinfra_cli/inventory.py +233 -89
  154. pyinfra_cli/log.py +39 -43
  155. pyinfra_cli/main.py +26 -495
  156. pyinfra_cli/prints.py +215 -156
  157. pyinfra_cli/util.py +172 -105
  158. pyinfra_cli/virtualenv.py +25 -20
  159. pyinfra/api/connectors/__init__.py +0 -21
  160. pyinfra/api/connectors/ansible.py +0 -99
  161. pyinfra/api/connectors/docker.py +0 -178
  162. pyinfra/api/connectors/local.py +0 -169
  163. pyinfra/api/connectors/ssh.py +0 -402
  164. pyinfra/api/connectors/sshuserclient/client.py +0 -105
  165. pyinfra/api/connectors/sshuserclient/config.py +0 -90
  166. pyinfra/api/connectors/util.py +0 -63
  167. pyinfra/api/connectors/vagrant.py +0 -155
  168. pyinfra/facts/init.py +0 -176
  169. pyinfra/facts/util/files.py +0 -102
  170. pyinfra/hook.py +0 -41
  171. pyinfra/modules/__init__.py +0 -11
  172. pyinfra/modules/apk.py +0 -64
  173. pyinfra/modules/apt.py +0 -272
  174. pyinfra/modules/brew.py +0 -122
  175. pyinfra/modules/files.py +0 -711
  176. pyinfra/modules/gem.py +0 -30
  177. pyinfra/modules/git.py +0 -115
  178. pyinfra/modules/init.py +0 -344
  179. pyinfra/modules/iptables.py +0 -271
  180. pyinfra/modules/lxd.py +0 -45
  181. pyinfra/modules/mysql.py +0 -347
  182. pyinfra/modules/npm.py +0 -47
  183. pyinfra/modules/pacman.py +0 -60
  184. pyinfra/modules/pip.py +0 -99
  185. pyinfra/modules/pkg.py +0 -43
  186. pyinfra/modules/postgresql.py +0 -245
  187. pyinfra/modules/puppet.py +0 -20
  188. pyinfra/modules/python.py +0 -37
  189. pyinfra/modules/server.py +0 -524
  190. pyinfra/modules/ssh.py +0 -150
  191. pyinfra/modules/util/files.py +0 -52
  192. pyinfra/modules/util/packaging.py +0 -118
  193. pyinfra/modules/vzctl.py +0 -133
  194. pyinfra/modules/yum.py +0 -171
  195. pyinfra/pseudo_modules.py +0 -64
  196. pyinfra-0.11.dev3.dist-info/.DS_Store +0 -0
  197. pyinfra-0.11.dev3.dist-info/METADATA +0 -135
  198. pyinfra-0.11.dev3.dist-info/RECORD +0 -95
  199. pyinfra-0.11.dev3.dist-info/entry_points.txt +0 -3
  200. pyinfra-0.11.dev3.dist-info/top_level.txt +0 -2
  201. pyinfra_cli/__main__.py +0 -40
  202. pyinfra_cli/config.py +0 -92
  203. /pyinfra/{modules/util → connectors}/__init__.py +0 -0
  204. /pyinfra/{api/connectors → connectors}/sshuserclient/__init__.py +0 -0
pyinfra/facts/yum.py CHANGED
@@ -1,53 +1,47 @@
1
- import re
1
+ from __future__ import annotations
2
2
 
3
- from pyinfra.api import FactBase
3
+ from typing_extensions import override
4
4
 
5
- from .util.packaging import parse_packages
5
+ from pyinfra.api import FactBase
6
6
 
7
- rpm_regex = r'^([a-zA-Z0-9_\-\+]+)\-([0-9a-z\.\-]+)\.[a-z0-9_\.]+$'
7
+ from .util import make_cat_files_command
8
+ from .util.packaging import parse_yum_repositories
8
9
 
9
10
 
10
- class RPMPackages(FactBase):
11
- '''
12
- Returns a dict of installed rpm packages:
11
+ class YumRepositories(FactBase):
12
+ """
13
+ Returns a list of installed yum repositories:
13
14
 
14
15
  .. code:: python
15
16
 
16
- 'package_name': ['version'],
17
- ...
18
- '''
19
-
20
- command = 'rpm -qa'
21
- default = dict
22
-
23
- def process(self, output):
24
- return parse_packages(
25
- rpm_regex, output,
26
- # yum packages are case-sensitive
27
- lower=False,
17
+ [
18
+ {
19
+ "repoid": "baseos",
20
+ "name": "AlmaLinux $releasever - BaseOS",
21
+ "mirrorlist": "https://mirrors.almalinux.org/mirrorlist/$releasever/baseos",
22
+ "enabled": "1",
23
+ "gpgcheck": "1",
24
+ "countme": "1",
25
+ "gpgkey": "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-9",
26
+ "metadata_expire": "86400",
27
+ "enabled_metadata": "1"
28
+ },
29
+ ]
30
+ """
31
+
32
+ @override
33
+ def command(self) -> str:
34
+ return make_cat_files_command(
35
+ "/etc/yum.conf",
36
+ "/etc/yum.repos.d/*.repo",
28
37
  )
29
38
 
39
+ @override
40
+ def requires_command(self) -> str:
41
+ return "yum"
30
42
 
31
- class RpmPackage(FactBase):
32
- '''
33
- Returns information on a .rpm file:
34
-
35
- .. code:: python
36
-
37
- {
38
- 'name': 'my_package',
39
- 'version': '1.0.0'
40
- }
41
- '''
42
-
43
- def command(self, name):
44
- return 'rpm -qp {0}'.format(name)
43
+ default = list
45
44
 
45
+ @override
46
46
  def process(self, output):
47
- for line in output:
48
- matches = re.match(rpm_regex, line)
49
- if matches:
50
- return {
51
- 'name': matches.group(1),
52
- 'version': matches.group(2),
53
- }
47
+ return parse_yum_repositories(output)
pyinfra/facts/zfs.py ADDED
@@ -0,0 +1,77 @@
1
+ """
2
+ Gather information about ZFS filesystems.
3
+ """
4
+
5
+ from typing_extensions import override
6
+
7
+ from pyinfra.api import FactBase, ShortFactBase
8
+
9
+
10
+ def _process_zfs_props_table(output):
11
+ datasets: dict = {}
12
+ for line in output:
13
+ dataset, property, value, source = tuple(line.split("\t"))
14
+ if dataset not in datasets:
15
+ datasets[dataset] = {}
16
+ datasets[dataset][property] = value
17
+ return datasets
18
+
19
+
20
+ class ZfsPools(FactBase):
21
+ @override
22
+ def command(self) -> str:
23
+ return "zpool get -H all"
24
+
25
+ @override
26
+ def requires_command(self) -> str:
27
+ return "zpool"
28
+
29
+ @override
30
+ def process(self, output):
31
+ return _process_zfs_props_table(output)
32
+
33
+
34
+ class ZfsDatasets(FactBase):
35
+ @override
36
+ def command(self) -> str:
37
+ return "zfs get -H all"
38
+
39
+ @override
40
+ def requires_command(self) -> str:
41
+ return "zfs"
42
+
43
+ @override
44
+ def process(self, output):
45
+ return _process_zfs_props_table(output)
46
+
47
+
48
+ class ZfsFilesystems(ShortFactBase):
49
+ fact = ZfsDatasets
50
+
51
+ @override
52
+ def process_data(self, data):
53
+ return {name: props for name, props in data.items() if props.get("type") == "filesystem"}
54
+
55
+
56
+ class ZfsSnapshots(ShortFactBase):
57
+ fact = ZfsDatasets
58
+
59
+ @override
60
+ def process_data(self, data):
61
+ return {name: props for name, props in data.items() if props.get("type") == "snapshot"}
62
+
63
+
64
+ class ZfsVolumes(ShortFactBase):
65
+ fact = ZfsDatasets
66
+
67
+ @override
68
+ def process_data(self, data):
69
+ return {name: props for name, props in data.items() if props.get("type") == "volume"}
70
+
71
+
72
+ # TODO: remove these in v4! Or flip the convention and remove all the other fact prefixes!
73
+ Pools = ZfsPools
74
+ Datasets = ZfsDatasets
75
+ Filesystems = ZfsFilesystems
76
+ Snapshots = ZfsSnapshots
77
+ Volumes = ZfsVolumes
@@ -0,0 +1,42 @@
1
+ from __future__ import annotations
2
+
3
+ from typing_extensions import override
4
+
5
+ from pyinfra.api import FactBase
6
+
7
+ from .util import make_cat_files_command
8
+ from .util.packaging import parse_zypper_repositories
9
+
10
+
11
+ class ZypperRepositories(FactBase):
12
+ """
13
+ Returns a list of installed zypper repositories:
14
+
15
+ .. code:: python
16
+
17
+ [
18
+ {
19
+ "repoid": "repo-oss",
20
+ "name": "Main Repository",
21
+ "enabled": "1",
22
+ "autorefresh": "1",
23
+ "baseurl": "http://download.opensuse.org/distribution/leap/$releasever/repo/oss/"
24
+ },
25
+ ]
26
+ """
27
+
28
+ @override
29
+ def command(self) -> str:
30
+ return make_cat_files_command(
31
+ "/etc/zypp/repos.d/*.repo",
32
+ )
33
+
34
+ @override
35
+ def requires_command(self) -> str:
36
+ return "zypper"
37
+
38
+ default = list
39
+
40
+ @override
41
+ def process(self, output):
42
+ return parse_zypper_repositories(output)
pyinfra/local.py CHANGED
@@ -1,134 +1,96 @@
1
1
  from os import path
2
- from subprocess import PIPE, Popen, STDOUT
2
+ from typing import Optional
3
3
 
4
- from gevent.queue import Queue
4
+ import click
5
5
 
6
6
  import pyinfra
7
+ from pyinfra import config, host, logger, state
8
+ from pyinfra.api.exceptions import PyinfraError
9
+ from pyinfra.api.util import get_file_path
10
+ from pyinfra.connectors.util import run_local_process
11
+ from pyinfra.context import ctx_state
7
12
 
8
- from . import logger, pseudo_host, pseudo_state
9
- from .api.exceptions import PyinfraError
10
- from .api.util import ensure_host_list, get_caller_frameinfo, read_buffer
11
13
 
12
-
13
- def include(filename, hosts=False, when=True):
14
- '''
15
- Executes a local python file within the ``pyinfra.pseudo_state.deploy_dir``
14
+ def include(filename: str, data: Optional[dict] = None):
15
+ """
16
+ Executes a local python file within the ``pyinfra.state.cwd``
16
17
  directory.
17
-
18
- Args:
19
- hosts (string, list): group name or list of hosts to limit this include to
20
- when (bool): indicate whether to trigger operations in this include
21
- '''
18
+ """
22
19
 
23
20
  if not pyinfra.is_cli:
24
- raise PyinfraError('local.include is only available in CLI mode.')
21
+ raise PyinfraError("local.include is only available in CLI mode.")
25
22
 
26
- if not when:
27
- return
23
+ filename = get_file_path(state, filename)
28
24
 
29
- if hosts is not False:
30
- hosts = ensure_host_list(hosts, inventory=pseudo_state.inventory)
31
- if pseudo_host not in hosts:
32
- return
25
+ logger.debug("Including local file: %s", filename)
33
26
 
34
- if pseudo_state.deploy_dir:
35
- filename = path.join(pseudo_state.deploy_dir, filename)
36
-
37
- frameinfo = get_caller_frameinfo()
38
-
39
- logger.debug('Including local file: {0}'.format(filename))
27
+ config_state = config.get_current_state()
40
28
 
41
29
  try:
42
30
  # Fixes a circular import because `pyinfra.local` is really a CLI
43
31
  # only thing (so should be `pyinfra_cli.local`). It is kept here
44
- # to maintain backwards compatability and the nicer public import
32
+ # to maintain backwards compatibility and the nicer public import
45
33
  # (ideally users never need to import from `pyinfra_cli`).
46
34
 
47
- from pyinfra_cli.config import extract_file_config
48
35
  from pyinfra_cli.util import exec_file
49
36
 
50
- # Load any config defined in the file and setup like a @deploy
51
- config_data = extract_file_config(filename)
52
- kwargs = {
53
- key.lower(): value
54
- for key, value in config_data.items()
55
- if key in [
56
- 'SUDO', 'SUDO_USER', 'SU_USER',
57
- 'PRESERVE_SUDO_ENV', 'IGNORE_ERRORS',
58
- ]
59
- }
60
- with pseudo_state.deploy(
61
- filename, kwargs, None, frameinfo.lineno,
62
- in_deploy=False,
63
- ):
37
+ with host.deploy(path.relpath(filename, state.cwd), None, data, in_deploy=False):
64
38
  exec_file(filename)
65
39
 
66
40
  # One potential solution to the above is to add local as an actual
67
- # module, ie `pyinfra.modules.local`.
41
+ # module, ie `pyinfra.operations.local`.
68
42
 
69
- except IOError as e:
70
- raise PyinfraError(
71
- 'Could not include local file: {0}\n{1}'.format(filename, e),
72
- )
43
+ finally:
44
+ config.set_current_state(config_state)
73
45
 
74
46
 
75
- def shell(commands, splitlines=False, ignore_errors=False):
76
- '''
47
+ def shell(
48
+ commands,
49
+ splitlines: bool = False,
50
+ ignore_errors: bool = False,
51
+ print_output: bool = False,
52
+ print_input: bool = False,
53
+ ):
54
+ """
77
55
  Subprocess based implementation of pyinfra/api/ssh.py's ``run_shell_command``.
78
56
 
79
57
  Args:
80
58
  commands (string, list): command or list of commands to execute
81
- spltlines (bool): optionally have the output split by lines
59
+ splitlines (bool): optionally have the output split by lines
82
60
  ignore_errors (bool): ignore errors when executing these commands
83
- '''
61
+ """
84
62
 
85
63
  if isinstance(commands, str):
86
64
  commands = [commands]
87
65
 
88
66
  all_stdout = []
89
67
 
90
- # Checking for pseudo_state means this function works outside a deploy
91
- # eg the vagrant connector.
92
- print_output = (
93
- pseudo_state.print_output
94
- if pseudo_state.isset()
95
- else False
96
- )
68
+ # Checking for state context being set means this function works outside a deploy
69
+ # e.g.: the vagrant connector.
70
+ if ctx_state.isset():
71
+ print_output = state.print_output
72
+ print_input = state.print_input
97
73
 
98
74
  for command in commands:
99
- print_prefix = 'localhost: '
75
+ print_prefix = "localhost: "
100
76
 
101
- if print_output:
102
- print('{0}>>> {1}'.format(print_prefix, command))
77
+ if print_input:
78
+ click.echo("{0}>>> {1}".format(print_prefix, command), err=True)
103
79
 
104
- process = Popen(command, shell=True, stdout=PIPE, stderr=STDOUT)
105
-
106
- stdout_queue = Queue()
107
-
108
- read_buffer(
109
- 'stdout',
110
- process.stdout,
111
- stdout_queue,
80
+ return_code, output = run_local_process(
81
+ command,
112
82
  print_output=print_output,
113
- print_func=lambda line: '{0}{1}'.format(print_prefix, line),
83
+ print_prefix=print_prefix,
114
84
  )
115
85
 
116
- stdout = [line for _, line in stdout_queue.queue]
117
-
118
- # Get & check result
119
- result = process.wait()
120
-
121
- # Close any open file descriptor
122
- process.stdout.close()
123
-
124
- if result > 0 and not ignore_errors:
86
+ if return_code > 0 and not ignore_errors:
125
87
  raise PyinfraError(
126
- 'Local command failed: {0}\n{1}'.format(command, stdout),
88
+ "Local command failed: {0}\n{1}".format(command, output.stderr),
127
89
  )
128
90
 
129
- all_stdout.extend(stdout)
91
+ all_stdout.extend(output.stdout_lines)
130
92
 
131
93
  if not splitlines:
132
- return '\n'.join(all_stdout)
94
+ return "\n".join(all_stdout)
133
95
 
134
96
  return all_stdout
@@ -0,0 +1,12 @@
1
+ # This file only exists to support:
2
+ # from pyinfra import operations
3
+ # operations.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,99 @@
1
+ """
2
+ Manage apk packages. (Alpine Linux)
3
+ """
4
+
5
+ from __future__ import annotations
6
+
7
+ from pyinfra import host
8
+ from pyinfra.api import operation
9
+ from pyinfra.facts.apk import ApkPackages
10
+
11
+ from .util.packaging import ensure_packages
12
+
13
+
14
+ @operation(is_idempotent=False)
15
+ def upgrade(available: bool = False):
16
+ """
17
+ Upgrades all apk packages.
18
+
19
+ + available: force all packages to be upgraded (recommended on whole Alpine version upgrades)
20
+ """
21
+
22
+ if available:
23
+ yield "apk upgrade --available"
24
+ else:
25
+ yield "apk upgrade"
26
+
27
+
28
+ _upgrade = upgrade._inner # noqa: E305
29
+
30
+
31
+ @operation(is_idempotent=False)
32
+ def update():
33
+ """
34
+ Updates apk repositories.
35
+ """
36
+
37
+ yield "apk update"
38
+
39
+
40
+ _update = update._inner # noqa: E305
41
+
42
+
43
+ @operation()
44
+ def packages(
45
+ packages: str | list[str] | None = None,
46
+ present=True,
47
+ latest=False,
48
+ update=False,
49
+ upgrade=False,
50
+ ):
51
+ """
52
+ Add/remove/update apk packages.
53
+
54
+ + packages: list of packages to ensure
55
+ + present: whether the packages should be installed
56
+ + latest: whether to upgrade packages without a specified version
57
+ + update: run ``apk update`` before installing packages
58
+ + upgrade: run ``apk upgrade`` before installing packages
59
+
60
+ Versions:
61
+ Package versions can be pinned like apk: ``<pkg>=<version>``.
62
+
63
+ **Examples:**
64
+
65
+ .. code:: python
66
+
67
+ from pyinfra.operations import apk
68
+ # Update package list and install packages
69
+ apk.packages(
70
+ name="Install Asterisk and Vim",
71
+ packages=["asterisk", "vim"],
72
+ update=True,
73
+ )
74
+
75
+ # Install the latest versions of packages (always check)
76
+ apk.packages(
77
+ name="Install latest Vim",
78
+ packages=["vim"],
79
+ latest=True,
80
+ )
81
+ """
82
+
83
+ if update:
84
+ yield from _update()
85
+
86
+ if upgrade:
87
+ yield from _upgrade()
88
+
89
+ yield from ensure_packages(
90
+ host,
91
+ packages,
92
+ host.get_fact(ApkPackages),
93
+ present,
94
+ install_command="apk add",
95
+ uninstall_command="apk del",
96
+ upgrade_command="apk upgrade",
97
+ version_join="=",
98
+ latest=latest,
99
+ )