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.
- pyinfra/__init__.py +9 -12
- pyinfra/__main__.py +4 -0
- pyinfra/api/__init__.py +19 -3
- pyinfra/api/arguments.py +413 -0
- pyinfra/api/arguments_typed.py +79 -0
- pyinfra/api/command.py +274 -0
- pyinfra/api/config.py +222 -28
- pyinfra/api/connect.py +33 -13
- pyinfra/api/connectors.py +27 -0
- pyinfra/api/deploy.py +65 -66
- pyinfra/api/exceptions.py +73 -18
- pyinfra/api/facts.py +267 -200
- pyinfra/api/host.py +416 -50
- pyinfra/api/inventory.py +121 -160
- pyinfra/api/metadata.py +69 -0
- pyinfra/api/operation.py +432 -262
- pyinfra/api/operations.py +273 -260
- pyinfra/api/state.py +302 -248
- pyinfra/api/util.py +309 -369
- pyinfra/connectors/base.py +173 -0
- pyinfra/connectors/chroot.py +212 -0
- pyinfra/connectors/docker.py +405 -0
- pyinfra/connectors/dockerssh.py +297 -0
- pyinfra/connectors/local.py +238 -0
- pyinfra/connectors/scp/__init__.py +1 -0
- pyinfra/connectors/scp/client.py +204 -0
- pyinfra/connectors/ssh.py +727 -0
- pyinfra/connectors/ssh_util.py +114 -0
- pyinfra/connectors/sshuserclient/client.py +309 -0
- pyinfra/connectors/sshuserclient/config.py +102 -0
- pyinfra/connectors/terraform.py +135 -0
- pyinfra/connectors/util.py +417 -0
- pyinfra/connectors/vagrant.py +183 -0
- pyinfra/context.py +145 -0
- pyinfra/facts/__init__.py +7 -6
- pyinfra/facts/apk.py +22 -7
- pyinfra/facts/apt.py +117 -60
- pyinfra/facts/brew.py +100 -15
- pyinfra/facts/bsdinit.py +23 -0
- pyinfra/facts/cargo.py +37 -0
- pyinfra/facts/choco.py +47 -0
- pyinfra/facts/crontab.py +195 -0
- pyinfra/facts/deb.py +94 -0
- pyinfra/facts/dnf.py +48 -0
- pyinfra/facts/docker.py +96 -23
- pyinfra/facts/efibootmgr.py +113 -0
- pyinfra/facts/files.py +629 -58
- pyinfra/facts/flatpak.py +77 -0
- pyinfra/facts/freebsd.py +70 -0
- pyinfra/facts/gem.py +19 -6
- pyinfra/facts/git.py +59 -14
- pyinfra/facts/gpg.py +150 -0
- pyinfra/facts/hardware.py +313 -167
- pyinfra/facts/iptables.py +72 -62
- pyinfra/facts/launchd.py +44 -0
- pyinfra/facts/lxd.py +17 -4
- pyinfra/facts/mysql.py +122 -86
- pyinfra/facts/npm.py +17 -9
- pyinfra/facts/openrc.py +71 -0
- pyinfra/facts/opkg.py +246 -0
- pyinfra/facts/pacman.py +50 -7
- pyinfra/facts/pip.py +24 -7
- pyinfra/facts/pipx.py +82 -0
- pyinfra/facts/pkg.py +15 -6
- pyinfra/facts/pkgin.py +35 -0
- pyinfra/facts/podman.py +54 -0
- pyinfra/facts/postgres.py +178 -0
- pyinfra/facts/postgresql.py +6 -147
- pyinfra/facts/rpm.py +105 -0
- pyinfra/facts/runit.py +77 -0
- pyinfra/facts/selinux.py +161 -0
- pyinfra/facts/server.py +762 -285
- pyinfra/facts/snap.py +88 -0
- pyinfra/facts/systemd.py +139 -0
- pyinfra/facts/sysvinit.py +59 -0
- pyinfra/facts/upstart.py +35 -0
- pyinfra/facts/util/__init__.py +17 -0
- pyinfra/facts/util/databases.py +4 -6
- pyinfra/facts/util/packaging.py +37 -6
- pyinfra/facts/util/units.py +30 -0
- pyinfra/facts/util/win_files.py +99 -0
- pyinfra/facts/vzctl.py +20 -13
- pyinfra/facts/xbps.py +35 -0
- pyinfra/facts/yum.py +34 -40
- pyinfra/facts/zfs.py +77 -0
- pyinfra/facts/zypper.py +42 -0
- pyinfra/local.py +45 -83
- pyinfra/operations/__init__.py +12 -0
- pyinfra/operations/apk.py +99 -0
- pyinfra/operations/apt.py +496 -0
- pyinfra/operations/brew.py +232 -0
- pyinfra/operations/bsdinit.py +59 -0
- pyinfra/operations/cargo.py +45 -0
- pyinfra/operations/choco.py +61 -0
- pyinfra/operations/crontab.py +194 -0
- pyinfra/operations/dnf.py +213 -0
- pyinfra/operations/docker.py +492 -0
- pyinfra/operations/files.py +2014 -0
- pyinfra/operations/flatpak.py +95 -0
- 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/gem.py +48 -0
- pyinfra/operations/git.py +420 -0
- pyinfra/operations/iptables.py +312 -0
- pyinfra/operations/launchd.py +45 -0
- pyinfra/operations/lxd.py +69 -0
- pyinfra/operations/mysql.py +610 -0
- pyinfra/operations/npm.py +57 -0
- pyinfra/operations/openrc.py +63 -0
- pyinfra/operations/opkg.py +89 -0
- pyinfra/operations/pacman.py +82 -0
- pyinfra/operations/pip.py +206 -0
- pyinfra/operations/pipx.py +103 -0
- pyinfra/operations/pkg.py +71 -0
- pyinfra/operations/pkgin.py +92 -0
- pyinfra/operations/postgres.py +437 -0
- pyinfra/operations/postgresql.py +30 -0
- pyinfra/operations/puppet.py +41 -0
- pyinfra/operations/python.py +73 -0
- pyinfra/operations/runit.py +184 -0
- pyinfra/operations/selinux.py +190 -0
- pyinfra/operations/server.py +1100 -0
- pyinfra/operations/snap.py +118 -0
- pyinfra/operations/ssh.py +217 -0
- pyinfra/operations/systemd.py +150 -0
- pyinfra/operations/sysvinit.py +142 -0
- pyinfra/operations/upstart.py +68 -0
- pyinfra/operations/util/__init__.py +12 -0
- pyinfra/operations/util/docker.py +407 -0
- pyinfra/operations/util/files.py +247 -0
- pyinfra/operations/util/packaging.py +338 -0
- pyinfra/operations/util/service.py +46 -0
- pyinfra/operations/vzctl.py +137 -0
- pyinfra/operations/xbps.py +78 -0
- pyinfra/operations/yum.py +213 -0
- pyinfra/operations/zfs.py +176 -0
- pyinfra/operations/zypper.py +193 -0
- pyinfra/progress.py +44 -32
- pyinfra/py.typed +0 -0
- pyinfra/version.py +9 -1
- pyinfra-3.6.dist-info/METADATA +142 -0
- pyinfra-3.6.dist-info/RECORD +160 -0
- {pyinfra-0.11.dev3.dist-info → pyinfra-3.6.dist-info}/WHEEL +1 -2
- pyinfra-3.6.dist-info/entry_points.txt +12 -0
- {pyinfra-0.11.dev3.dist-info → pyinfra-3.6.dist-info/licenses}/LICENSE.md +1 -1
- pyinfra_cli/__init__.py +1 -0
- pyinfra_cli/cli.py +793 -0
- pyinfra_cli/commands.py +66 -0
- pyinfra_cli/exceptions.py +155 -65
- pyinfra_cli/inventory.py +233 -89
- pyinfra_cli/log.py +39 -43
- pyinfra_cli/main.py +26 -495
- pyinfra_cli/prints.py +215 -156
- pyinfra_cli/util.py +172 -105
- pyinfra_cli/virtualenv.py +25 -20
- pyinfra/api/connectors/__init__.py +0 -21
- pyinfra/api/connectors/ansible.py +0 -99
- pyinfra/api/connectors/docker.py +0 -178
- pyinfra/api/connectors/local.py +0 -169
- pyinfra/api/connectors/ssh.py +0 -402
- pyinfra/api/connectors/sshuserclient/client.py +0 -105
- pyinfra/api/connectors/sshuserclient/config.py +0 -90
- pyinfra/api/connectors/util.py +0 -63
- pyinfra/api/connectors/vagrant.py +0 -155
- pyinfra/facts/init.py +0 -176
- pyinfra/facts/util/files.py +0 -102
- pyinfra/hook.py +0 -41
- pyinfra/modules/__init__.py +0 -11
- pyinfra/modules/apk.py +0 -64
- pyinfra/modules/apt.py +0 -272
- pyinfra/modules/brew.py +0 -122
- pyinfra/modules/files.py +0 -711
- pyinfra/modules/gem.py +0 -30
- pyinfra/modules/git.py +0 -115
- pyinfra/modules/init.py +0 -344
- pyinfra/modules/iptables.py +0 -271
- pyinfra/modules/lxd.py +0 -45
- pyinfra/modules/mysql.py +0 -347
- pyinfra/modules/npm.py +0 -47
- pyinfra/modules/pacman.py +0 -60
- pyinfra/modules/pip.py +0 -99
- pyinfra/modules/pkg.py +0 -43
- pyinfra/modules/postgresql.py +0 -245
- pyinfra/modules/puppet.py +0 -20
- pyinfra/modules/python.py +0 -37
- pyinfra/modules/server.py +0 -524
- pyinfra/modules/ssh.py +0 -150
- pyinfra/modules/util/files.py +0 -52
- pyinfra/modules/util/packaging.py +0 -118
- pyinfra/modules/vzctl.py +0 -133
- pyinfra/modules/yum.py +0 -171
- pyinfra/pseudo_modules.py +0 -64
- pyinfra-0.11.dev3.dist-info/.DS_Store +0 -0
- pyinfra-0.11.dev3.dist-info/METADATA +0 -135
- pyinfra-0.11.dev3.dist-info/RECORD +0 -95
- pyinfra-0.11.dev3.dist-info/entry_points.txt +0 -3
- pyinfra-0.11.dev3.dist-info/top_level.txt +0 -2
- pyinfra_cli/__main__.py +0 -40
- pyinfra_cli/config.py +0 -92
- /pyinfra/{modules/util → connectors}/__init__.py +0 -0
- /pyinfra/{api/connectors → connectors}/sshuserclient/__init__.py +0 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Manage OpenRC init services.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from pyinfra import host
|
|
8
|
+
from pyinfra.api import operation
|
|
9
|
+
from pyinfra.facts.openrc import OpenrcEnabled, OpenrcStatus
|
|
10
|
+
|
|
11
|
+
from .util.service import handle_service_control
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@operation()
|
|
15
|
+
def service(
|
|
16
|
+
service: str,
|
|
17
|
+
running=True,
|
|
18
|
+
restarted=False,
|
|
19
|
+
reloaded=False,
|
|
20
|
+
command: str | None = None,
|
|
21
|
+
enabled: bool | None = None,
|
|
22
|
+
runlevel="default",
|
|
23
|
+
):
|
|
24
|
+
"""
|
|
25
|
+
Manage the state of OpenRC services.
|
|
26
|
+
|
|
27
|
+
+ service: name of the service to manage
|
|
28
|
+
+ running: whether the service should be running
|
|
29
|
+
+ restarted: whether the service should be restarted
|
|
30
|
+
+ reloaded: whether the service should be reloaded
|
|
31
|
+
+ command: custom command to pass like: ``rc-service <service> <command>``
|
|
32
|
+
+ enabled: whether this service should be enabled/disabled on boot
|
|
33
|
+
+ runlevel: runlevel to manage services for
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
yield from handle_service_control(
|
|
37
|
+
host,
|
|
38
|
+
service,
|
|
39
|
+
host.get_fact(OpenrcStatus, runlevel=runlevel),
|
|
40
|
+
"rc-service {0} {1}",
|
|
41
|
+
running,
|
|
42
|
+
restarted,
|
|
43
|
+
reloaded,
|
|
44
|
+
command,
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
if isinstance(enabled, bool):
|
|
48
|
+
openrc_enabled = host.get_fact(OpenrcEnabled, runlevel=runlevel)
|
|
49
|
+
is_enabled = openrc_enabled.get(service, False)
|
|
50
|
+
|
|
51
|
+
if enabled is True:
|
|
52
|
+
if not is_enabled:
|
|
53
|
+
yield "rc-update add {0} {1}".format(service, runlevel)
|
|
54
|
+
openrc_enabled[service] = True
|
|
55
|
+
else:
|
|
56
|
+
host.noop("service {0} is enabled".format(service))
|
|
57
|
+
|
|
58
|
+
if enabled is False:
|
|
59
|
+
if is_enabled:
|
|
60
|
+
yield "rc-update del {0} {1}".format(service, runlevel)
|
|
61
|
+
openrc_enabled[service] = False
|
|
62
|
+
else:
|
|
63
|
+
host.noop("service {0} is disabled".format(service))
|
|
@@ -0,0 +1,89 @@
|
|
|
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
|
+
from pyinfra.operations import opkg
|
|
56
|
+
# Ensure packages are installed (will not force package upgrade)
|
|
57
|
+
opkg.packages(['asterisk', 'vim'], name="Install Asterisk and Vim")
|
|
58
|
+
|
|
59
|
+
# Install the latest versions of packages (always check)
|
|
60
|
+
opkg.packages(
|
|
61
|
+
'vim',
|
|
62
|
+
latest=True,
|
|
63
|
+
name="Ensure we have the latest version of Vim"
|
|
64
|
+
)
|
|
65
|
+
"""
|
|
66
|
+
if str(packages) == "" or (
|
|
67
|
+
isinstance(packages, list) and (len(packages) < 1 or all(len(p) < 1 for p in packages))
|
|
68
|
+
):
|
|
69
|
+
host.noop("empty or invalid package list provided to opkg.packages")
|
|
70
|
+
return
|
|
71
|
+
|
|
72
|
+
pkg_list = packages if isinstance(packages, list) else [packages]
|
|
73
|
+
have_equals = ",".join([pkg.split(EQUALS)[0] for pkg in pkg_list if EQUALS in pkg])
|
|
74
|
+
if len(have_equals) > 0:
|
|
75
|
+
raise ValueError(f"opkg does not support version pinning but found for: '{have_equals}'")
|
|
76
|
+
|
|
77
|
+
if update:
|
|
78
|
+
yield from _update._inner()
|
|
79
|
+
|
|
80
|
+
yield from ensure_packages(
|
|
81
|
+
host,
|
|
82
|
+
pkg_list,
|
|
83
|
+
host.get_fact(OpkgPackages),
|
|
84
|
+
present,
|
|
85
|
+
install_command="opkg install",
|
|
86
|
+
upgrade_command="opkg upgrade",
|
|
87
|
+
uninstall_command="opkg remove",
|
|
88
|
+
latest=latest,
|
|
89
|
+
)
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Manage pacman packages. (Arch Linux package manager)
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from pyinfra import host
|
|
8
|
+
from pyinfra.api import operation
|
|
9
|
+
from pyinfra.facts.pacman import PacmanPackages, PacmanUnpackGroup
|
|
10
|
+
|
|
11
|
+
from .util.packaging import ensure_packages
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@operation(is_idempotent=False)
|
|
15
|
+
def upgrade():
|
|
16
|
+
"""
|
|
17
|
+
Upgrades all pacman packages.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
yield "pacman --noconfirm -Su"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
_upgrade = upgrade._inner # noqa: E305
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@operation(is_idempotent=False)
|
|
27
|
+
def update():
|
|
28
|
+
"""
|
|
29
|
+
Updates pacman repositories.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
yield "pacman -Sy"
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
_update = update._inner # noqa: E305
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@operation()
|
|
39
|
+
def packages(
|
|
40
|
+
packages: str | list[str] | None = None,
|
|
41
|
+
present=True,
|
|
42
|
+
update=False,
|
|
43
|
+
upgrade=False,
|
|
44
|
+
):
|
|
45
|
+
"""
|
|
46
|
+
Add/remove pacman packages.
|
|
47
|
+
|
|
48
|
+
+ packages: list of packages to ensure
|
|
49
|
+
+ present: whether the packages should be installed
|
|
50
|
+
+ update: run ``pacman -Sy`` before installing packages
|
|
51
|
+
+ upgrade: run ``pacman -Su`` before installing packages
|
|
52
|
+
|
|
53
|
+
Versions:
|
|
54
|
+
Package versions can be pinned like pacman: ``<pkg>=<version>``.
|
|
55
|
+
|
|
56
|
+
**Example:**
|
|
57
|
+
|
|
58
|
+
.. code:: python
|
|
59
|
+
|
|
60
|
+
from pyinfra.operations import pacman
|
|
61
|
+
pacman.packages(
|
|
62
|
+
name="Install Vim and a plugin",
|
|
63
|
+
packages=["vim-fugitive", "vim"],
|
|
64
|
+
update=True,
|
|
65
|
+
)
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
if update:
|
|
69
|
+
yield from _update()
|
|
70
|
+
|
|
71
|
+
if upgrade:
|
|
72
|
+
yield from _upgrade()
|
|
73
|
+
|
|
74
|
+
yield from ensure_packages(
|
|
75
|
+
host,
|
|
76
|
+
packages,
|
|
77
|
+
host.get_fact(PacmanPackages),
|
|
78
|
+
present,
|
|
79
|
+
install_command="pacman --noconfirm -S",
|
|
80
|
+
uninstall_command="pacman --noconfirm -R",
|
|
81
|
+
expand_package_fact=lambda package: host.get_fact(PacmanUnpackGroup, package=package),
|
|
82
|
+
)
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Manage pip (python) packages. Compatible globally or inside
|
|
3
|
+
a virtualenv (virtual environment).
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from pyinfra import host
|
|
9
|
+
from pyinfra.api import operation
|
|
10
|
+
from pyinfra.facts.files import File
|
|
11
|
+
from pyinfra.facts.pip import PipPackages
|
|
12
|
+
|
|
13
|
+
from . import files
|
|
14
|
+
from .util.packaging import PkgInfo, ensure_packages
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@operation()
|
|
18
|
+
def virtualenv(
|
|
19
|
+
path: str,
|
|
20
|
+
python: str | None = None,
|
|
21
|
+
venv=False,
|
|
22
|
+
site_packages=False,
|
|
23
|
+
always_copy=False,
|
|
24
|
+
present=True,
|
|
25
|
+
):
|
|
26
|
+
"""
|
|
27
|
+
Add/remove Python virtualenvs.
|
|
28
|
+
|
|
29
|
+
+ python: python interpreter to use
|
|
30
|
+
+ venv: use standard venv module instead of virtualenv
|
|
31
|
+
+ site_packages: give access to the global site-packages
|
|
32
|
+
+ always_copy: always copy files rather than symlinking
|
|
33
|
+
+ present: whether the virtualenv should exist
|
|
34
|
+
|
|
35
|
+
**Example:**
|
|
36
|
+
|
|
37
|
+
.. code:: python
|
|
38
|
+
|
|
39
|
+
from pyinfra.operations import pip
|
|
40
|
+
pip.virtualenv(
|
|
41
|
+
name="Create a virtualenv",
|
|
42
|
+
path="/usr/local/bin/venv",
|
|
43
|
+
)
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
# Check for *contents* of a virtualenv, ie don't accept an empty directory
|
|
47
|
+
# as a valid virtualenv but ensure the activate script exists.
|
|
48
|
+
activate_script_path = "{0}/bin/activate".format(path)
|
|
49
|
+
|
|
50
|
+
if present is False:
|
|
51
|
+
if host.get_fact(File, path=activate_script_path):
|
|
52
|
+
yield from files.directory._inner(path, present=False)
|
|
53
|
+
else:
|
|
54
|
+
host.noop("virtualenv {0} does not exist".format(path))
|
|
55
|
+
|
|
56
|
+
if present:
|
|
57
|
+
if not host.get_fact(File, path=activate_script_path):
|
|
58
|
+
# Create missing virtualenv
|
|
59
|
+
command = ["virtualenv"]
|
|
60
|
+
|
|
61
|
+
if venv:
|
|
62
|
+
command = [python or "python", "-m", "venv"]
|
|
63
|
+
|
|
64
|
+
if python and not venv:
|
|
65
|
+
command.append("-p {0}".format(python))
|
|
66
|
+
|
|
67
|
+
if site_packages:
|
|
68
|
+
command.append("--system-site-packages")
|
|
69
|
+
|
|
70
|
+
if always_copy and not venv:
|
|
71
|
+
command.append("--always-copy")
|
|
72
|
+
elif always_copy and venv:
|
|
73
|
+
command.append("--copies")
|
|
74
|
+
|
|
75
|
+
command.append(path)
|
|
76
|
+
|
|
77
|
+
yield " ".join(command)
|
|
78
|
+
else:
|
|
79
|
+
host.noop("virtualenv {0} exists".format(path))
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
_virtualenv = virtualenv._inner # noqa
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
@operation()
|
|
86
|
+
def venv(
|
|
87
|
+
path: str,
|
|
88
|
+
python: str | None = None,
|
|
89
|
+
site_packages=False,
|
|
90
|
+
always_copy=False,
|
|
91
|
+
present=True,
|
|
92
|
+
):
|
|
93
|
+
"""
|
|
94
|
+
Add/remove Python virtualenvs.
|
|
95
|
+
|
|
96
|
+
+ python: python interpreter to use
|
|
97
|
+
+ site_packages: give access to the global site-packages
|
|
98
|
+
+ always_copy: always copy files rather than symlinking
|
|
99
|
+
+ present: whether the virtualenv should exist
|
|
100
|
+
|
|
101
|
+
**Example:**
|
|
102
|
+
|
|
103
|
+
.. code:: python
|
|
104
|
+
|
|
105
|
+
pip.venv(
|
|
106
|
+
name="Create a virtualenv",
|
|
107
|
+
path="/usr/local/bin/venv",
|
|
108
|
+
)
|
|
109
|
+
"""
|
|
110
|
+
|
|
111
|
+
yield from _virtualenv(
|
|
112
|
+
venv=True,
|
|
113
|
+
path=path,
|
|
114
|
+
python=python,
|
|
115
|
+
site_packages=site_packages,
|
|
116
|
+
always_copy=always_copy,
|
|
117
|
+
present=present,
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
@operation()
|
|
122
|
+
def packages(
|
|
123
|
+
packages: str | list[str] | None = None,
|
|
124
|
+
present=True,
|
|
125
|
+
latest=False,
|
|
126
|
+
requirements: str | None = None,
|
|
127
|
+
pip="pip",
|
|
128
|
+
virtualenv: str | None = None,
|
|
129
|
+
virtualenv_kwargs: dict | None = None,
|
|
130
|
+
extra_install_args: str | None = None,
|
|
131
|
+
):
|
|
132
|
+
"""
|
|
133
|
+
Install/remove/update pip packages.
|
|
134
|
+
|
|
135
|
+
+ packages: list of packages to ensure
|
|
136
|
+
+ present: whether the packages should be installed
|
|
137
|
+
+ latest: whether to upgrade packages without a specified version
|
|
138
|
+
+ requirements: location of requirements file to install/uninstall
|
|
139
|
+
+ pip: name or path of the pip directory to use
|
|
140
|
+
+ virtualenv: root directory of virtualenv to work in
|
|
141
|
+
+ virtualenv_kwargs: dictionary of arguments to pass to ``pip.virtualenv``
|
|
142
|
+
+ extra_install_args: additional arguments to the pip install command
|
|
143
|
+
|
|
144
|
+
Virtualenv:
|
|
145
|
+
This will be created if it does not exist already. ``virtualenv_kwargs``
|
|
146
|
+
will be passed to ``pip.virtualenv`` which can be used to control how
|
|
147
|
+
the env is created.
|
|
148
|
+
|
|
149
|
+
Versions:
|
|
150
|
+
Package versions can be pinned like pip: ``<pkg>==<version>``.
|
|
151
|
+
|
|
152
|
+
**Example:**
|
|
153
|
+
|
|
154
|
+
.. code:: python
|
|
155
|
+
|
|
156
|
+
pip.packages(
|
|
157
|
+
name="Install pyinfra into a virtualenv",
|
|
158
|
+
packages=["pyinfra"],
|
|
159
|
+
virtualenv="/usr/local/bin/venv",
|
|
160
|
+
)
|
|
161
|
+
"""
|
|
162
|
+
|
|
163
|
+
virtualenv_kwargs = virtualenv_kwargs or {}
|
|
164
|
+
|
|
165
|
+
# Ensure any virtualenv
|
|
166
|
+
if virtualenv:
|
|
167
|
+
yield from _virtualenv(virtualenv, **virtualenv_kwargs)
|
|
168
|
+
|
|
169
|
+
# And update pip path
|
|
170
|
+
virtualenv = virtualenv.rstrip("/")
|
|
171
|
+
pip = "{0}/bin/{1}".format(virtualenv, pip)
|
|
172
|
+
|
|
173
|
+
install_command_args = [pip, "install"]
|
|
174
|
+
if extra_install_args:
|
|
175
|
+
install_command_args.append(extra_install_args)
|
|
176
|
+
install_command = " ".join(install_command_args)
|
|
177
|
+
|
|
178
|
+
upgrade_command = "{0} --upgrade".format(install_command)
|
|
179
|
+
uninstall_command = " ".join([pip, "uninstall", "--yes"])
|
|
180
|
+
|
|
181
|
+
# (un)Install requirements
|
|
182
|
+
if requirements is not None:
|
|
183
|
+
if present:
|
|
184
|
+
yield "{0} -r {1}".format(upgrade_command if latest else install_command, requirements)
|
|
185
|
+
else:
|
|
186
|
+
yield "{0} -r {1}".format(uninstall_command, requirements)
|
|
187
|
+
|
|
188
|
+
# Handle passed in packages
|
|
189
|
+
if packages:
|
|
190
|
+
if isinstance(packages, str):
|
|
191
|
+
packages = [packages]
|
|
192
|
+
# PEP-0426 states that Python packages should be compared using lowercase, so lowercase the
|
|
193
|
+
# current packages. PkgInfo.from_pep508 takes care of the package name
|
|
194
|
+
current_packages = host.get_fact(PipPackages, pip=pip)
|
|
195
|
+
current_packages = {pkg.lower(): versions for pkg, versions in current_packages.items()}
|
|
196
|
+
|
|
197
|
+
yield from ensure_packages(
|
|
198
|
+
host,
|
|
199
|
+
list(filter(None, (PkgInfo.from_pep508(package) for package in packages))),
|
|
200
|
+
current_packages,
|
|
201
|
+
present,
|
|
202
|
+
install_command=install_command,
|
|
203
|
+
uninstall_command=uninstall_command,
|
|
204
|
+
upgrade_command=upgrade_command,
|
|
205
|
+
latest=latest,
|
|
206
|
+
)
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Manage pipx (python) applications.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Optional, Union
|
|
6
|
+
|
|
7
|
+
from pyinfra import host
|
|
8
|
+
from pyinfra.api import operation
|
|
9
|
+
from pyinfra.facts.pipx import PipxEnvironment, PipxPackages
|
|
10
|
+
from pyinfra.facts.server import Path
|
|
11
|
+
|
|
12
|
+
from .util.packaging import PkgInfo, ensure_packages
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@operation()
|
|
16
|
+
def packages(
|
|
17
|
+
packages: Optional[Union[str, list[str]]] = None,
|
|
18
|
+
present=True,
|
|
19
|
+
latest=False,
|
|
20
|
+
extra_args: Optional[str] = None,
|
|
21
|
+
):
|
|
22
|
+
"""
|
|
23
|
+
Install/remove/update pipx packages.
|
|
24
|
+
|
|
25
|
+
+ packages: list of packages (PEP-508 format) to ensure
|
|
26
|
+
+ present: whether the packages should be installed
|
|
27
|
+
+ latest: whether to upgrade packages without a specified version
|
|
28
|
+
+ extra_args: additional arguments to the pipx command
|
|
29
|
+
|
|
30
|
+
Versions:
|
|
31
|
+
Package versions can be pinned like pip: ``<pkg>==<version>``.
|
|
32
|
+
|
|
33
|
+
**Example:**
|
|
34
|
+
|
|
35
|
+
.. code:: python
|
|
36
|
+
|
|
37
|
+
from pyinfra.operations import pipx
|
|
38
|
+
pipx.packages(
|
|
39
|
+
name="Install ",
|
|
40
|
+
packages=["pyinfra"],
|
|
41
|
+
)
|
|
42
|
+
"""
|
|
43
|
+
if packages is None:
|
|
44
|
+
host.noop("no package list provided to pipx.packages")
|
|
45
|
+
return
|
|
46
|
+
|
|
47
|
+
prep_install_command = ["pipx", "install"]
|
|
48
|
+
|
|
49
|
+
if extra_args:
|
|
50
|
+
prep_install_command.append(extra_args)
|
|
51
|
+
install_command = " ".join(prep_install_command)
|
|
52
|
+
|
|
53
|
+
uninstall_command = "pipx uninstall"
|
|
54
|
+
upgrade_command = "pipx upgrade"
|
|
55
|
+
|
|
56
|
+
# PEP-0426 states that Python packages should be compared using lowercase, so lowercase the
|
|
57
|
+
# current packages. PkgInfo.from_pep508 takes care of it for the package names
|
|
58
|
+
current_packages = {
|
|
59
|
+
pkg.lower(): version for pkg, version in host.get_fact(PipxPackages).items()
|
|
60
|
+
}
|
|
61
|
+
if isinstance(packages, str):
|
|
62
|
+
packages = [packages]
|
|
63
|
+
|
|
64
|
+
# pipx support only one package name at a time
|
|
65
|
+
for package in packages:
|
|
66
|
+
if (pkg_info := PkgInfo.from_pep508(package)) is None:
|
|
67
|
+
continue # from_pep508 logged a warning
|
|
68
|
+
yield from ensure_packages(
|
|
69
|
+
host,
|
|
70
|
+
[pkg_info],
|
|
71
|
+
current_packages,
|
|
72
|
+
present,
|
|
73
|
+
install_command=install_command,
|
|
74
|
+
uninstall_command=uninstall_command,
|
|
75
|
+
upgrade_command=upgrade_command,
|
|
76
|
+
latest=latest,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
@operation()
|
|
81
|
+
def upgrade_all():
|
|
82
|
+
"""
|
|
83
|
+
Upgrade all pipx packages.
|
|
84
|
+
"""
|
|
85
|
+
yield "pipx upgrade-all"
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
@operation()
|
|
89
|
+
def ensure_path():
|
|
90
|
+
"""
|
|
91
|
+
Ensure pipx bin dir is in the PATH.
|
|
92
|
+
"""
|
|
93
|
+
|
|
94
|
+
# Fetch the current user's PATH
|
|
95
|
+
path = host.get_fact(Path)
|
|
96
|
+
# Fetch the pipx environment variables
|
|
97
|
+
pipx_env = host.get_fact(PipxEnvironment)
|
|
98
|
+
|
|
99
|
+
# If the pipx bin dir is already in the user's PATH, we're done
|
|
100
|
+
if "PIPX_BIN_DIR" in pipx_env and pipx_env["PIPX_BIN_DIR"] in path.split(":"):
|
|
101
|
+
host.noop("pipx bin dir is already in the PATH")
|
|
102
|
+
else:
|
|
103
|
+
yield "pipx ensurepath"
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Manage BSD packages and repositories. Note that BSD package names are case-sensitive.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from pyinfra import host
|
|
8
|
+
from pyinfra.api import operation
|
|
9
|
+
from pyinfra.facts.files import File
|
|
10
|
+
from pyinfra.facts.pkg import PkgPackages
|
|
11
|
+
from pyinfra.facts.server import Arch, Os, OsVersion, Which
|
|
12
|
+
|
|
13
|
+
from .util.packaging import ensure_packages
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@operation()
|
|
17
|
+
def packages(packages: str | list[str] | None = None, present=True, pkg_path: str | None = None):
|
|
18
|
+
"""
|
|
19
|
+
Install/remove/update pkg packages. This will use ``pkg ...`` where available
|
|
20
|
+
(FreeBSD) and the ``pkg_*`` variants elsewhere.
|
|
21
|
+
|
|
22
|
+
+ packages: list of packages to ensure
|
|
23
|
+
+ present: whether the packages should be installed
|
|
24
|
+
+ pkg_path: the PKG_PATH environment variable to set
|
|
25
|
+
|
|
26
|
+
pkg_path:
|
|
27
|
+
By default this is autogenerated as follows (tested/working for OpenBSD):
|
|
28
|
+
``http://ftp.<OS>.org/pub/<OS>/<VERSION>/packages/<ARCH>/``. Note that OpenBSD's
|
|
29
|
+
official mirrors only hold the latest two versions packages.
|
|
30
|
+
|
|
31
|
+
NetBSD/FreeBSD helpfully use their own directory structures, so the default won't
|
|
32
|
+
work.
|
|
33
|
+
|
|
34
|
+
**Example:**
|
|
35
|
+
|
|
36
|
+
.. code:: python
|
|
37
|
+
|
|
38
|
+
from pyinfra.operations import pkg
|
|
39
|
+
pkg.packages(
|
|
40
|
+
name="Install Vim and Vim Addon Manager",
|
|
41
|
+
packages=["vim-addon-manager", "vim"],
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
if present is True:
|
|
47
|
+
if not pkg_path and not host.get_fact(File, path="/etc/installurl"):
|
|
48
|
+
host_os = host.get_fact(Os) or ""
|
|
49
|
+
pkg_path = "http://ftp.{http}.org/pub/{os}/{version}/packages/{arch}/".format(
|
|
50
|
+
http=host_os.lower(),
|
|
51
|
+
os=host_os,
|
|
52
|
+
version=host.get_fact(OsVersion),
|
|
53
|
+
arch=host.get_fact(Arch),
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
# FreeBSD used "pkg ..." and OpenBSD uses "pkg_[add|delete]"
|
|
57
|
+
is_pkg = host.get_fact(Which, command="pkg")
|
|
58
|
+
install_command = "pkg install -y" if is_pkg else "pkg_add"
|
|
59
|
+
uninstall_command = "pkg delete -y" if is_pkg else "pkg_delete"
|
|
60
|
+
|
|
61
|
+
if pkg_path:
|
|
62
|
+
install_command = "PKG_PATH={0} {1}".format(pkg_path, install_command)
|
|
63
|
+
|
|
64
|
+
yield from ensure_packages(
|
|
65
|
+
host,
|
|
66
|
+
packages,
|
|
67
|
+
host.get_fact(PkgPackages),
|
|
68
|
+
present,
|
|
69
|
+
install_command=install_command,
|
|
70
|
+
uninstall_command=uninstall_command,
|
|
71
|
+
)
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Manage pkgin packages.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from pyinfra import host
|
|
8
|
+
from pyinfra.api import operation
|
|
9
|
+
from pyinfra.facts.pkgin import PkginPackages
|
|
10
|
+
|
|
11
|
+
from .util.packaging import ensure_packages
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@operation(is_idempotent=False)
|
|
15
|
+
def upgrade():
|
|
16
|
+
"""
|
|
17
|
+
Upgrades all pkgin packages.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
yield "pkgin -y upgrade"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
_upgrade = upgrade._inner # noqa: E305
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@operation(is_idempotent=False)
|
|
27
|
+
def update():
|
|
28
|
+
"""
|
|
29
|
+
Updates pkgin repositories.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
yield "pkgin -y update"
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
_update = update._inner # noqa: E305
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@operation()
|
|
39
|
+
def packages(
|
|
40
|
+
packages: str | list[str] | None = None,
|
|
41
|
+
present=True,
|
|
42
|
+
latest=False,
|
|
43
|
+
update=False,
|
|
44
|
+
upgrade=False,
|
|
45
|
+
):
|
|
46
|
+
"""
|
|
47
|
+
Add/remove/update pkgin packages.
|
|
48
|
+
|
|
49
|
+
+ packages: list of packages to ensure
|
|
50
|
+
+ present: whether the packages should be installed
|
|
51
|
+
+ latest: whether to upgrade packages without a specified version
|
|
52
|
+
+ update: run ``pkgin update`` before installing packages
|
|
53
|
+
+ upgrade: run ``pkgin upgrade`` before installing packages
|
|
54
|
+
|
|
55
|
+
**Examples:**
|
|
56
|
+
|
|
57
|
+
.. code:: python
|
|
58
|
+
|
|
59
|
+
from pyinfra.operations import pkgin
|
|
60
|
+
# Update package list and install packages
|
|
61
|
+
pkgin.packages(
|
|
62
|
+
name="Install tmux and Vim",
|
|
63
|
+
packages=["tmux", "vim"],
|
|
64
|
+
update=True,
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
# Install the latest versions of packages (always check)
|
|
68
|
+
pkgin.packages(
|
|
69
|
+
name="Install latest Vim",
|
|
70
|
+
packages=["vim"],
|
|
71
|
+
latest=True,
|
|
72
|
+
)
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
if update:
|
|
76
|
+
yield from _update()
|
|
77
|
+
|
|
78
|
+
if upgrade:
|
|
79
|
+
yield from _upgrade()
|
|
80
|
+
|
|
81
|
+
# TODO support glob for specific versions (it isn't as simple
|
|
82
|
+
# as apt-s, as pkgin supports something like 'mysql-server>=5.6<5.7')
|
|
83
|
+
yield from ensure_packages(
|
|
84
|
+
host,
|
|
85
|
+
packages,
|
|
86
|
+
host.get_fact(PkginPackages),
|
|
87
|
+
present,
|
|
88
|
+
install_command="pkgin -y install",
|
|
89
|
+
uninstall_command="pkgin -y remove",
|
|
90
|
+
upgrade_command="pkgin -y upgrade",
|
|
91
|
+
latest=latest,
|
|
92
|
+
)
|