pyinfra 2.9.1__py2.py3-none-any.whl → 3.0__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.
- pyinfra/api/__init__.py +3 -0
- pyinfra/api/arguments.py +265 -253
- pyinfra/api/arguments_typed.py +80 -0
- pyinfra/api/command.py +68 -53
- pyinfra/api/config.py +139 -32
- pyinfra/api/connect.py +1 -1
- pyinfra/api/connectors.py +7 -26
- pyinfra/api/deploy.py +21 -52
- pyinfra/api/exceptions.py +33 -8
- pyinfra/api/facts.py +102 -137
- pyinfra/api/host.py +150 -82
- pyinfra/api/inventory.py +21 -25
- pyinfra/api/operation.py +240 -198
- pyinfra/api/operations.py +102 -148
- pyinfra/api/state.py +137 -79
- pyinfra/api/util.py +79 -86
- pyinfra/connectors/base.py +147 -0
- pyinfra/connectors/chroot.py +160 -169
- pyinfra/connectors/docker.py +220 -237
- pyinfra/connectors/dockerssh.py +231 -253
- pyinfra/connectors/local.py +196 -208
- pyinfra/connectors/ssh.py +530 -613
- pyinfra/connectors/ssh_util.py +114 -0
- pyinfra/connectors/sshuserclient/client.py +5 -3
- pyinfra/connectors/terraform.py +86 -65
- pyinfra/connectors/util.py +211 -137
- pyinfra/connectors/vagrant.py +60 -53
- pyinfra/context.py +4 -2
- pyinfra/facts/apk.py +2 -0
- pyinfra/facts/apt.py +2 -0
- pyinfra/facts/brew.py +2 -0
- pyinfra/facts/bsdinit.py +2 -0
- pyinfra/facts/cargo.py +2 -0
- pyinfra/facts/choco.py +2 -0
- pyinfra/facts/deb.py +7 -2
- pyinfra/facts/dnf.py +2 -0
- pyinfra/facts/docker.py +19 -0
- pyinfra/facts/files.py +47 -32
- pyinfra/facts/gem.py +2 -0
- pyinfra/facts/git.py +3 -1
- pyinfra/facts/gpg.py +3 -1
- pyinfra/facts/hardware.py +34 -24
- pyinfra/facts/iptables.py +5 -3
- pyinfra/facts/launchd.py +2 -0
- pyinfra/facts/lxd.py +2 -0
- pyinfra/facts/mysql.py +13 -6
- pyinfra/facts/npm.py +1 -0
- pyinfra/facts/openrc.py +2 -0
- pyinfra/facts/pacman.py +6 -2
- pyinfra/facts/pip.py +2 -0
- pyinfra/facts/pkg.py +2 -0
- pyinfra/facts/pkgin.py +2 -0
- pyinfra/facts/postgres.py +168 -0
- pyinfra/facts/postgresql.py +6 -160
- pyinfra/facts/rpm.py +12 -9
- pyinfra/facts/runit.py +68 -0
- pyinfra/facts/selinux.py +3 -1
- pyinfra/facts/server.py +80 -36
- pyinfra/facts/snap.py +2 -0
- pyinfra/facts/systemd.py +31 -12
- pyinfra/facts/sysvinit.py +10 -10
- pyinfra/facts/upstart.py +2 -0
- pyinfra/facts/util/packaging.py +7 -4
- pyinfra/facts/vzctl.py +2 -0
- pyinfra/facts/xbps.py +2 -0
- pyinfra/facts/yum.py +2 -0
- pyinfra/facts/zypper.py +2 -0
- pyinfra/local.py +4 -5
- pyinfra/operations/apk.py +6 -4
- pyinfra/operations/apt.py +46 -65
- pyinfra/operations/brew.py +17 -22
- pyinfra/operations/bsdinit.py +9 -7
- pyinfra/operations/cargo.py +4 -2
- pyinfra/operations/choco.py +4 -2
- pyinfra/operations/dnf.py +19 -23
- pyinfra/operations/docker.py +339 -0
- pyinfra/operations/files.py +188 -386
- pyinfra/operations/gem.py +4 -2
- pyinfra/operations/git.py +24 -53
- pyinfra/operations/iptables.py +29 -35
- pyinfra/operations/launchd.py +6 -7
- pyinfra/operations/lxd.py +8 -13
- pyinfra/operations/mysql.py +62 -81
- pyinfra/operations/npm.py +9 -2
- pyinfra/operations/openrc.py +6 -4
- pyinfra/operations/pacman.py +7 -8
- pyinfra/operations/pip.py +25 -24
- pyinfra/operations/pkg.py +4 -2
- pyinfra/operations/pkgin.py +6 -4
- pyinfra/operations/postgres.py +349 -0
- pyinfra/operations/postgresql.py +18 -379
- pyinfra/operations/puppet.py +3 -1
- pyinfra/operations/python.py +8 -19
- pyinfra/operations/runit.py +182 -0
- pyinfra/operations/selinux.py +47 -44
- pyinfra/operations/server.py +111 -127
- pyinfra/operations/snap.py +4 -4
- pyinfra/operations/ssh.py +20 -33
- pyinfra/operations/systemd.py +19 -15
- pyinfra/operations/sysvinit.py +9 -16
- pyinfra/operations/upstart.py +9 -7
- pyinfra/operations/util/__init__.py +12 -0
- pyinfra/operations/util/docker.py +177 -0
- pyinfra/operations/util/files.py +24 -16
- pyinfra/operations/util/packaging.py +55 -57
- pyinfra/operations/util/service.py +39 -51
- pyinfra/operations/vzctl.py +12 -10
- pyinfra/operations/xbps.py +6 -4
- pyinfra/operations/yum.py +18 -22
- pyinfra/operations/zypper.py +12 -13
- pyinfra/version.py +5 -2
- {pyinfra-2.9.1.dist-info → pyinfra-3.0.dist-info}/METADATA +40 -41
- pyinfra-3.0.dist-info/RECORD +167 -0
- {pyinfra-2.9.1.dist-info → pyinfra-3.0.dist-info}/WHEEL +1 -1
- pyinfra-3.0.dist-info/entry_points.txt +11 -0
- pyinfra_cli/__main__.py +4 -3
- pyinfra_cli/commands.py +7 -2
- pyinfra_cli/exceptions.py +78 -42
- pyinfra_cli/inventory.py +40 -6
- pyinfra_cli/log.py +17 -3
- pyinfra_cli/main.py +133 -90
- pyinfra_cli/prints.py +95 -127
- pyinfra_cli/util.py +62 -29
- tests/test_api/test_api.py +2 -0
- tests/test_api/test_api_arguments.py +13 -13
- tests/test_api/test_api_deploys.py +28 -29
- tests/test_api/test_api_facts.py +60 -98
- tests/test_api/test_api_operations.py +101 -201
- tests/test_cli/test_cli.py +18 -49
- tests/test_cli/test_cli_deploy.py +11 -37
- tests/test_cli/test_cli_exceptions.py +50 -19
- tests/test_cli/util.py +1 -1
- tests/test_connectors/test_chroot.py +6 -6
- tests/test_connectors/test_docker.py +4 -4
- tests/test_connectors/test_dockerssh.py +38 -50
- tests/test_connectors/test_local.py +11 -12
- tests/test_connectors/test_ssh.py +105 -93
- tests/test_connectors/test_terraform.py +9 -15
- tests/test_connectors/test_util.py +24 -46
- tests/test_connectors/test_vagrant.py +7 -7
- pyinfra/api/operation.pyi +0 -117
- pyinfra/connectors/ansible.py +0 -171
- pyinfra/connectors/mech.py +0 -186
- pyinfra/connectors/pyinfrawinrmsession/__init__.py +0 -28
- pyinfra/connectors/winrm.py +0 -320
- pyinfra/facts/windows.py +0 -366
- pyinfra/facts/windows_files.py +0 -90
- pyinfra/operations/windows.py +0 -59
- pyinfra/operations/windows_files.py +0 -551
- pyinfra-2.9.1.dist-info/RECORD +0 -170
- pyinfra-2.9.1.dist-info/entry_points.txt +0 -14
- tests/test_connectors/test_ansible.py +0 -64
- tests/test_connectors/test_mech.py +0 -126
- tests/test_connectors/test_winrm.py +0 -76
- {pyinfra-2.9.1.dist-info → pyinfra-3.0.dist-info}/LICENSE.md +0 -0
- {pyinfra-2.9.1.dist-info → pyinfra-3.0.dist-info}/top_level.txt +0 -0
pyinfra/facts/systemd.py
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import re
|
|
4
|
+
from typing import Dict, Iterable
|
|
2
5
|
|
|
3
|
-
from pyinfra.api import FactBase
|
|
6
|
+
from pyinfra.api import FactBase, FactTypeError, QuoteString, StringCommand
|
|
4
7
|
|
|
5
8
|
# Valid unit names consist of a "name prefix" and a dot and a suffix specifying the unit type.
|
|
6
9
|
# The "unit prefix" must consist of one or more valid characters
|
|
@@ -21,21 +24,19 @@ SYSTEMD_UNIT_NAME_REGEX = (
|
|
|
21
24
|
|
|
22
25
|
def _make_systemctl_cmd(user_mode=False, machine=None, user_name=None):
|
|
23
26
|
# base command for normal and user mode
|
|
24
|
-
systemctl_cmd = "systemctl --user" if user_mode else "systemctl"
|
|
27
|
+
systemctl_cmd = ["systemctl --user"] if user_mode else ["systemctl"]
|
|
25
28
|
|
|
26
29
|
# add user and machine flag if given in args
|
|
27
30
|
if machine is not None:
|
|
28
31
|
if user_name is not None:
|
|
29
|
-
|
|
32
|
+
systemctl_cmd.append("--machine={1}@{0}".format(machine, user_name))
|
|
30
33
|
else:
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
systemctl_cmd = "{0} {1}".format(systemctl_cmd, machine_opt)
|
|
34
|
+
systemctl_cmd.append("--machine={0}".format(machine))
|
|
34
35
|
|
|
35
|
-
return systemctl_cmd
|
|
36
|
+
return StringCommand(*systemctl_cmd)
|
|
36
37
|
|
|
37
38
|
|
|
38
|
-
class SystemdStatus(FactBase):
|
|
39
|
+
class SystemdStatus(FactBase[Dict[str, bool]]):
|
|
39
40
|
"""
|
|
40
41
|
Returns a dictionary map of systemd units to booleans indicating whether they are active.
|
|
41
42
|
|
|
@@ -58,17 +59,35 @@ class SystemdStatus(FactBase):
|
|
|
58
59
|
state_key = "SubState"
|
|
59
60
|
state_values = ["running", "waiting", "exited"]
|
|
60
61
|
|
|
61
|
-
def command(self, user_mode=False, machine=None, user_name=None):
|
|
62
|
+
def command(self, user_mode=False, machine=None, user_name=None, services=None):
|
|
62
63
|
fact_cmd = _make_systemctl_cmd(
|
|
63
64
|
user_mode=user_mode,
|
|
64
65
|
machine=machine,
|
|
65
66
|
user_name=user_name,
|
|
66
67
|
)
|
|
67
68
|
|
|
68
|
-
|
|
69
|
+
if services is None:
|
|
70
|
+
service_strs = [QuoteString("*")]
|
|
71
|
+
elif isinstance(services, str):
|
|
72
|
+
service_strs = [QuoteString(services)]
|
|
73
|
+
elif isinstance(services, Iterable):
|
|
74
|
+
service_strs = [QuoteString(s) for s in services]
|
|
75
|
+
else:
|
|
76
|
+
raise FactTypeError(f"Invalid type passed for services argument: {type(services)}")
|
|
77
|
+
|
|
78
|
+
return StringCommand(
|
|
79
|
+
fact_cmd,
|
|
80
|
+
"show",
|
|
81
|
+
"--all",
|
|
82
|
+
"--property",
|
|
83
|
+
"Id",
|
|
84
|
+
"--property",
|
|
85
|
+
self.state_key,
|
|
86
|
+
*service_strs,
|
|
87
|
+
)
|
|
69
88
|
|
|
70
|
-
def process(self, output):
|
|
71
|
-
services = {}
|
|
89
|
+
def process(self, output) -> Dict[str, bool]:
|
|
90
|
+
services: Dict[str, bool] = {}
|
|
72
91
|
|
|
73
92
|
current_unit = None
|
|
74
93
|
for line in output:
|
pyinfra/facts/sysvinit.py
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import re
|
|
4
|
+
from typing import Optional
|
|
2
5
|
|
|
3
6
|
from pyinfra.api import FactBase
|
|
4
7
|
|
|
@@ -6,7 +9,7 @@ from pyinfra.api import FactBase
|
|
|
6
9
|
class InitdStatus(FactBase):
|
|
7
10
|
"""
|
|
8
11
|
Low level check for every /etc/init.d/* script. Unfortunately many of these
|
|
9
|
-
|
|
12
|
+
misbehave and return exit status 0 while also displaying the help info/not
|
|
10
13
|
offering status support.
|
|
11
14
|
|
|
12
15
|
Returns a dict of name -> status.
|
|
@@ -29,26 +32,23 @@ class InitdStatus(FactBase):
|
|
|
29
32
|
regex = r"([a-zA-Z0-9\-]+)=([0-9]+)"
|
|
30
33
|
default = dict
|
|
31
34
|
|
|
32
|
-
def process(self, output):
|
|
33
|
-
services = {}
|
|
35
|
+
def process(self, output) -> dict[str, Optional[bool]]:
|
|
36
|
+
services: dict[str, Optional[bool]] = {}
|
|
34
37
|
|
|
35
38
|
for line in output:
|
|
36
39
|
matches = re.match(self.regex, line)
|
|
37
40
|
if matches:
|
|
38
|
-
|
|
41
|
+
intstatus = int(matches.group(2))
|
|
42
|
+
status: Optional[bool] = None
|
|
39
43
|
|
|
40
44
|
# Exit code 0 = OK/running
|
|
41
|
-
if
|
|
45
|
+
if intstatus == 0:
|
|
42
46
|
status = True
|
|
43
47
|
|
|
44
48
|
# Exit codes 1-3 = DOWN/not running
|
|
45
|
-
elif
|
|
49
|
+
elif intstatus < 4:
|
|
46
50
|
status = False
|
|
47
51
|
|
|
48
|
-
# Exit codes 4+ = unknown
|
|
49
|
-
else:
|
|
50
|
-
status = None
|
|
51
|
-
|
|
52
52
|
services[matches.group(1)] = status
|
|
53
53
|
|
|
54
54
|
return services
|
pyinfra/facts/upstart.py
CHANGED
pyinfra/facts/util/packaging.py
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import re
|
|
4
|
+
from typing import Iterable
|
|
2
5
|
|
|
3
6
|
|
|
4
|
-
def parse_packages(regex, output):
|
|
5
|
-
packages = {}
|
|
7
|
+
def parse_packages(regex: str, output: Iterable[str]) -> dict[str, set[str]]:
|
|
8
|
+
packages: dict[str, set[str]] = {}
|
|
6
9
|
|
|
7
10
|
for line in output:
|
|
8
11
|
matches = re.match(regex, line)
|
|
@@ -18,7 +21,7 @@ def parse_packages(regex, output):
|
|
|
18
21
|
def _parse_yum_or_zypper_repositories(output):
|
|
19
22
|
repos = []
|
|
20
23
|
|
|
21
|
-
current_repo = {}
|
|
24
|
+
current_repo: dict[str, str] = {}
|
|
22
25
|
for line in output:
|
|
23
26
|
line = line.strip()
|
|
24
27
|
if not line or line.startswith("#"):
|
|
@@ -32,7 +35,7 @@ def _parse_yum_or_zypper_repositories(output):
|
|
|
32
35
|
current_repo["name"] = line[1:-1]
|
|
33
36
|
|
|
34
37
|
if current_repo and "=" in line:
|
|
35
|
-
key, value =
|
|
38
|
+
key, value = re.split(r"\s*=\s*", line, maxsplit=1)
|
|
36
39
|
current_repo[key] = value
|
|
37
40
|
|
|
38
41
|
if current_repo:
|
pyinfra/facts/vzctl.py
CHANGED
pyinfra/facts/xbps.py
CHANGED
pyinfra/facts/yum.py
CHANGED
pyinfra/facts/zypper.py
CHANGED
pyinfra/local.py
CHANGED
|
@@ -6,7 +6,7 @@ import pyinfra
|
|
|
6
6
|
from pyinfra import config, host, logger, state
|
|
7
7
|
from pyinfra.api.exceptions import PyinfraError
|
|
8
8
|
from pyinfra.api.util import get_file_path
|
|
9
|
-
from pyinfra.connectors.util import run_local_process
|
|
9
|
+
from pyinfra.connectors.util import run_local_process
|
|
10
10
|
from pyinfra.context import ctx_state
|
|
11
11
|
|
|
12
12
|
|
|
@@ -76,19 +76,18 @@ def shell(
|
|
|
76
76
|
if print_input:
|
|
77
77
|
click.echo("{0}>>> {1}".format(print_prefix, command), err=True)
|
|
78
78
|
|
|
79
|
-
return_code,
|
|
79
|
+
return_code, output = run_local_process(
|
|
80
80
|
command,
|
|
81
81
|
print_output=print_output,
|
|
82
82
|
print_prefix=print_prefix,
|
|
83
83
|
)
|
|
84
|
-
stdout, stderr = split_combined_output(combined_output)
|
|
85
84
|
|
|
86
85
|
if return_code > 0 and not ignore_errors:
|
|
87
86
|
raise PyinfraError(
|
|
88
|
-
"Local command failed: {0}\n{1}".format(command, stderr),
|
|
87
|
+
"Local command failed: {0}\n{1}".format(command, output.stderr),
|
|
89
88
|
)
|
|
90
89
|
|
|
91
|
-
all_stdout.extend(
|
|
90
|
+
all_stdout.extend(output.stdout_lines)
|
|
92
91
|
|
|
93
92
|
if not splitlines:
|
|
94
93
|
return "\n".join(all_stdout)
|
pyinfra/operations/apk.py
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
Manage apk packages.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
5
7
|
from pyinfra import host
|
|
6
8
|
from pyinfra.api import operation
|
|
7
9
|
from pyinfra.facts.apk import ApkPackages
|
|
@@ -23,7 +25,7 @@ def upgrade(available: bool = False):
|
|
|
23
25
|
yield "apk upgrade"
|
|
24
26
|
|
|
25
27
|
|
|
26
|
-
_upgrade = upgrade # noqa: E305
|
|
28
|
+
_upgrade = upgrade._inner # noqa: E305
|
|
27
29
|
|
|
28
30
|
|
|
29
31
|
@operation(is_idempotent=False)
|
|
@@ -35,12 +37,12 @@ def update():
|
|
|
35
37
|
yield "apk update"
|
|
36
38
|
|
|
37
39
|
|
|
38
|
-
_update = update # noqa: E305
|
|
40
|
+
_update = update._inner # noqa: E305
|
|
39
41
|
|
|
40
42
|
|
|
41
|
-
@operation
|
|
43
|
+
@operation()
|
|
42
44
|
def packages(
|
|
43
|
-
packages=None,
|
|
45
|
+
packages: str | list[str] | None = None,
|
|
44
46
|
present=True,
|
|
45
47
|
latest=False,
|
|
46
48
|
update=False,
|
pyinfra/operations/apt.py
CHANGED
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
Manage apt packages and repositories.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
from
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from datetime import timedelta
|
|
6
8
|
from urllib.parse import urlparse
|
|
7
9
|
|
|
8
|
-
from pyinfra import host
|
|
10
|
+
from pyinfra import host
|
|
9
11
|
from pyinfra.api import OperationError, operation
|
|
10
12
|
from pyinfra.facts.apt import AptKeys, AptSources, parse_apt_repo
|
|
11
13
|
from pyinfra.facts.deb import DebPackage, DebPackages
|
|
@@ -19,7 +21,7 @@ from .util.packaging import ensure_packages
|
|
|
19
21
|
APT_UPDATE_FILENAME = "/var/lib/apt/periodic/update-success-stamp"
|
|
20
22
|
|
|
21
23
|
|
|
22
|
-
def noninteractive_apt(command, force=False):
|
|
24
|
+
def noninteractive_apt(command: str, force=False):
|
|
23
25
|
args = ["DEBIAN_FRONTEND=noninteractive apt-get -y"]
|
|
24
26
|
|
|
25
27
|
if force:
|
|
@@ -36,8 +38,8 @@ def noninteractive_apt(command, force=False):
|
|
|
36
38
|
return " ".join(args)
|
|
37
39
|
|
|
38
40
|
|
|
39
|
-
@operation
|
|
40
|
-
def key(src=None, keyserver=None, keyid=None):
|
|
41
|
+
@operation()
|
|
42
|
+
def key(src: str | None = None, keyserver: str | None = None, keyid: str | list[str] | None = None):
|
|
41
43
|
"""
|
|
42
44
|
Add apt gpg keys with ``apt-key``.
|
|
43
45
|
|
|
@@ -48,6 +50,11 @@ def key(src=None, keyserver=None, keyid=None):
|
|
|
48
50
|
keyserver/id:
|
|
49
51
|
These must be provided together.
|
|
50
52
|
|
|
53
|
+
.. warning::
|
|
54
|
+
``apt-key`` is deprecated in Debian, it is recommended NOT to use this
|
|
55
|
+
operation and instead follow the instructions here:
|
|
56
|
+
https://wiki.debian.org/DebianRepository/UseThirdParty
|
|
57
|
+
|
|
51
58
|
**Examples:**
|
|
52
59
|
|
|
53
60
|
.. code:: python
|
|
@@ -78,10 +85,6 @@ def key(src=None, keyserver=None, keyid=None):
|
|
|
78
85
|
yield "(wget -O - {0} || curl -sSLf {0}) | apt-key add -".format(src)
|
|
79
86
|
else:
|
|
80
87
|
yield "apt-key add {0}".format(src)
|
|
81
|
-
|
|
82
|
-
if keyid:
|
|
83
|
-
for kid in keyid:
|
|
84
|
-
existing_keys[kid] = {}
|
|
85
88
|
else:
|
|
86
89
|
host.noop("All keys from {0} are already available in the apt keychain".format(src))
|
|
87
90
|
|
|
@@ -98,8 +101,6 @@ def key(src=None, keyserver=None, keyid=None):
|
|
|
98
101
|
keyserver,
|
|
99
102
|
" ".join(needed_keys),
|
|
100
103
|
)
|
|
101
|
-
for kid in keyid:
|
|
102
|
-
existing_keys[kid] = {}
|
|
103
104
|
else:
|
|
104
105
|
host.noop(
|
|
105
106
|
"Keys {0} are already available in the apt keychain".format(
|
|
@@ -108,8 +109,8 @@ def key(src=None, keyserver=None, keyid=None):
|
|
|
108
109
|
)
|
|
109
110
|
|
|
110
111
|
|
|
111
|
-
@operation
|
|
112
|
-
def repo(src, present=True, filename=None):
|
|
112
|
+
@operation()
|
|
113
|
+
def repo(src: str, present=True, filename: str | None = None):
|
|
113
114
|
"""
|
|
114
115
|
Add/remove apt repositories.
|
|
115
116
|
|
|
@@ -144,24 +145,20 @@ def repo(src, present=True, filename=None):
|
|
|
144
145
|
|
|
145
146
|
# Doesn't exist and we want it
|
|
146
147
|
if not is_present and present:
|
|
147
|
-
yield from files.line(
|
|
148
|
-
filename,
|
|
149
|
-
src,
|
|
148
|
+
yield from files.line._inner(
|
|
149
|
+
path=filename,
|
|
150
|
+
line=src,
|
|
150
151
|
escape_regex_characters=True,
|
|
151
152
|
)
|
|
152
|
-
apt_sources.append(repo)
|
|
153
153
|
|
|
154
154
|
# Exists and we don't want it
|
|
155
155
|
elif is_present and not present:
|
|
156
|
-
yield from files.line(
|
|
157
|
-
filename,
|
|
158
|
-
src,
|
|
156
|
+
yield from files.line._inner(
|
|
157
|
+
path=filename,
|
|
158
|
+
line=src,
|
|
159
159
|
present=False,
|
|
160
|
-
assume_present=True,
|
|
161
160
|
escape_regex_characters=True,
|
|
162
161
|
)
|
|
163
|
-
apt_sources.remove(repo)
|
|
164
|
-
|
|
165
162
|
else:
|
|
166
163
|
host.noop(
|
|
167
164
|
'apt repo "{0}" {1}'.format(
|
|
@@ -172,7 +169,7 @@ def repo(src, present=True, filename=None):
|
|
|
172
169
|
|
|
173
170
|
|
|
174
171
|
@operation(is_idempotent=False)
|
|
175
|
-
def ppa(src, present=True):
|
|
172
|
+
def ppa(src: str, present=True):
|
|
176
173
|
"""
|
|
177
174
|
Add/remove Ubuntu ppa repositories.
|
|
178
175
|
|
|
@@ -201,8 +198,8 @@ def ppa(src, present=True):
|
|
|
201
198
|
yield 'apt-add-repository -y --remove "{0}"'.format(src)
|
|
202
199
|
|
|
203
200
|
|
|
204
|
-
@operation
|
|
205
|
-
def deb(src, present=True, force=False):
|
|
201
|
+
@operation()
|
|
202
|
+
def deb(src: str, present=True, force=False):
|
|
206
203
|
"""
|
|
207
204
|
Add/remove ``.deb`` file packages.
|
|
208
205
|
|
|
@@ -234,27 +231,23 @@ def deb(src, present=True, force=False):
|
|
|
234
231
|
# If source is a url
|
|
235
232
|
if urlparse(src).scheme:
|
|
236
233
|
# Generate a temp filename
|
|
237
|
-
temp_filename =
|
|
234
|
+
temp_filename = host.get_temp_filename(src)
|
|
238
235
|
|
|
239
236
|
# Ensure it's downloaded
|
|
240
|
-
yield from files.download(src, temp_filename)
|
|
237
|
+
yield from files.download._inner(src=src, dest=temp_filename)
|
|
241
238
|
|
|
242
239
|
# Override the source with the downloaded file
|
|
243
240
|
src = temp_filename
|
|
244
241
|
|
|
245
242
|
# Check for file .deb information (if file is present)
|
|
246
|
-
info = host.get_fact(DebPackage,
|
|
243
|
+
info = host.get_fact(DebPackage, package=src)
|
|
247
244
|
current_packages = host.get_fact(DebPackages)
|
|
248
245
|
|
|
249
246
|
exists = False
|
|
250
247
|
|
|
251
248
|
# We have deb info! Check against installed packages
|
|
252
|
-
if info:
|
|
253
|
-
|
|
254
|
-
info["name"] in current_packages
|
|
255
|
-
and info.get("version") in current_packages[info["name"]]
|
|
256
|
-
):
|
|
257
|
-
exists = True
|
|
249
|
+
if info and info.get("version") in current_packages.get(info.get("name"), {}):
|
|
250
|
+
exists = True
|
|
258
251
|
|
|
259
252
|
# Package does not exist and we want?
|
|
260
253
|
if present:
|
|
@@ -266,9 +259,6 @@ def deb(src, present=True, force=False):
|
|
|
266
259
|
# Now reinstall, and critically configure, the package - if there are still
|
|
267
260
|
# missing deps, now we error
|
|
268
261
|
yield "dpkg --force-confdef --force-confold -i {0}".format(src)
|
|
269
|
-
|
|
270
|
-
if info:
|
|
271
|
-
current_packages[info["name"]] = [info.get("version")]
|
|
272
262
|
else:
|
|
273
263
|
host.noop("deb {0} is installed".format(original_src))
|
|
274
264
|
|
|
@@ -279,7 +269,6 @@ def deb(src, present=True, force=False):
|
|
|
279
269
|
noninteractive_apt("remove", force=force),
|
|
280
270
|
info["name"],
|
|
281
271
|
)
|
|
282
|
-
current_packages.pop(info["name"])
|
|
283
272
|
else:
|
|
284
273
|
host.noop("deb {0} is not installed".format(original_src))
|
|
285
274
|
|
|
@@ -291,7 +280,7 @@ def deb(src, present=True, force=False):
|
|
|
291
280
|
"unless the ``cache_time`` argument is provided."
|
|
292
281
|
),
|
|
293
282
|
)
|
|
294
|
-
def update(cache_time=None):
|
|
283
|
+
def update(cache_time: int | None = None):
|
|
295
284
|
"""
|
|
296
285
|
Updates apt repositories.
|
|
297
286
|
|
|
@@ -326,14 +315,6 @@ def update(cache_time=None):
|
|
|
326
315
|
# cache_time to work.
|
|
327
316
|
if cache_time:
|
|
328
317
|
yield "touch {0}".format(APT_UPDATE_FILENAME)
|
|
329
|
-
if cache_info is None:
|
|
330
|
-
host.create_fact(
|
|
331
|
-
File,
|
|
332
|
-
kwargs={"path": APT_UPDATE_FILENAME},
|
|
333
|
-
data={"mtime": datetime.utcnow()},
|
|
334
|
-
)
|
|
335
|
-
else:
|
|
336
|
-
cache_info["mtime"] = datetime.utcnow()
|
|
337
318
|
|
|
338
319
|
|
|
339
320
|
_update = update # noqa: E305
|
|
@@ -357,7 +338,7 @@ def upgrade(auto_remove: bool = False):
|
|
|
357
338
|
|
|
358
339
|
# Upgrade all packages and remove unneeded transitive dependencies
|
|
359
340
|
apt.upgrade(
|
|
360
|
-
name="Upgrade apt packages and remove unneeded dependencies"
|
|
341
|
+
name="Upgrade apt packages and remove unneeded dependencies",
|
|
361
342
|
auto_remove=True
|
|
362
343
|
)
|
|
363
344
|
"""
|
|
@@ -390,19 +371,19 @@ def dist_upgrade():
|
|
|
390
371
|
yield noninteractive_apt("dist-upgrade")
|
|
391
372
|
|
|
392
373
|
|
|
393
|
-
@operation
|
|
374
|
+
@operation()
|
|
394
375
|
def packages(
|
|
395
|
-
packages=None,
|
|
376
|
+
packages: str | list[str] | None = None,
|
|
396
377
|
present=True,
|
|
397
378
|
latest=False,
|
|
398
379
|
update=False,
|
|
399
|
-
cache_time=None,
|
|
380
|
+
cache_time: int | None = None,
|
|
400
381
|
upgrade=False,
|
|
401
382
|
force=False,
|
|
402
383
|
no_recommends=False,
|
|
403
384
|
allow_downgrades=False,
|
|
404
|
-
extra_install_args=None,
|
|
405
|
-
extra_uninstall_args=None,
|
|
385
|
+
extra_install_args: str | None = None,
|
|
386
|
+
extra_uninstall_args: str | None = None,
|
|
406
387
|
):
|
|
407
388
|
"""
|
|
408
389
|
Install/remove/update packages & update apt.
|
|
@@ -454,29 +435,29 @@ def packages(
|
|
|
454
435
|
"""
|
|
455
436
|
|
|
456
437
|
if update:
|
|
457
|
-
yield from _update(cache_time=cache_time)
|
|
438
|
+
yield from _update._inner(cache_time=cache_time)
|
|
458
439
|
|
|
459
440
|
if upgrade:
|
|
460
|
-
yield from _upgrade()
|
|
441
|
+
yield from _upgrade._inner()
|
|
461
442
|
|
|
462
|
-
|
|
443
|
+
install_command_args = ["install"]
|
|
463
444
|
if no_recommends is True:
|
|
464
|
-
|
|
445
|
+
install_command_args.append("--no-install-recommends")
|
|
465
446
|
if allow_downgrades:
|
|
466
|
-
|
|
447
|
+
install_command_args.append("--allow-downgrades")
|
|
467
448
|
|
|
468
|
-
upgrade_command = " ".join(
|
|
449
|
+
upgrade_command = " ".join(install_command_args)
|
|
469
450
|
|
|
470
451
|
if extra_install_args:
|
|
471
|
-
|
|
452
|
+
install_command_args.append(extra_install_args)
|
|
472
453
|
|
|
473
|
-
install_command = " ".join(
|
|
454
|
+
install_command = " ".join(install_command_args)
|
|
474
455
|
|
|
475
|
-
|
|
456
|
+
uninstall_command_args = ["remove"]
|
|
476
457
|
if extra_uninstall_args:
|
|
477
|
-
|
|
458
|
+
uninstall_command_args.append(extra_uninstall_args)
|
|
478
459
|
|
|
479
|
-
uninstall_command = " ".join(
|
|
460
|
+
uninstall_command = " ".join(uninstall_command_args)
|
|
480
461
|
|
|
481
462
|
# Compare/ensure packages are present/not
|
|
482
463
|
yield from ensure_packages(
|
pyinfra/operations/brew.py
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
Manage brew packages on mac/OSX. See https://brew.sh/
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import urllib.parse
|
|
6
8
|
|
|
7
9
|
from pyinfra import host
|
|
8
10
|
from pyinfra.api import operation
|
|
@@ -35,9 +37,9 @@ def upgrade():
|
|
|
35
37
|
_upgrade = upgrade # noqa: E305
|
|
36
38
|
|
|
37
39
|
|
|
38
|
-
@operation
|
|
40
|
+
@operation()
|
|
39
41
|
def packages(
|
|
40
|
-
packages=None,
|
|
42
|
+
packages: str | list[str] | None = None,
|
|
41
43
|
present=True,
|
|
42
44
|
latest=False,
|
|
43
45
|
update=False,
|
|
@@ -75,10 +77,10 @@ def packages(
|
|
|
75
77
|
"""
|
|
76
78
|
|
|
77
79
|
if update:
|
|
78
|
-
yield from _update()
|
|
80
|
+
yield from _update._inner()
|
|
79
81
|
|
|
80
82
|
if upgrade:
|
|
81
|
-
yield from _upgrade()
|
|
83
|
+
yield from _upgrade._inner()
|
|
82
84
|
|
|
83
85
|
yield from ensure_packages(
|
|
84
86
|
host,
|
|
@@ -93,27 +95,22 @@ def packages(
|
|
|
93
95
|
)
|
|
94
96
|
|
|
95
97
|
|
|
96
|
-
def cask_args(
|
|
98
|
+
def cask_args():
|
|
97
99
|
return ("", " --cask") if new_cask_cli(host.get_fact(BrewVersion)) else ("cask ", "")
|
|
98
100
|
|
|
99
101
|
|
|
100
|
-
@operation(
|
|
101
|
-
is_idempotent=False,
|
|
102
|
-
pipeline_facts={"brew_version": ""},
|
|
103
|
-
)
|
|
102
|
+
@operation(is_idempotent=False)
|
|
104
103
|
def cask_upgrade():
|
|
105
104
|
"""
|
|
106
105
|
Upgrades all brew casks.
|
|
107
106
|
"""
|
|
108
107
|
|
|
109
|
-
yield "brew %supgrade%s" % cask_args(
|
|
108
|
+
yield "brew %supgrade%s" % cask_args()
|
|
110
109
|
|
|
111
110
|
|
|
112
|
-
@operation(
|
|
113
|
-
pipeline_facts={"brew_version": ""},
|
|
114
|
-
)
|
|
111
|
+
@operation()
|
|
115
112
|
def casks(
|
|
116
|
-
casks=None,
|
|
113
|
+
casks: str | list[str] | None = None,
|
|
117
114
|
present=True,
|
|
118
115
|
latest=False,
|
|
119
116
|
upgrade=False,
|
|
@@ -143,9 +140,9 @@ def casks(
|
|
|
143
140
|
"""
|
|
144
141
|
|
|
145
142
|
if upgrade:
|
|
146
|
-
yield from cask_upgrade()
|
|
143
|
+
yield from cask_upgrade._inner()
|
|
147
144
|
|
|
148
|
-
args = cask_args(
|
|
145
|
+
args = cask_args()
|
|
149
146
|
|
|
150
147
|
yield from ensure_packages(
|
|
151
148
|
host,
|
|
@@ -160,8 +157,8 @@ def casks(
|
|
|
160
157
|
)
|
|
161
158
|
|
|
162
159
|
|
|
163
|
-
@operation
|
|
164
|
-
def tap(src=None, present=True, url=None):
|
|
160
|
+
@operation()
|
|
161
|
+
def tap(src: str | None = None, present=True, url: str | None = None):
|
|
165
162
|
"""
|
|
166
163
|
Add/remove brew taps.
|
|
167
164
|
|
|
@@ -204,7 +201,7 @@ def tap(src=None, present=True, url=None):
|
|
|
204
201
|
host.noop("no tap was specified")
|
|
205
202
|
return
|
|
206
203
|
|
|
207
|
-
src = src or urllib.parse.urlparse(url).path.strip("/")
|
|
204
|
+
src = src or str(urllib.parse.urlparse(url).path).strip("/")
|
|
208
205
|
|
|
209
206
|
if len(src.split("/")) != 2:
|
|
210
207
|
host.noop("src '{0}' doesn't have two components.".format(src))
|
|
@@ -219,7 +216,6 @@ def tap(src=None, present=True, url=None):
|
|
|
219
216
|
|
|
220
217
|
if already_tapped:
|
|
221
218
|
yield "brew untap {0}".format(src)
|
|
222
|
-
taps.remove(src)
|
|
223
219
|
return
|
|
224
220
|
|
|
225
221
|
if not present:
|
|
@@ -232,5 +228,4 @@ def tap(src=None, present=True, url=None):
|
|
|
232
228
|
cmd = " ".join([cmd, url])
|
|
233
229
|
|
|
234
230
|
yield cmd
|
|
235
|
-
taps.append(src)
|
|
236
231
|
return
|
pyinfra/operations/bsdinit.py
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
Manage BSD init services (``/etc/rc.d``, ``/usr/local/etc/rc.d``).
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
5
7
|
from pyinfra import host
|
|
6
8
|
from pyinfra.api import operation
|
|
7
9
|
from pyinfra.facts.bsdinit import RcdStatus
|
|
@@ -11,14 +13,14 @@ from . import files
|
|
|
11
13
|
from .util.service import handle_service_control
|
|
12
14
|
|
|
13
15
|
|
|
14
|
-
@operation
|
|
16
|
+
@operation()
|
|
15
17
|
def service(
|
|
16
|
-
service,
|
|
18
|
+
service: str,
|
|
17
19
|
running=True,
|
|
18
20
|
restarted=False,
|
|
19
21
|
reloaded=False,
|
|
20
|
-
command=None,
|
|
21
|
-
enabled=None,
|
|
22
|
+
command: str | None = None,
|
|
23
|
+
enabled: bool | None = None,
|
|
22
24
|
):
|
|
23
25
|
"""
|
|
24
26
|
Manage the state of BSD init services.
|
|
@@ -49,9 +51,9 @@ def service(
|
|
|
49
51
|
|
|
50
52
|
# BSD init is simple, just add/remove <service>_enabled="YES"
|
|
51
53
|
if isinstance(enabled, bool):
|
|
52
|
-
yield from files.line(
|
|
53
|
-
"/etc/rc.conf.local",
|
|
54
|
-
"^{0}_enable=".format(service),
|
|
54
|
+
yield from files.line._inner(
|
|
55
|
+
path="/etc/rc.conf.local",
|
|
56
|
+
line="^{0}_enable=".format(service),
|
|
55
57
|
replace='{0}_enable="YES"'.format(service),
|
|
56
58
|
present=enabled,
|
|
57
59
|
)
|