pyinfra 0.11.dev3__py3-none-any.whl → 3.5.1__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 (203) hide show
  1. pyinfra/__init__.py +9 -12
  2. pyinfra/__main__.py +4 -0
  3. pyinfra/api/__init__.py +18 -3
  4. pyinfra/api/arguments.py +406 -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 +67 -18
  12. pyinfra/api/facts.py +253 -202
  13. pyinfra/api/host.py +413 -50
  14. pyinfra/api/inventory.py +121 -160
  15. pyinfra/api/operation.py +432 -262
  16. pyinfra/api/operations.py +273 -260
  17. pyinfra/api/state.py +302 -248
  18. pyinfra/api/util.py +291 -368
  19. pyinfra/connectors/base.py +173 -0
  20. pyinfra/connectors/chroot.py +212 -0
  21. pyinfra/connectors/docker.py +381 -0
  22. pyinfra/connectors/dockerssh.py +297 -0
  23. pyinfra/connectors/local.py +238 -0
  24. pyinfra/connectors/scp/__init__.py +1 -0
  25. pyinfra/connectors/scp/client.py +204 -0
  26. pyinfra/connectors/ssh.py +670 -0
  27. pyinfra/connectors/ssh_util.py +114 -0
  28. pyinfra/connectors/sshuserclient/client.py +309 -0
  29. pyinfra/connectors/sshuserclient/config.py +102 -0
  30. pyinfra/connectors/terraform.py +135 -0
  31. pyinfra/connectors/util.py +410 -0
  32. pyinfra/connectors/vagrant.py +183 -0
  33. pyinfra/context.py +145 -0
  34. pyinfra/facts/__init__.py +7 -6
  35. pyinfra/facts/apk.py +22 -7
  36. pyinfra/facts/apt.py +117 -60
  37. pyinfra/facts/brew.py +100 -15
  38. pyinfra/facts/bsdinit.py +23 -0
  39. pyinfra/facts/cargo.py +37 -0
  40. pyinfra/facts/choco.py +47 -0
  41. pyinfra/facts/crontab.py +195 -0
  42. pyinfra/facts/deb.py +94 -0
  43. pyinfra/facts/dnf.py +48 -0
  44. pyinfra/facts/docker.py +96 -23
  45. pyinfra/facts/efibootmgr.py +113 -0
  46. pyinfra/facts/files.py +630 -58
  47. pyinfra/facts/flatpak.py +77 -0
  48. pyinfra/facts/freebsd.py +70 -0
  49. pyinfra/facts/gem.py +19 -6
  50. pyinfra/facts/git.py +59 -14
  51. pyinfra/facts/gpg.py +150 -0
  52. pyinfra/facts/hardware.py +313 -167
  53. pyinfra/facts/iptables.py +72 -62
  54. pyinfra/facts/launchd.py +44 -0
  55. pyinfra/facts/lxd.py +17 -4
  56. pyinfra/facts/mysql.py +122 -86
  57. pyinfra/facts/npm.py +17 -9
  58. pyinfra/facts/openrc.py +71 -0
  59. pyinfra/facts/opkg.py +246 -0
  60. pyinfra/facts/pacman.py +50 -7
  61. pyinfra/facts/pip.py +24 -7
  62. pyinfra/facts/pipx.py +82 -0
  63. pyinfra/facts/pkg.py +15 -6
  64. pyinfra/facts/pkgin.py +35 -0
  65. pyinfra/facts/podman.py +54 -0
  66. pyinfra/facts/postgres.py +178 -0
  67. pyinfra/facts/postgresql.py +6 -147
  68. pyinfra/facts/rpm.py +105 -0
  69. pyinfra/facts/runit.py +77 -0
  70. pyinfra/facts/selinux.py +161 -0
  71. pyinfra/facts/server.py +746 -285
  72. pyinfra/facts/snap.py +88 -0
  73. pyinfra/facts/systemd.py +139 -0
  74. pyinfra/facts/sysvinit.py +59 -0
  75. pyinfra/facts/upstart.py +35 -0
  76. pyinfra/facts/util/__init__.py +17 -0
  77. pyinfra/facts/util/databases.py +4 -6
  78. pyinfra/facts/util/packaging.py +37 -6
  79. pyinfra/facts/util/units.py +30 -0
  80. pyinfra/facts/util/win_files.py +99 -0
  81. pyinfra/facts/vzctl.py +20 -13
  82. pyinfra/facts/xbps.py +35 -0
  83. pyinfra/facts/yum.py +34 -40
  84. pyinfra/facts/zfs.py +77 -0
  85. pyinfra/facts/zypper.py +42 -0
  86. pyinfra/local.py +45 -83
  87. pyinfra/operations/__init__.py +12 -0
  88. pyinfra/operations/apk.py +98 -0
  89. pyinfra/operations/apt.py +488 -0
  90. pyinfra/operations/brew.py +231 -0
  91. pyinfra/operations/bsdinit.py +59 -0
  92. pyinfra/operations/cargo.py +45 -0
  93. pyinfra/operations/choco.py +61 -0
  94. pyinfra/operations/crontab.py +191 -0
  95. pyinfra/operations/dnf.py +210 -0
  96. pyinfra/operations/docker.py +446 -0
  97. pyinfra/operations/files.py +1939 -0
  98. pyinfra/operations/flatpak.py +94 -0
  99. pyinfra/operations/freebsd/__init__.py +12 -0
  100. pyinfra/operations/freebsd/freebsd_update.py +70 -0
  101. pyinfra/operations/freebsd/pkg.py +219 -0
  102. pyinfra/operations/freebsd/service.py +116 -0
  103. pyinfra/operations/freebsd/sysrc.py +92 -0
  104. pyinfra/operations/gem.py +47 -0
  105. pyinfra/operations/git.py +419 -0
  106. pyinfra/operations/iptables.py +311 -0
  107. pyinfra/operations/launchd.py +45 -0
  108. pyinfra/operations/lxd.py +68 -0
  109. pyinfra/operations/mysql.py +609 -0
  110. pyinfra/operations/npm.py +57 -0
  111. pyinfra/operations/openrc.py +63 -0
  112. pyinfra/operations/opkg.py +88 -0
  113. pyinfra/operations/pacman.py +81 -0
  114. pyinfra/operations/pip.py +205 -0
  115. pyinfra/operations/pipx.py +102 -0
  116. pyinfra/operations/pkg.py +70 -0
  117. pyinfra/operations/pkgin.py +91 -0
  118. pyinfra/operations/postgres.py +436 -0
  119. pyinfra/operations/postgresql.py +30 -0
  120. pyinfra/operations/puppet.py +40 -0
  121. pyinfra/operations/python.py +72 -0
  122. pyinfra/operations/runit.py +184 -0
  123. pyinfra/operations/selinux.py +189 -0
  124. pyinfra/operations/server.py +1099 -0
  125. pyinfra/operations/snap.py +117 -0
  126. pyinfra/operations/ssh.py +216 -0
  127. pyinfra/operations/systemd.py +149 -0
  128. pyinfra/operations/sysvinit.py +141 -0
  129. pyinfra/operations/upstart.py +68 -0
  130. pyinfra/operations/util/__init__.py +12 -0
  131. pyinfra/operations/util/docker.py +251 -0
  132. pyinfra/operations/util/files.py +247 -0
  133. pyinfra/operations/util/packaging.py +336 -0
  134. pyinfra/operations/util/service.py +46 -0
  135. pyinfra/operations/vzctl.py +137 -0
  136. pyinfra/operations/xbps.py +77 -0
  137. pyinfra/operations/yum.py +210 -0
  138. pyinfra/operations/zfs.py +175 -0
  139. pyinfra/operations/zypper.py +192 -0
  140. pyinfra/progress.py +44 -32
  141. pyinfra/py.typed +0 -0
  142. pyinfra/version.py +9 -1
  143. pyinfra-3.5.1.dist-info/METADATA +141 -0
  144. pyinfra-3.5.1.dist-info/RECORD +159 -0
  145. {pyinfra-0.11.dev3.dist-info → pyinfra-3.5.1.dist-info}/WHEEL +1 -2
  146. pyinfra-3.5.1.dist-info/entry_points.txt +12 -0
  147. {pyinfra-0.11.dev3.dist-info → pyinfra-3.5.1.dist-info/licenses}/LICENSE.md +1 -1
  148. pyinfra_cli/__init__.py +1 -0
  149. pyinfra_cli/cli.py +780 -0
  150. pyinfra_cli/commands.py +66 -0
  151. pyinfra_cli/exceptions.py +155 -65
  152. pyinfra_cli/inventory.py +233 -89
  153. pyinfra_cli/log.py +39 -43
  154. pyinfra_cli/main.py +26 -495
  155. pyinfra_cli/prints.py +215 -156
  156. pyinfra_cli/util.py +172 -105
  157. pyinfra_cli/virtualenv.py +25 -20
  158. pyinfra/api/connectors/__init__.py +0 -21
  159. pyinfra/api/connectors/ansible.py +0 -99
  160. pyinfra/api/connectors/docker.py +0 -178
  161. pyinfra/api/connectors/local.py +0 -169
  162. pyinfra/api/connectors/ssh.py +0 -402
  163. pyinfra/api/connectors/sshuserclient/client.py +0 -105
  164. pyinfra/api/connectors/sshuserclient/config.py +0 -90
  165. pyinfra/api/connectors/util.py +0 -63
  166. pyinfra/api/connectors/vagrant.py +0 -155
  167. pyinfra/facts/init.py +0 -176
  168. pyinfra/facts/util/files.py +0 -102
  169. pyinfra/hook.py +0 -41
  170. pyinfra/modules/__init__.py +0 -11
  171. pyinfra/modules/apk.py +0 -64
  172. pyinfra/modules/apt.py +0 -272
  173. pyinfra/modules/brew.py +0 -122
  174. pyinfra/modules/files.py +0 -711
  175. pyinfra/modules/gem.py +0 -30
  176. pyinfra/modules/git.py +0 -115
  177. pyinfra/modules/init.py +0 -344
  178. pyinfra/modules/iptables.py +0 -271
  179. pyinfra/modules/lxd.py +0 -45
  180. pyinfra/modules/mysql.py +0 -347
  181. pyinfra/modules/npm.py +0 -47
  182. pyinfra/modules/pacman.py +0 -60
  183. pyinfra/modules/pip.py +0 -99
  184. pyinfra/modules/pkg.py +0 -43
  185. pyinfra/modules/postgresql.py +0 -245
  186. pyinfra/modules/puppet.py +0 -20
  187. pyinfra/modules/python.py +0 -37
  188. pyinfra/modules/server.py +0 -524
  189. pyinfra/modules/ssh.py +0 -150
  190. pyinfra/modules/util/files.py +0 -52
  191. pyinfra/modules/util/packaging.py +0 -118
  192. pyinfra/modules/vzctl.py +0 -133
  193. pyinfra/modules/yum.py +0 -171
  194. pyinfra/pseudo_modules.py +0 -64
  195. pyinfra-0.11.dev3.dist-info/.DS_Store +0 -0
  196. pyinfra-0.11.dev3.dist-info/METADATA +0 -135
  197. pyinfra-0.11.dev3.dist-info/RECORD +0 -95
  198. pyinfra-0.11.dev3.dist-info/entry_points.txt +0 -3
  199. pyinfra-0.11.dev3.dist-info/top_level.txt +0 -2
  200. pyinfra_cli/__main__.py +0 -40
  201. pyinfra_cli/config.py +0 -92
  202. /pyinfra/{modules/util → connectors}/__init__.py +0 -0
  203. /pyinfra/{api/connectors → connectors}/sshuserclient/__init__.py +0 -0
@@ -0,0 +1,66 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+
5
+ from pyinfra.api.facts import FactBase
6
+
7
+ from .exceptions import CliError
8
+ from .util import parse_cli_arg, try_import_module_attribute
9
+
10
+
11
+ def get_func_and_args(commands):
12
+ operation_name = commands[0]
13
+
14
+ op = try_import_module_attribute(operation_name, prefix="pyinfra.operations")
15
+
16
+ # Parse the arguments
17
+ operation_args = commands[1:]
18
+
19
+ if len(operation_args) == 1:
20
+ # Check if we're JSON (in which case we expect a list of two items:
21
+ # a list of args and a dict of kwargs).
22
+ try:
23
+ args, kwargs = json.loads(operation_args[0])
24
+ return op, (args or (), kwargs or {})
25
+ except ValueError:
26
+ pass
27
+
28
+ args = [parse_cli_arg(arg) for arg in operation_args if "=" not in arg]
29
+
30
+ kwargs = {
31
+ key: parse_cli_arg(value)
32
+ for key, value in [arg.split("=", 1) for arg in operation_args if "=" in arg]
33
+ }
34
+
35
+ return op, (args, kwargs)
36
+
37
+
38
+ def get_facts_and_args(commands):
39
+ facts: list[tuple[FactBase, tuple, dict]] = []
40
+
41
+ current_fact = None
42
+
43
+ for command in commands:
44
+ if "=" in command:
45
+ if not current_fact:
46
+ raise CliError("Invalid fact commands: `{0}`".format(commands))
47
+
48
+ key, value = command.split("=", 1)
49
+ current_fact[2][key] = parse_cli_arg(value)
50
+ continue
51
+
52
+ if current_fact:
53
+ facts.append(current_fact)
54
+ current_fact = None
55
+
56
+ if "." not in command:
57
+ raise CliError(f"Invalid fact: `{command}`, should be in the format `module.cls`")
58
+
59
+ fact_cls = try_import_module_attribute(command, prefix="pyinfra.facts")
60
+ assert fact_cls is not None
61
+ current_fact = (fact_cls, (), {})
62
+
63
+ if current_fact:
64
+ facts.append(current_fact)
65
+
66
+ return facts
pyinfra_cli/exceptions.py CHANGED
@@ -1,78 +1,168 @@
1
+ import abc
1
2
  import sys
2
-
3
- from traceback import format_exception, format_tb
3
+ from inspect import getframeinfo
4
+ from traceback import format_exception, format_tb, walk_tb
5
+ from types import TracebackType
4
6
 
5
7
  import click
6
-
7
- from pyinfra import logger, pseudo_host, pseudo_state
8
- from pyinfra.api.exceptions import PyinfraError
9
- from pyinfra.hook import Error as HookError
10
-
11
-
12
- class CliError(PyinfraError, click.ClickException):
13
- def show(self):
14
- name = 'unknown error'
15
-
16
- if isinstance(self, HookError):
17
- name = 'hook error'
18
-
19
- elif isinstance(self, PyinfraError):
20
- name = 'pyinfra error'
21
-
22
- elif isinstance(self, IOError):
23
- name = 'local IO error'
24
-
25
- if pseudo_host.isset():
26
- # Get any operation meta + name
27
- op_name = None
28
- current_op_hash = pseudo_state.current_op_hash
29
- current_op_meta = pseudo_state.op_meta.get(current_op_hash)
30
- if current_op_meta:
31
- op_name = ', '.join(current_op_meta['names'])
32
-
33
- sys.stderr.write('--> {0}{1}{2}: '.format(
34
- pseudo_host.print_prefix,
35
- click.style(name, 'red', bold=True),
36
- ' (operation={0})'.format(op_name) if op_name else '',
37
- ))
38
- else:
39
- sys.stderr.write(
40
- '--> {0}: '.format(click.style(name, 'red', bold=True)),
41
- )
42
-
43
- logger.warning(self)
44
-
45
-
46
- class UnexpectedError(click.ClickException):
8
+ from typing_extensions import override
9
+
10
+ from pyinfra import logger
11
+ from pyinfra.api.exceptions import (
12
+ ArgumentTypeError,
13
+ ConnectorDataTypeError,
14
+ OperationError,
15
+ PyinfraError,
16
+ )
17
+ from pyinfra.api.util import PYINFRA_INSTALL_DIR
18
+
19
+
20
+ def get_frame_line_from_tb(tb: TracebackType):
21
+ frame_lines = list(walk_tb(tb))
22
+ frame_lines.reverse()
23
+ for frame, line in frame_lines:
24
+ info = getframeinfo(frame)
25
+ if info.filename.startswith(PYINFRA_INSTALL_DIR):
26
+ continue
27
+ return info
28
+
29
+
30
+ class WrappedError(click.ClickException):
31
+ def __init__(self, e: Exception):
32
+ self.traceback = e.__traceback__
33
+ self.exception = e
34
+
35
+ # Pull message from the wrapped exception
36
+ message = getattr(e, "message", e.args[0])
37
+ if not isinstance(message, str):
38
+ message = repr(message)
39
+ self.message = message
40
+
41
+ @override
42
+ def show(self, file=None):
43
+ name = "unknown error"
44
+
45
+ if isinstance(self.exception, ConnectorDataTypeError):
46
+ name = "Connector data type error"
47
+ elif isinstance(self.exception, ArgumentTypeError):
48
+ name = "Argument type error"
49
+ elif isinstance(self.exception, OperationError):
50
+ name = "Operation error"
51
+ elif isinstance(self.exception, PyinfraError):
52
+ name = "pyinfra error"
53
+ elif isinstance(self.exception, IOError):
54
+ name = "Local IO error"
55
+
56
+ if self.traceback:
57
+ info = get_frame_line_from_tb(self.traceback)
58
+ if info:
59
+ name = f"{name} in {info.filename} line {info.lineno}"
60
+
61
+ logger.warning(
62
+ "--> {0}: {1}".format(
63
+ click.style(name, "red", bold=True),
64
+ self,
65
+ ),
66
+ )
67
+
68
+
69
+ class CliError(click.ClickException):
70
+ @override
71
+ def show(self, file=None):
72
+ logger.warning(
73
+ "--> {0}: {1}".format(
74
+ click.style("pyinfra error", "red", bold=True),
75
+ self,
76
+ ),
77
+ )
78
+
79
+
80
+ class UnexpectedMixin(abc.ABC):
81
+ exception: Exception
82
+ traceback: TracebackType
83
+
84
+ def get_traceback_lines(self):
85
+ traceback = getattr(self.exception, "_traceback")
86
+ return format_tb(traceback)
87
+
88
+ def get_traceback(self):
89
+ return "".join(self.get_traceback_lines())
90
+
91
+ def get_exception(self):
92
+ return "".join(format_exception(self.exception.__class__, self.exception, None))
93
+
94
+
95
+ class UnexpectedExternalError(click.ClickException, UnexpectedMixin):
96
+ def __init__(self, e, filename):
97
+ _, _, traceback = sys.exc_info()
98
+ e._traceback = traceback
99
+ self.exception = e
100
+ self.filename = filename
101
+
102
+ @override
103
+ def show(self, file=None):
104
+ logger.warning(
105
+ "--> {0}:\n".format(
106
+ click.style(
107
+ "An exception occurred in: {0}".format(self.filename),
108
+ "red",
109
+ bold=True,
110
+ ),
111
+ ),
112
+ )
113
+
114
+ click.echo("Traceback (most recent call last):", err=True)
115
+ click.echo(self.get_traceback(), err=True, nl=False)
116
+ click.echo(self.get_exception(), err=True)
117
+
118
+
119
+ class UnexpectedInternalError(click.ClickException, UnexpectedMixin):
47
120
  def __init__(self, e):
48
- self.e = e
49
-
50
- def show(self):
51
- sys.stderr.write('--> {0}:\n'.format(click.style(
52
- 'An unexpected exception occurred',
53
- 'red',
54
- bold=True,
55
- )))
56
- print()
57
-
58
- traceback = getattr(self.e, '_traceback')
59
- traceback_lines = format_tb(traceback)
60
- traceback = ''.join(traceback_lines)
121
+ _, _, traceback = sys.exc_info()
122
+ e._traceback = traceback
123
+ self.exception = e
124
+
125
+ @override
126
+ def show(self, file=None):
127
+ click.echo(
128
+ "--> {0}:\n".format(
129
+ click.style(
130
+ "An internal exception occurred",
131
+ "red",
132
+ bold=True,
133
+ ),
134
+ ),
135
+ err=True,
136
+ )
137
+
138
+ traceback_lines = self.get_traceback_lines()
139
+ traceback = self.get_traceback()
61
140
 
62
141
  # Syntax errors contain the filename/line/etc, but other exceptions
63
142
  # don't, so print the *last* call to stderr.
64
- if not isinstance(self.e, SyntaxError):
143
+ if not isinstance(self.exception, SyntaxError):
65
144
  sys.stderr.write(traceback_lines[-1])
66
145
 
67
- exception = ''.join(format_exception(self.e.__class__, self.e, None))
68
- sys.stderr.write(exception)
146
+ exception = self.get_exception()
147
+ click.echo(exception, err=True)
69
148
 
70
- # Write the full trace + exception to pyinfra-debug.log
71
- with open('pyinfra-debug.log', 'w') as f:
149
+ with open("pyinfra-debug.log", "w", encoding="utf-8") as f:
72
150
  f.write(traceback)
73
151
  f.write(exception)
74
152
 
75
- print()
76
- print('--> The full traceback has been written to {0}'.format(
77
- click.style('pyinfra-debug.log', bold=True),
78
- ))
153
+ logger.debug(traceback)
154
+ logger.debug(exception)
155
+
156
+ click.echo(
157
+ "--> The full traceback has been written to {0}".format(
158
+ click.style("pyinfra-debug.log", bold=True),
159
+ ),
160
+ err=True,
161
+ )
162
+ click.echo(
163
+ (
164
+ "--> If this is unexpected please consider submitting a bug report "
165
+ "on GitHub, for more information run `pyinfra --support`."
166
+ ),
167
+ err=True,
168
+ )