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.
- pyinfra/api/arguments.py +9 -2
- pyinfra/api/arguments_typed.py +4 -5
- pyinfra/api/command.py +22 -3
- pyinfra/api/config.py +5 -2
- pyinfra/api/deploy.py +4 -2
- pyinfra/api/facts.py +3 -0
- pyinfra/api/host.py +15 -7
- pyinfra/api/operation.py +2 -1
- pyinfra/api/state.py +1 -1
- pyinfra/connectors/base.py +34 -8
- pyinfra/connectors/chroot.py +7 -2
- pyinfra/connectors/docker.py +24 -8
- pyinfra/connectors/dockerssh.py +7 -2
- pyinfra/connectors/local.py +7 -2
- pyinfra/connectors/ssh.py +9 -2
- pyinfra/connectors/sshuserclient/client.py +42 -14
- pyinfra/connectors/sshuserclient/config.py +2 -0
- pyinfra/connectors/terraform.py +1 -1
- pyinfra/connectors/util.py +13 -9
- pyinfra/context.py +9 -2
- pyinfra/facts/apk.py +8 -1
- pyinfra/facts/apt.py +68 -0
- pyinfra/facts/brew.py +13 -0
- pyinfra/facts/bsdinit.py +3 -0
- pyinfra/facts/cargo.py +5 -0
- pyinfra/facts/choco.py +6 -0
- pyinfra/facts/crontab.py +195 -0
- pyinfra/facts/deb.py +10 -0
- pyinfra/facts/dnf.py +5 -0
- pyinfra/facts/docker.py +16 -0
- pyinfra/facts/efibootmgr.py +113 -0
- pyinfra/facts/files.py +112 -7
- pyinfra/facts/flatpak.py +7 -0
- pyinfra/facts/freebsd.py +75 -0
- pyinfra/facts/gem.py +5 -0
- pyinfra/facts/git.py +12 -2
- pyinfra/facts/gpg.py +7 -0
- pyinfra/facts/hardware.py +13 -0
- pyinfra/facts/iptables.py +9 -1
- pyinfra/facts/launchd.py +5 -0
- pyinfra/facts/lxd.py +5 -0
- pyinfra/facts/mysql.py +9 -2
- pyinfra/facts/npm.py +5 -0
- pyinfra/facts/openrc.py +8 -0
- pyinfra/facts/opkg.py +245 -0
- pyinfra/facts/pacman.py +9 -1
- pyinfra/facts/pip.py +5 -0
- pyinfra/facts/pipx.py +82 -0
- pyinfra/facts/pkg.py +4 -0
- pyinfra/facts/pkgin.py +5 -0
- pyinfra/facts/podman.py +54 -0
- pyinfra/facts/postgres.py +10 -2
- pyinfra/facts/rpm.py +11 -0
- pyinfra/facts/runit.py +7 -0
- pyinfra/facts/selinux.py +16 -0
- pyinfra/facts/server.py +87 -79
- pyinfra/facts/snap.py +7 -0
- pyinfra/facts/systemd.py +5 -0
- pyinfra/facts/sysvinit.py +4 -0
- pyinfra/facts/upstart.py +5 -0
- pyinfra/facts/util/__init__.py +4 -1
- pyinfra/facts/util/units.py +30 -0
- pyinfra/facts/vzctl.py +5 -0
- pyinfra/facts/xbps.py +6 -1
- pyinfra/facts/yum.py +5 -0
- pyinfra/facts/zfs.py +41 -21
- pyinfra/facts/zypper.py +5 -0
- pyinfra/local.py +3 -2
- pyinfra/operations/apt.py +36 -22
- pyinfra/operations/crontab.py +189 -0
- pyinfra/operations/docker.py +61 -56
- pyinfra/operations/files.py +65 -1
- pyinfra/operations/freebsd/__init__.py +12 -0
- pyinfra/operations/freebsd/freebsd_update.py +70 -0
- pyinfra/operations/freebsd/pkg.py +219 -0
- pyinfra/operations/freebsd/service.py +116 -0
- pyinfra/operations/freebsd/sysrc.py +92 -0
- pyinfra/operations/git.py +23 -7
- pyinfra/operations/opkg.py +88 -0
- pyinfra/operations/pip.py +3 -2
- pyinfra/operations/pipx.py +90 -0
- pyinfra/operations/postgres.py +114 -27
- pyinfra/operations/runit.py +2 -0
- pyinfra/operations/server.py +9 -181
- pyinfra/operations/util/docker.py +44 -22
- pyinfra/operations/zfs.py +3 -3
- {pyinfra-3.1.1.dist-info → pyinfra-3.3.dist-info}/LICENSE.md +1 -1
- {pyinfra-3.1.1.dist-info → pyinfra-3.3.dist-info}/METADATA +25 -25
- pyinfra-3.3.dist-info/RECORD +187 -0
- pyinfra_cli/exceptions.py +5 -0
- pyinfra_cli/inventory.py +26 -9
- pyinfra_cli/log.py +3 -0
- pyinfra_cli/main.py +9 -8
- pyinfra_cli/prints.py +19 -4
- pyinfra_cli/util.py +3 -0
- pyinfra_cli/virtualenv.py +1 -1
- tests/test_cli/test_cli_deploy.py +15 -13
- tests/test_cli/test_cli_inventory.py +53 -0
- tests/test_connectors/test_ssh.py +302 -182
- tests/test_connectors/test_sshuserclient.py +68 -1
- pyinfra-3.1.1.dist-info/RECORD +0 -172
- {pyinfra-3.1.1.dist-info → pyinfra-3.3.dist-info}/WHEEL +0 -0
- {pyinfra-3.1.1.dist-info → pyinfra-3.3.dist-info}/entry_points.txt +0 -0
- {pyinfra-3.1.1.dist-info → pyinfra-3.3.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Manage FreeBSD services.
|
|
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.api.exceptions import OperationValueError
|
|
12
|
+
from pyinfra.facts.freebsd import ServiceScript, ServiceStatus
|
|
13
|
+
|
|
14
|
+
SRV_STARTED: str = "started"
|
|
15
|
+
SRV_STOPPED: str = "stopped"
|
|
16
|
+
SRV_RESTARTED: str = "restarted"
|
|
17
|
+
SRV_RELOADED: str = "reloaded"
|
|
18
|
+
SRV_CUSTOM: str = "custom"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@operation()
|
|
22
|
+
def service(
|
|
23
|
+
srvname: str,
|
|
24
|
+
jail: Optional[str] = None,
|
|
25
|
+
srvstate: str = SRV_STARTED,
|
|
26
|
+
command: Optional[Union[str, List[str]]] = None,
|
|
27
|
+
environment: Optional[List[str]] = None,
|
|
28
|
+
verbose: bool = False,
|
|
29
|
+
):
|
|
30
|
+
"""
|
|
31
|
+
Control (start/stop/etc.) ``rc(8)`` scripts.
|
|
32
|
+
|
|
33
|
+
+ srvname: Service.
|
|
34
|
+
+ jail: See ``-j`` in ``service(8)``.
|
|
35
|
+
+ srvstate: Desire state of the service.
|
|
36
|
+
+ command: When ``srvstate`` is ``custom``, the command to execute.
|
|
37
|
+
+ environment: See ``-E`` in ``service(8)``.
|
|
38
|
+
+ verbose: See ``-v`` in ``service(8)``.
|
|
39
|
+
|
|
40
|
+
States:
|
|
41
|
+
There are a few states you can use to manipulate the service:
|
|
42
|
+
|
|
43
|
+
- started: The service must be started.
|
|
44
|
+
- stopped: The service must be stopped.
|
|
45
|
+
- restarted: The service must be restarted.
|
|
46
|
+
- reloaded: The service must be reloaded.
|
|
47
|
+
- custom: Run a custom command for this service.
|
|
48
|
+
|
|
49
|
+
**Examples:**
|
|
50
|
+
|
|
51
|
+
.. code:: python
|
|
52
|
+
|
|
53
|
+
# Start a service.
|
|
54
|
+
service.service(
|
|
55
|
+
"beanstalkd",
|
|
56
|
+
srvstate="started"
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
# Execute a custom command.
|
|
60
|
+
service.service(
|
|
61
|
+
"sopel",
|
|
62
|
+
srvstate="custom",
|
|
63
|
+
command="configure"
|
|
64
|
+
)
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
if not host.get_fact(ServiceScript, srvname=srvname, jail=jail):
|
|
68
|
+
host.noop(f"Cannot find rc(8) script '{srvname}'")
|
|
69
|
+
return
|
|
70
|
+
|
|
71
|
+
args: List[Union[str, "QuoteString"]] = []
|
|
72
|
+
|
|
73
|
+
args.append("service")
|
|
74
|
+
|
|
75
|
+
if verbose:
|
|
76
|
+
args.append("-v")
|
|
77
|
+
|
|
78
|
+
if jail is not None:
|
|
79
|
+
args.extend(["-j", QuoteString(jail)])
|
|
80
|
+
|
|
81
|
+
if environment is not None:
|
|
82
|
+
for env_var in environment:
|
|
83
|
+
args.extend(["-E", QuoteString(env_var)])
|
|
84
|
+
|
|
85
|
+
if srvstate == SRV_STARTED:
|
|
86
|
+
if host.get_fact(ServiceStatus, srvname=srvname, jail=jail):
|
|
87
|
+
host.noop(f"Service '{srvname}' already started")
|
|
88
|
+
return
|
|
89
|
+
|
|
90
|
+
args.extend([QuoteString(srvname), "start"])
|
|
91
|
+
|
|
92
|
+
elif srvstate == SRV_STOPPED:
|
|
93
|
+
if not host.get_fact(ServiceStatus, srvname=srvname, jail=jail):
|
|
94
|
+
host.noop(f"Service '{srvname}' already stopped")
|
|
95
|
+
return
|
|
96
|
+
|
|
97
|
+
args.extend([QuoteString(srvname), "stop"])
|
|
98
|
+
elif srvstate == SRV_RESTARTED:
|
|
99
|
+
args.extend([QuoteString(srvname), "restart"])
|
|
100
|
+
|
|
101
|
+
elif srvstate == SRV_RELOADED:
|
|
102
|
+
args.extend([QuoteString(srvname), "reload"])
|
|
103
|
+
|
|
104
|
+
elif srvstate == SRV_CUSTOM:
|
|
105
|
+
args.append(QuoteString(srvname))
|
|
106
|
+
|
|
107
|
+
if command is not None:
|
|
108
|
+
if isinstance(command, str):
|
|
109
|
+
command = [command]
|
|
110
|
+
|
|
111
|
+
args.extend([QuoteString(c) for c in command])
|
|
112
|
+
|
|
113
|
+
else:
|
|
114
|
+
raise OperationValueError(f"Invalid service command: {srvstate}")
|
|
115
|
+
|
|
116
|
+
yield StringCommand(*args)
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Manipulate system rc files.
|
|
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.api.exceptions import OperationValueError
|
|
12
|
+
from pyinfra.facts.freebsd import Sysrc
|
|
13
|
+
|
|
14
|
+
SYSRC_ADD: str = "add"
|
|
15
|
+
SYSRC_SUB: str = "sub"
|
|
16
|
+
SYSRC_SET: str = "set"
|
|
17
|
+
SYSRC_DEL: str = "del"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@operation()
|
|
21
|
+
def sysrc(
|
|
22
|
+
parameter: str,
|
|
23
|
+
value: str,
|
|
24
|
+
jail: Optional[str] = None,
|
|
25
|
+
command: str = SYSRC_SET,
|
|
26
|
+
overwrite: bool = False,
|
|
27
|
+
):
|
|
28
|
+
"""
|
|
29
|
+
Safely edit system rc files.
|
|
30
|
+
|
|
31
|
+
+ parameter: Parameter to manipulate.
|
|
32
|
+
+ value: Value, if the parameter requires it.
|
|
33
|
+
+ jail: See ``-j`` in ``sysrc(8)``.
|
|
34
|
+
+ command: Desire state of the parameter.
|
|
35
|
+
+ overwrite: Overwrite the value of the parameter when ``command`` is set to ``set``.
|
|
36
|
+
|
|
37
|
+
Commands:
|
|
38
|
+
There are a few commands you can use to manipulate the rc file:
|
|
39
|
+
|
|
40
|
+
- add: Adds the value to the parameter.
|
|
41
|
+
- sub: Delete the parameter value.
|
|
42
|
+
- set: Change the parameter value. If the parameter already has a value
|
|
43
|
+
set, the changes will not be applied unless ``overwrite`` is set
|
|
44
|
+
to ``True``.
|
|
45
|
+
- del: Delete the parameter.
|
|
46
|
+
|
|
47
|
+
**Example:**
|
|
48
|
+
|
|
49
|
+
.. code:: python
|
|
50
|
+
|
|
51
|
+
sysrc.sysrc(
|
|
52
|
+
"beanstalkd_enable",
|
|
53
|
+
"YES",
|
|
54
|
+
command="set"
|
|
55
|
+
)
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
args: List[Union[str, "QuoteString"]] = []
|
|
59
|
+
|
|
60
|
+
args.extend(["sysrc", "-i"])
|
|
61
|
+
|
|
62
|
+
if command == SYSRC_DEL:
|
|
63
|
+
sign = "="
|
|
64
|
+
|
|
65
|
+
if not host.get_fact(Sysrc, parameter=parameter, jail=jail):
|
|
66
|
+
host.noop(f"Cannot find sysrc(8) parameter '{parameter}'")
|
|
67
|
+
return
|
|
68
|
+
|
|
69
|
+
args.append("-x")
|
|
70
|
+
|
|
71
|
+
elif command == SYSRC_SET:
|
|
72
|
+
sign = "="
|
|
73
|
+
|
|
74
|
+
if not overwrite and host.get_fact(Sysrc, parameter=parameter, jail=jail):
|
|
75
|
+
host.noop(f"sysrc(8) parameter '{parameter}' already set")
|
|
76
|
+
return
|
|
77
|
+
|
|
78
|
+
elif command == SYSRC_ADD:
|
|
79
|
+
sign = "+="
|
|
80
|
+
|
|
81
|
+
elif command == SYSRC_SUB:
|
|
82
|
+
sign = "-="
|
|
83
|
+
|
|
84
|
+
else:
|
|
85
|
+
raise OperationValueError(f"Invalid sysrc command: {command}")
|
|
86
|
+
|
|
87
|
+
if jail is not None:
|
|
88
|
+
args.extend(["-j", QuoteString(jail)])
|
|
89
|
+
|
|
90
|
+
args.extend(["--", QuoteString(f"{parameter}{sign}{value}")])
|
|
91
|
+
|
|
92
|
+
yield StringCommand(*args)
|
pyinfra/operations/git.py
CHANGED
|
@@ -16,24 +16,40 @@ from .util.files import chown, unix_path_join
|
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
@operation()
|
|
19
|
-
def config(key: str, value: str, multi_value=False, repo: str | None = None):
|
|
19
|
+
def config(key: str, value: str, multi_value=False, repo: str | None = None, system=False):
|
|
20
20
|
"""
|
|
21
|
-
Manage git config
|
|
21
|
+
Manage git config at repository, user or system level.
|
|
22
22
|
|
|
23
23
|
+ key: the key of the config to ensure
|
|
24
24
|
+ value: the value this key should have
|
|
25
25
|
+ multi_value: Add the value rather than set it for settings that can have multiple values
|
|
26
26
|
+ repo: specify the git repo path to edit local config (defaults to global)
|
|
27
|
+
+ system: whether, when ``repo`` is unspecified, to work at system level (or default to global)
|
|
27
28
|
|
|
28
|
-
**
|
|
29
|
+
**Examples:**
|
|
29
30
|
|
|
30
31
|
.. code:: python
|
|
31
32
|
|
|
32
33
|
git.config(
|
|
33
|
-
name="
|
|
34
|
+
name="Always prune specified repo",
|
|
35
|
+
key="fetch.prune",
|
|
36
|
+
value="true",
|
|
37
|
+
repo="/usr/local/src/pyinfra",
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
git.config(
|
|
41
|
+
name="Ensure user name is set for all repos of specified user",
|
|
34
42
|
key="user.name",
|
|
35
43
|
value="Anon E. Mouse",
|
|
36
|
-
|
|
44
|
+
_sudo=True,
|
|
45
|
+
_sudo_user="anon"
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
git.config(
|
|
49
|
+
name="Ensure same date format for all users",
|
|
50
|
+
key="log.date",
|
|
51
|
+
value="iso",
|
|
52
|
+
system=True
|
|
37
53
|
)
|
|
38
54
|
|
|
39
55
|
"""
|
|
@@ -41,14 +57,14 @@ def config(key: str, value: str, multi_value=False, repo: str | None = None):
|
|
|
41
57
|
existing_config = {}
|
|
42
58
|
|
|
43
59
|
if not repo:
|
|
44
|
-
existing_config = host.get_fact(GitConfig)
|
|
60
|
+
existing_config = host.get_fact(GitConfig, system=system)
|
|
45
61
|
|
|
46
62
|
# Only get the config if the repo exists at this stage
|
|
47
63
|
elif host.get_fact(Directory, path=unix_path_join(repo, ".git")):
|
|
48
64
|
existing_config = host.get_fact(GitConfig, repo=repo)
|
|
49
65
|
|
|
50
66
|
if repo is None:
|
|
51
|
-
base_command = "git config --global"
|
|
67
|
+
base_command = "git config" + (" --system" if system else " --global")
|
|
52
68
|
else:
|
|
53
69
|
base_command = "cd {0} && git config --local".format(repo)
|
|
54
70
|
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Manage packages on OpenWrt using opkg
|
|
3
|
+
+ ``update`` - update local copy of package information
|
|
4
|
+
+ ``packages`` - install and remove packages
|
|
5
|
+
|
|
6
|
+
see https://openwrt.org/docs/guide-user/additional-software/opkg
|
|
7
|
+
OpenWrt recommends against upgrading all packages thus there is no ``opkg.upgrade`` function
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from typing import List, Union
|
|
11
|
+
|
|
12
|
+
from pyinfra import host
|
|
13
|
+
from pyinfra.api import StringCommand, operation
|
|
14
|
+
from pyinfra.facts.opkg import OpkgPackages
|
|
15
|
+
from pyinfra.operations.util.packaging import ensure_packages
|
|
16
|
+
|
|
17
|
+
EQUALS = "="
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@operation(is_idempotent=False)
|
|
21
|
+
def update():
|
|
22
|
+
"""
|
|
23
|
+
Update the local opkg information.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
yield StringCommand("opkg update")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
_update = update
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@operation()
|
|
33
|
+
def packages(
|
|
34
|
+
packages: Union[str, List[str]] = "",
|
|
35
|
+
present: bool = True,
|
|
36
|
+
latest: bool = False,
|
|
37
|
+
update: bool = True,
|
|
38
|
+
):
|
|
39
|
+
"""
|
|
40
|
+
Add/remove/update opkg packages.
|
|
41
|
+
|
|
42
|
+
+ packages: package or list of packages to that must/must not be present
|
|
43
|
+
+ present: whether the package(s) should be installed (default True) or removed
|
|
44
|
+
+ latest: whether to attempt to upgrade the specified package(s) (default False)
|
|
45
|
+
+ update: run ``opkg update`` before installing packages (default True)
|
|
46
|
+
|
|
47
|
+
Not Supported:
|
|
48
|
+
Opkg does not support version pinning, i.e. ``<pkg>=<version>`` is not allowed
|
|
49
|
+
and will cause an exception.
|
|
50
|
+
|
|
51
|
+
**Examples:**
|
|
52
|
+
|
|
53
|
+
.. code:: python
|
|
54
|
+
|
|
55
|
+
# Ensure packages are installed∂ (will not force package upgrade)
|
|
56
|
+
opkg.packages(['asterisk', 'vim'], name="Install Asterisk and Vim")
|
|
57
|
+
|
|
58
|
+
# Install the latest versions of packages (always check)
|
|
59
|
+
opkg.packages(
|
|
60
|
+
'vim',
|
|
61
|
+
latest=True,
|
|
62
|
+
name="Ensure we have the latest version of Vim"
|
|
63
|
+
)
|
|
64
|
+
"""
|
|
65
|
+
if str(packages) == "" or (
|
|
66
|
+
isinstance(packages, list) and (len(packages) < 1 or all(len(p) < 1 for p in packages))
|
|
67
|
+
):
|
|
68
|
+
host.noop("empty or invalid package list provided to opkg.packages")
|
|
69
|
+
return
|
|
70
|
+
|
|
71
|
+
pkg_list = packages if isinstance(packages, list) else [packages]
|
|
72
|
+
have_equals = ",".join([pkg.split(EQUALS)[0] for pkg in pkg_list if EQUALS in pkg])
|
|
73
|
+
if len(have_equals) > 0:
|
|
74
|
+
raise ValueError(f"opkg does not support version pinning but found for: '{have_equals}'")
|
|
75
|
+
|
|
76
|
+
if update:
|
|
77
|
+
yield from _update._inner()
|
|
78
|
+
|
|
79
|
+
yield from ensure_packages(
|
|
80
|
+
host,
|
|
81
|
+
pkg_list,
|
|
82
|
+
host.get_fact(OpkgPackages),
|
|
83
|
+
present,
|
|
84
|
+
install_command="opkg install",
|
|
85
|
+
upgrade_command="opkg upgrade",
|
|
86
|
+
uninstall_command="opkg remove",
|
|
87
|
+
latest=latest,
|
|
88
|
+
)
|
pyinfra/operations/pip.py
CHANGED
|
@@ -174,12 +174,13 @@ def packages(
|
|
|
174
174
|
install_command_args.append(extra_install_args)
|
|
175
175
|
install_command = " ".join(install_command_args)
|
|
176
176
|
|
|
177
|
+
upgrade_command = "{0} --upgrade".format(install_command)
|
|
177
178
|
uninstall_command = " ".join([pip, "uninstall", "--yes"])
|
|
178
179
|
|
|
179
180
|
# (un)Install requirements
|
|
180
181
|
if requirements is not None:
|
|
181
182
|
if present:
|
|
182
|
-
yield "{0} -r {1}".format(install_command, requirements)
|
|
183
|
+
yield "{0} -r {1}".format(upgrade_command if latest else install_command, requirements)
|
|
183
184
|
else:
|
|
184
185
|
yield "{0} -r {1}".format(uninstall_command, requirements)
|
|
185
186
|
|
|
@@ -199,7 +200,7 @@ def packages(
|
|
|
199
200
|
present,
|
|
200
201
|
install_command=install_command,
|
|
201
202
|
uninstall_command=uninstall_command,
|
|
202
|
-
upgrade_command=
|
|
203
|
+
upgrade_command=upgrade_command,
|
|
203
204
|
version_join="==",
|
|
204
205
|
latest=latest,
|
|
205
206
|
)
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Manage pipx (python) applications.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from pyinfra import host
|
|
6
|
+
from pyinfra.api import operation
|
|
7
|
+
from pyinfra.facts.pipx import PipxEnvironment, PipxPackages
|
|
8
|
+
from pyinfra.facts.server import Path
|
|
9
|
+
|
|
10
|
+
from .util.packaging import ensure_packages
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@operation()
|
|
14
|
+
def packages(
|
|
15
|
+
packages=None,
|
|
16
|
+
present=True,
|
|
17
|
+
latest=False,
|
|
18
|
+
extra_args=None,
|
|
19
|
+
):
|
|
20
|
+
"""
|
|
21
|
+
Install/remove/update pipx packages.
|
|
22
|
+
|
|
23
|
+
+ packages: list of packages to ensure
|
|
24
|
+
+ present: whether the packages should be installed
|
|
25
|
+
+ latest: whether to upgrade packages without a specified version
|
|
26
|
+
+ extra_args: additional arguments to the pipx command
|
|
27
|
+
|
|
28
|
+
Versions:
|
|
29
|
+
Package versions can be pinned like pip: ``<pkg>==<version>``.
|
|
30
|
+
|
|
31
|
+
**Example:**
|
|
32
|
+
|
|
33
|
+
.. code:: python
|
|
34
|
+
|
|
35
|
+
pipx.packages(
|
|
36
|
+
name="Install ",
|
|
37
|
+
packages=["pyinfra"],
|
|
38
|
+
)
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
prep_install_command = ["pipx", "install"]
|
|
42
|
+
|
|
43
|
+
if extra_args:
|
|
44
|
+
prep_install_command.append(extra_args)
|
|
45
|
+
install_command = " ".join(prep_install_command)
|
|
46
|
+
|
|
47
|
+
uninstall_command = "pipx uninstall"
|
|
48
|
+
upgrade_command = "pipx upgrade"
|
|
49
|
+
|
|
50
|
+
current_packages = host.get_fact(PipxPackages)
|
|
51
|
+
|
|
52
|
+
# pipx support only one package name at a time
|
|
53
|
+
for package in packages:
|
|
54
|
+
yield from ensure_packages(
|
|
55
|
+
host,
|
|
56
|
+
[package],
|
|
57
|
+
current_packages,
|
|
58
|
+
present,
|
|
59
|
+
install_command=install_command,
|
|
60
|
+
uninstall_command=uninstall_command,
|
|
61
|
+
upgrade_command=upgrade_command,
|
|
62
|
+
version_join="==",
|
|
63
|
+
latest=latest,
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@operation()
|
|
68
|
+
def upgrade_all():
|
|
69
|
+
"""
|
|
70
|
+
Upgrade all pipx packages.
|
|
71
|
+
"""
|
|
72
|
+
yield "pipx upgrade-all"
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
@operation()
|
|
76
|
+
def ensure_path():
|
|
77
|
+
"""
|
|
78
|
+
Ensure pipx bin dir is in the PATH.
|
|
79
|
+
"""
|
|
80
|
+
|
|
81
|
+
# Fetch the current user's PATH
|
|
82
|
+
path = host.get_fact(Path)
|
|
83
|
+
# Fetch the pipx environment variables
|
|
84
|
+
pipx_env = host.get_fact(PipxEnvironment)
|
|
85
|
+
|
|
86
|
+
# If the pipx bin dir is already in the user's PATH, we're done
|
|
87
|
+
if "PIPX_BIN_DIR" in pipx_env and pipx_env["PIPX_BIN_DIR"] in path.split(":"):
|
|
88
|
+
host.noop("pipx bin dir is already in the PATH")
|
|
89
|
+
else:
|
|
90
|
+
yield "pipx ensurepath"
|