from pyinfra import host, logger
from pyinfra.api import operation, OperationError, StringCommand, QuoteString
from pyinfra.facts.server import Which
from pyinfra.facts.files import File
@operation()
def download(
src: str,
dest: str,
user: str | None = None,
group: str | None = None,
mode: str | None = None,
force: bool = False,
sha256sum: str | None = None,
):
"""
Download files from remote locations using curl or wget.
+ src: source URL of the file
+ dest: where to save the file
+ user: user to own the file
+ group: group to own the file
+ mode: permissions of the file
+ force: always download the file, even if it already exists
+ sha256sum: sha256 hash to checksum the downloaded file against
**Example:**
.. code:: python
from pyinfra.operations import files
files.download(
name="Download config file",
src="https://example.com/config.yml",
dest="/etc/app/config.yml",
mode="644",
)
"""
info = host.get_fact(File, path=dest)
# Destination is a directory?
if info is False:
raise OperationError(
f"Destination {dest} already exists and is not a file"
)
# Determine if we need to download
download = force or info is None
if sha256sum and info:
from pyinfra.facts.files import Sha256File
if sha256sum != host.get_fact(Sha256File, path=dest):
download = True
if download:
temp_file = host.get_temp_filename(dest)
# Try curl first, then wget
if host.get_fact(Which, command="curl"):
yield StringCommand(
"curl", "-sSLf", QuoteString(src), "-o", QuoteString(temp_file)
)
elif host.get_fact(Which, command="wget"):
yield StringCommand(
"wget", "-q", QuoteString(src), "-O", QuoteString(temp_file)
)
else:
raise OperationError("Neither curl nor wget is available")
yield StringCommand("mv", QuoteString(temp_file), QuoteString(dest))
if user or group:
from pyinfra.operations.util.files import chown
yield chown(dest, user, group)
if mode:
from pyinfra.operations.util.files import chmod
yield chmod(dest, mode)
if sha256sum:
yield (
f"(sha256sum {dest} | grep {sha256sum}) || "
f"(echo 'SHA256 did not match!' && exit 1)"
)
else:
host.noop(f"file {dest} has already been downloaded")