mirror of
https://github.com/containers/podman-compose.git
synced 2025-04-23 17:09:23 +02:00
Format codebase with ruff
Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
This commit is contained in:
parent
a5c354d60b
commit
a967cab02b
@ -50,11 +50,7 @@ def is_dict(dict_object):
|
|||||||
|
|
||||||
|
|
||||||
def is_list(list_object):
|
def is_list(list_object):
|
||||||
return (
|
return not is_str(list_object) and not is_dict(list_object) and hasattr(list_object, "__iter__")
|
||||||
not is_str(list_object)
|
|
||||||
and not is_dict(list_object)
|
|
||||||
and hasattr(list_object, "__iter__")
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# identity filter
|
# identity filter
|
||||||
@ -170,9 +166,7 @@ def parse_short_mount(mount_str, basedir):
|
|||||||
# User-relative path
|
# User-relative path
|
||||||
# - ~/configs:/etc/configs/:ro
|
# - ~/configs:/etc/configs/:ro
|
||||||
mount_type = "bind"
|
mount_type = "bind"
|
||||||
mount_src = os.path.abspath(
|
mount_src = os.path.abspath(os.path.join(basedir, os.path.expanduser(mount_src)))
|
||||||
os.path.join(basedir, os.path.expanduser(mount_src))
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
# Named volume
|
# Named volume
|
||||||
# - datavolume:/var/lib/mysql
|
# - datavolume:/var/lib/mysql
|
||||||
@ -225,13 +219,11 @@ def fix_mount_dict(compose, mount_dict, proj_name, srv_name):
|
|||||||
# handle anonymous or implied volume
|
# handle anonymous or implied volume
|
||||||
if not source:
|
if not source:
|
||||||
# missing source
|
# missing source
|
||||||
vol["name"] = "_".join(
|
vol["name"] = "_".join([
|
||||||
[
|
proj_name,
|
||||||
proj_name,
|
srv_name,
|
||||||
srv_name,
|
hashlib.sha256(mount_dict["target"].encode("utf-8")).hexdigest(),
|
||||||
hashlib.sha256(mount_dict["target"].encode("utf-8")).hexdigest(),
|
])
|
||||||
]
|
|
||||||
)
|
|
||||||
elif not name:
|
elif not name:
|
||||||
external = vol.get("external", None)
|
external = vol.get("external", None)
|
||||||
if isinstance(external, dict):
|
if isinstance(external, dict):
|
||||||
@ -382,9 +374,7 @@ async def assert_volume(compose, mount_dict):
|
|||||||
if mount_dict["type"] == "bind":
|
if mount_dict["type"] == "bind":
|
||||||
basedir = os.path.realpath(compose.dirname)
|
basedir = os.path.realpath(compose.dirname)
|
||||||
mount_src = mount_dict["source"]
|
mount_src = mount_dict["source"]
|
||||||
mount_src = os.path.realpath(
|
mount_src = os.path.realpath(os.path.join(basedir, os.path.expanduser(mount_src)))
|
||||||
os.path.join(basedir, os.path.expanduser(mount_src))
|
|
||||||
)
|
|
||||||
if not os.path.exists(mount_src):
|
if not os.path.exists(mount_src):
|
||||||
try:
|
try:
|
||||||
os.makedirs(mount_src, exist_ok=True)
|
os.makedirs(mount_src, exist_ok=True)
|
||||||
@ -425,9 +415,7 @@ async def assert_volume(compose, mount_dict):
|
|||||||
_ = (await compose.podman.output([], "volume", ["inspect", vol_name])).decode("utf-8")
|
_ = (await compose.podman.output([], "volume", ["inspect", vol_name])).decode("utf-8")
|
||||||
|
|
||||||
|
|
||||||
def mount_desc_to_mount_args(
|
def mount_desc_to_mount_args(compose, mount_desc, srv_name, cnt_name): # pylint: disable=unused-argument
|
||||||
compose, mount_desc, srv_name, cnt_name
|
|
||||||
): # pylint: disable=unused-argument
|
|
||||||
mount_type = mount_desc.get("type", None)
|
mount_type = mount_desc.get("type", None)
|
||||||
vol = mount_desc.get("_vol", None) if mount_type == "volume" else None
|
vol = mount_desc.get("_vol", None) if mount_type == "volume" else None
|
||||||
source = vol["name"] if vol else mount_desc.get("source", None)
|
source = vol["name"] if vol else mount_desc.get("source", None)
|
||||||
@ -475,9 +463,7 @@ def container_to_ulimit_args(cnt, podman_args):
|
|||||||
podman_args.extend(["--ulimit", i])
|
podman_args.extend(["--ulimit", i])
|
||||||
|
|
||||||
|
|
||||||
def mount_desc_to_volume_args(
|
def mount_desc_to_volume_args(compose, mount_desc, srv_name, cnt_name): # pylint: disable=unused-argument
|
||||||
compose, mount_desc, srv_name, cnt_name
|
|
||||||
): # pylint: disable=unused-argument
|
|
||||||
mount_type = mount_desc["type"]
|
mount_type = mount_desc["type"]
|
||||||
if mount_type not in ("bind", "volume"):
|
if mount_type not in ("bind", "volume"):
|
||||||
raise ValueError("unknown mount type:" + mount_type)
|
raise ValueError("unknown mount type:" + mount_type)
|
||||||
@ -488,13 +474,9 @@ def mount_desc_to_volume_args(
|
|||||||
target = mount_desc["target"]
|
target = mount_desc["target"]
|
||||||
opts = []
|
opts = []
|
||||||
|
|
||||||
propagations = set(
|
propagations = set(filteri(mount_desc.get(mount_type, {}).get("propagation", "").split(",")))
|
||||||
filteri(mount_desc.get(mount_type, {}).get("propagation", "").split(","))
|
|
||||||
)
|
|
||||||
if mount_type != "bind":
|
if mount_type != "bind":
|
||||||
propagations.update(
|
propagations.update(filteri(mount_desc.get("bind", {}).get("propagation", "").split(",")))
|
||||||
filteri(mount_desc.get("bind", {}).get("propagation", "").split(","))
|
|
||||||
)
|
|
||||||
opts.extend(propagations)
|
opts.extend(propagations)
|
||||||
# --volume, -v[=[[SOURCE-VOLUME|HOST-DIR:]CONTAINER-DIR[:OPTIONS]]]
|
# --volume, -v[=[[SOURCE-VOLUME|HOST-DIR:]CONTAINER-DIR[:OPTIONS]]]
|
||||||
# [rw|ro]
|
# [rw|ro]
|
||||||
@ -554,9 +536,7 @@ async def get_mount_args(compose, cnt, volume):
|
|||||||
def get_secret_args(compose, cnt, secret):
|
def get_secret_args(compose, cnt, secret):
|
||||||
secret_name = secret if is_str(secret) else secret.get("source", None)
|
secret_name = secret if is_str(secret) else secret.get("source", None)
|
||||||
if not secret_name or secret_name not in compose.declared_secrets.keys():
|
if not secret_name or secret_name not in compose.declared_secrets.keys():
|
||||||
raise ValueError(
|
raise ValueError(f'ERROR: undeclared secret: "{secret}", service: {cnt["_service"]}')
|
||||||
f'ERROR: undeclared secret: "{secret}", service: {cnt["_service"]}'
|
|
||||||
)
|
|
||||||
declared_secret = compose.declared_secrets[secret_name]
|
declared_secret = compose.declared_secrets[secret_name]
|
||||||
|
|
||||||
source_file = declared_secret.get("file", None)
|
source_file = declared_secret.get("file", None)
|
||||||
@ -577,9 +557,7 @@ def get_secret_args(compose, cnt, secret):
|
|||||||
else:
|
else:
|
||||||
dest_file = target
|
dest_file = target
|
||||||
basedir = compose.dirname
|
basedir = compose.dirname
|
||||||
source_file = os.path.realpath(
|
source_file = os.path.realpath(os.path.join(basedir, os.path.expanduser(source_file)))
|
||||||
os.path.join(basedir, os.path.expanduser(source_file))
|
|
||||||
)
|
|
||||||
volume_ref = ["--volume", f"{source_file}:{dest_file}:ro,rprivate,rbind"]
|
volume_ref = ["--volume", f"{source_file}:{dest_file}:ro,rprivate,rbind"]
|
||||||
if uid or gid or mode:
|
if uid or gid or mode:
|
||||||
sec = target if target else secret_name
|
sec = target if target else secret_name
|
||||||
@ -620,9 +598,7 @@ def get_secret_args(compose, cnt, secret):
|
|||||||
return ["--secret", "{}{}".format(secret_name, secret_opts)]
|
return ["--secret", "{}{}".format(secret_name, secret_opts)]
|
||||||
|
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
'ERROR: unparsable secret: "{}", service: "{}"'.format(
|
'ERROR: unparsable secret: "{}", service: "{}"'.format(secret_name, cnt["_service"])
|
||||||
secret_name, cnt["_service"]
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -647,35 +623,27 @@ def container_to_res_args(cnt, podman_args):
|
|||||||
# add args
|
# add args
|
||||||
cpus = cpus_limit_v3 or cpus_limit_v2
|
cpus = cpus_limit_v3 or cpus_limit_v2
|
||||||
if cpus:
|
if cpus:
|
||||||
podman_args.extend(
|
podman_args.extend((
|
||||||
(
|
"--cpus",
|
||||||
"--cpus",
|
str(cpus),
|
||||||
str(cpus),
|
))
|
||||||
)
|
|
||||||
)
|
|
||||||
if cpu_shares_v2:
|
if cpu_shares_v2:
|
||||||
podman_args.extend(
|
podman_args.extend((
|
||||||
(
|
"--cpu-shares",
|
||||||
"--cpu-shares",
|
str(cpu_shares_v2),
|
||||||
str(cpu_shares_v2),
|
))
|
||||||
)
|
|
||||||
)
|
|
||||||
mem = mem_limit_v3 or mem_limit_v2
|
mem = mem_limit_v3 or mem_limit_v2
|
||||||
if mem:
|
if mem:
|
||||||
podman_args.extend(
|
podman_args.extend((
|
||||||
(
|
"-m",
|
||||||
"-m",
|
str(mem).lower(),
|
||||||
str(mem).lower(),
|
))
|
||||||
)
|
|
||||||
)
|
|
||||||
mem_res = mem_res_v3 or mem_res_v2
|
mem_res = mem_res_v3 or mem_res_v2
|
||||||
if mem_res:
|
if mem_res:
|
||||||
podman_args.extend(
|
podman_args.extend((
|
||||||
(
|
"--memory-reservation",
|
||||||
"--memory-reservation",
|
str(mem_res).lower(),
|
||||||
str(mem_res).lower(),
|
))
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def port_dict_to_str(port_desc):
|
def port_dict_to_str(port_desc):
|
||||||
@ -731,16 +699,12 @@ async def assert_cnt_nets(compose, cnt):
|
|||||||
is_ext = net_desc.get("external", None)
|
is_ext = net_desc.get("external", None)
|
||||||
ext_desc = is_ext if is_dict(is_ext) else {}
|
ext_desc = is_ext if is_dict(is_ext) else {}
|
||||||
default_net_name = net if is_ext else f"{proj_name}_{net}"
|
default_net_name = net if is_ext else f"{proj_name}_{net}"
|
||||||
net_name = (
|
net_name = ext_desc.get("name", None) or net_desc.get("name", None) or default_net_name
|
||||||
ext_desc.get("name", None) or net_desc.get("name", None) or default_net_name
|
|
||||||
)
|
|
||||||
try:
|
try:
|
||||||
await compose.podman.output([], "network", ["exists", net_name])
|
await compose.podman.output([], "network", ["exists", net_name])
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
if is_ext:
|
if is_ext:
|
||||||
raise RuntimeError(
|
raise RuntimeError(f"External network [{net_name}] does not exists") from e
|
||||||
f"External network [{net_name}] does not exists"
|
|
||||||
) from e
|
|
||||||
args = [
|
args = [
|
||||||
"create",
|
"create",
|
||||||
"--label",
|
"--label",
|
||||||
@ -843,12 +807,10 @@ def get_net_args(compose, cnt):
|
|||||||
if not ip6:
|
if not ip6:
|
||||||
ip6 = net_value.get("ipv6_address", None)
|
ip6 = net_value.get("ipv6_address", None)
|
||||||
net_priority = net_value.get("priority", 0)
|
net_priority = net_value.get("priority", 0)
|
||||||
prioritized_cnt_nets.append(
|
prioritized_cnt_nets.append((
|
||||||
(
|
net_priority,
|
||||||
net_priority,
|
net_key,
|
||||||
net_key,
|
))
|
||||||
)
|
|
||||||
)
|
|
||||||
# sort dict by priority
|
# sort dict by priority
|
||||||
prioritized_cnt_nets.sort(reverse=True)
|
prioritized_cnt_nets.sort(reverse=True)
|
||||||
cnt_nets = [net_key for _, net_key in prioritized_cnt_nets]
|
cnt_nets = [net_key for _, net_key in prioritized_cnt_nets]
|
||||||
@ -859,9 +821,7 @@ def get_net_args(compose, cnt):
|
|||||||
is_ext = net_desc.get("external", None)
|
is_ext = net_desc.get("external", None)
|
||||||
ext_desc = is_ext if is_dict(is_ext) else {}
|
ext_desc = is_ext if is_dict(is_ext) else {}
|
||||||
default_net_name = net if is_ext else f"{proj_name}_{net}"
|
default_net_name = net if is_ext else f"{proj_name}_{net}"
|
||||||
net_name = (
|
net_name = ext_desc.get("name", None) or net_desc.get("name", None) or default_net_name
|
||||||
ext_desc.get("name", None) or net_desc.get("name", None) or default_net_name
|
|
||||||
)
|
|
||||||
net_names.append(net_name)
|
net_names.append(net_name)
|
||||||
net_names_str = ",".join(net_names)
|
net_names_str = ",".join(net_names)
|
||||||
|
|
||||||
@ -874,11 +834,7 @@ def get_net_args(compose, cnt):
|
|||||||
is_ext = net_desc.get("external", None)
|
is_ext = net_desc.get("external", None)
|
||||||
ext_desc = is_ext if is_dict(is_ext) else {}
|
ext_desc = is_ext if is_dict(is_ext) else {}
|
||||||
default_net_name = net_ if is_ext else f"{proj_name}_{net_}"
|
default_net_name = net_ if is_ext else f"{proj_name}_{net_}"
|
||||||
net_name = (
|
net_name = ext_desc.get("name", None) or net_desc.get("name", None) or default_net_name
|
||||||
ext_desc.get("name", None)
|
|
||||||
or net_desc.get("name", None)
|
|
||||||
or default_net_name
|
|
||||||
)
|
|
||||||
|
|
||||||
ipv4 = multiple_nets[net_].get("ipv4_address", None)
|
ipv4 = multiple_nets[net_].get("ipv4_address", None)
|
||||||
ipv6 = multiple_nets[net_].get("ipv6_address", None)
|
ipv6 = multiple_nets[net_].get("ipv6_address", None)
|
||||||
@ -890,9 +846,7 @@ def get_net_args(compose, cnt):
|
|||||||
net_args.extend(["--network", f"{net_name}:ip={ipv4}"])
|
net_args.extend(["--network", f"{net_name}:ip={ipv4}"])
|
||||||
else:
|
else:
|
||||||
if is_bridge:
|
if is_bridge:
|
||||||
net_args.extend(
|
net_args.extend(["--net", net_names_str, "--network-alias", ",".join(aliases)])
|
||||||
["--net", net_names_str, "--network-alias", ",".join(aliases)]
|
|
||||||
)
|
|
||||||
if ip:
|
if ip:
|
||||||
net_args.append(f"--ip={ip}")
|
net_args.append(f"--ip={ip}")
|
||||||
if ip6:
|
if ip6:
|
||||||
@ -1041,9 +995,10 @@ async def container_to_args(compose, cnt, detached=True):
|
|||||||
# If it's a string, it's equivalent to specifying CMD-SHELL
|
# If it's a string, it's equivalent to specifying CMD-SHELL
|
||||||
if is_str(healthcheck_test):
|
if is_str(healthcheck_test):
|
||||||
# podman does not add shell to handle command with whitespace
|
# podman does not add shell to handle command with whitespace
|
||||||
podman_args.extend(
|
podman_args.extend([
|
||||||
["--healthcheck-command", "/bin/sh -c " + cmd_quote(healthcheck_test)]
|
"--healthcheck-command",
|
||||||
)
|
"/bin/sh -c " + cmd_quote(healthcheck_test),
|
||||||
|
])
|
||||||
elif is_list(healthcheck_test):
|
elif is_list(healthcheck_test):
|
||||||
healthcheck_test = healthcheck_test.copy()
|
healthcheck_test = healthcheck_test.copy()
|
||||||
# If it's a list, first item is either NONE, CMD or CMD-SHELL.
|
# If it's a list, first item is either NONE, CMD or CMD-SHELL.
|
||||||
@ -1158,7 +1113,13 @@ def flat_deps(services, with_extends=False):
|
|||||||
|
|
||||||
|
|
||||||
class Podman:
|
class Podman:
|
||||||
def __init__(self, compose, podman_path="podman", dry_run=False, semaphore: asyncio.Semaphore = asyncio.Semaphore(sys.maxsize)):
|
def __init__(
|
||||||
|
self,
|
||||||
|
compose,
|
||||||
|
podman_path="podman",
|
||||||
|
dry_run=False,
|
||||||
|
semaphore: asyncio.Semaphore = asyncio.Semaphore(sys.maxsize),
|
||||||
|
):
|
||||||
self.compose = compose
|
self.compose = compose
|
||||||
self.podman_path = podman_path
|
self.podman_path = podman_path
|
||||||
self.dry_run = dry_run
|
self.dry_run = dry_run
|
||||||
@ -1171,9 +1132,7 @@ class Podman:
|
|||||||
cmd_ls = [self.podman_path, *podman_args, cmd] + xargs + cmd_args
|
cmd_ls = [self.podman_path, *podman_args, cmd] + xargs + cmd_args
|
||||||
log(cmd_ls)
|
log(cmd_ls)
|
||||||
p = await asyncio.subprocess.create_subprocess_exec(
|
p = await asyncio.subprocess.create_subprocess_exec(
|
||||||
*cmd_ls,
|
*cmd_ls, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE
|
||||||
stdout=asyncio.subprocess.PIPE,
|
|
||||||
stderr=asyncio.subprocess.PIPE
|
|
||||||
)
|
)
|
||||||
|
|
||||||
stdout_data, stderr_data = await p.communicate()
|
stdout_data, stderr_data = await p.communicate()
|
||||||
@ -1202,7 +1161,7 @@ class Podman:
|
|||||||
log_formatter=None,
|
log_formatter=None,
|
||||||
*,
|
*,
|
||||||
# Intentionally mutable default argument to hold references to tasks
|
# Intentionally mutable default argument to hold references to tasks
|
||||||
task_reference=set()
|
task_reference=set(),
|
||||||
) -> int:
|
) -> int:
|
||||||
async with self.semaphore:
|
async with self.semaphore:
|
||||||
cmd_args = list(map(str, cmd_args or []))
|
cmd_args = list(map(str, cmd_args or []))
|
||||||
@ -1258,18 +1217,20 @@ class Podman:
|
|||||||
async def volume_ls(self, proj=None):
|
async def volume_ls(self, proj=None):
|
||||||
if not proj:
|
if not proj:
|
||||||
proj = self.compose.project_name
|
proj = self.compose.project_name
|
||||||
output = (await self.output(
|
output = (
|
||||||
[],
|
await self.output(
|
||||||
"volume",
|
[],
|
||||||
[
|
"volume",
|
||||||
"ls",
|
[
|
||||||
"--noheading",
|
"ls",
|
||||||
"--filter",
|
"--noheading",
|
||||||
f"label=io.podman.compose.project={proj}",
|
"--filter",
|
||||||
"--format",
|
f"label=io.podman.compose.project={proj}",
|
||||||
"{{.Name}}",
|
"--format",
|
||||||
],
|
"{{.Name}}",
|
||||||
)).decode("utf-8")
|
],
|
||||||
|
)
|
||||||
|
).decode("utf-8")
|
||||||
volumes = output.splitlines()
|
volumes = output.splitlines()
|
||||||
return volumes
|
return volumes
|
||||||
|
|
||||||
@ -1333,9 +1294,7 @@ def normalize_service_final(service: dict, project_dir: str) -> dict:
|
|||||||
context = build if is_str(build) else build.get("context", ".")
|
context = build if is_str(build) else build.get("context", ".")
|
||||||
context = os.path.normpath(os.path.join(project_dir, context))
|
context = os.path.normpath(os.path.join(project_dir, context))
|
||||||
dockerfile = (
|
dockerfile = (
|
||||||
"Dockerfile"
|
"Dockerfile" if is_str(build) else service["build"].get("dockerfile", "Dockerfile")
|
||||||
if is_str(build)
|
|
||||||
else service["build"].get("dockerfile", "Dockerfile")
|
|
||||||
)
|
)
|
||||||
if not is_dict(service["build"]):
|
if not is_dict(service["build"]):
|
||||||
service["build"] = {}
|
service["build"] = {}
|
||||||
@ -1377,17 +1336,13 @@ def rec_merge_one(target, source):
|
|||||||
if not isinstance(value2, type(value)):
|
if not isinstance(value2, type(value)):
|
||||||
value_type = type(value)
|
value_type = type(value)
|
||||||
value2_type = type(value2)
|
value2_type = type(value2)
|
||||||
raise ValueError(
|
raise ValueError(f"can't merge value of [{key}] of type {value_type} and {value2_type}")
|
||||||
f"can't merge value of [{key}] of type {value_type} and {value2_type}"
|
|
||||||
)
|
|
||||||
if is_list(value2):
|
if is_list(value2):
|
||||||
if key == "volumes":
|
if key == "volumes":
|
||||||
# clean duplicate mount targets
|
# clean duplicate mount targets
|
||||||
pts = {v.split(":", 2)[1] for v in value2 if ":" in v}
|
pts = {v.split(":", 2)[1] for v in value2 if ":" in v}
|
||||||
del_ls = [
|
del_ls = [
|
||||||
ix
|
ix for (ix, v) in enumerate(value) if ":" in v and v.split(":", 2)[1] in pts
|
||||||
for (ix, v) in enumerate(value)
|
|
||||||
if ":" in v and v.split(":", 2)[1] in pts
|
|
||||||
]
|
]
|
||||||
for ix in reversed(del_ls):
|
for ix in reversed(del_ls):
|
||||||
del value[ix]
|
del value[ix]
|
||||||
@ -1490,11 +1445,11 @@ class PodmanCompose:
|
|||||||
self.merged_yaml = None
|
self.merged_yaml = None
|
||||||
self.yaml_hash = ""
|
self.yaml_hash = ""
|
||||||
self.console_colors = [
|
self.console_colors = [
|
||||||
"\x1B[1;32m",
|
"\x1b[1;32m",
|
||||||
"\x1B[1;33m",
|
"\x1b[1;33m",
|
||||||
"\x1B[1;34m",
|
"\x1b[1;34m",
|
||||||
"\x1B[1;35m",
|
"\x1b[1;35m",
|
||||||
"\x1B[1;36m",
|
"\x1b[1;36m",
|
||||||
]
|
]
|
||||||
|
|
||||||
def assert_services(self, services):
|
def assert_services(self, services):
|
||||||
@ -1534,10 +1489,9 @@ class PodmanCompose:
|
|||||||
if not args.dry_run:
|
if not args.dry_run:
|
||||||
# just to make sure podman is running
|
# just to make sure podman is running
|
||||||
try:
|
try:
|
||||||
self.podman_version = (
|
self.podman_version = (await self.podman.output(["--version"], "", [])).decode(
|
||||||
(await self.podman.output(["--version"], "", [])).decode("utf-8").strip()
|
"utf-8"
|
||||||
or ""
|
).strip() or ""
|
||||||
)
|
|
||||||
self.podman_version = (self.podman_version.split() or [""])[-1]
|
self.podman_version = (self.podman_version.split() or [""])[-1]
|
||||||
except subprocess.CalledProcessError:
|
except subprocess.CalledProcessError:
|
||||||
self.podman_version = None
|
self.podman_version = None
|
||||||
@ -1603,24 +1557,18 @@ class PodmanCompose:
|
|||||||
# TODO: remove next line
|
# TODO: remove next line
|
||||||
os.chdir(dirname)
|
os.chdir(dirname)
|
||||||
|
|
||||||
os.environ.update(
|
os.environ.update({
|
||||||
{
|
key: value for key, value in dotenv_dict.items() if key.startswith("PODMAN_")
|
||||||
key: value
|
})
|
||||||
for key, value in dotenv_dict.items()
|
|
||||||
if key.startswith("PODMAN_")
|
|
||||||
}
|
|
||||||
)
|
|
||||||
self.environ = dict(os.environ)
|
self.environ = dict(os.environ)
|
||||||
self.environ.update(dotenv_dict)
|
self.environ.update(dotenv_dict)
|
||||||
# see: https://docs.docker.com/compose/reference/envvars/
|
# see: https://docs.docker.com/compose/reference/envvars/
|
||||||
# see: https://docs.docker.com/compose/env-file/
|
# see: https://docs.docker.com/compose/env-file/
|
||||||
self.environ.update(
|
self.environ.update({
|
||||||
{
|
"COMPOSE_PROJECT_DIR": dirname,
|
||||||
"COMPOSE_PROJECT_DIR": dirname,
|
"COMPOSE_FILE": pathsep.join(relative_files),
|
||||||
"COMPOSE_FILE": pathsep.join(relative_files),
|
"COMPOSE_PATH_SEPARATOR": pathsep,
|
||||||
"COMPOSE_PATH_SEPARATOR": pathsep,
|
})
|
||||||
}
|
|
||||||
)
|
|
||||||
compose = {}
|
compose = {}
|
||||||
# Iterate over files primitively to allow appending to files in-loop
|
# Iterate over files primitively to allow appending to files in-loop
|
||||||
files_iter = iter(files)
|
files_iter = iter(files)
|
||||||
@ -1636,8 +1584,7 @@ class PodmanCompose:
|
|||||||
# log(filename, json.dumps(content, indent = 2))
|
# log(filename, json.dumps(content, indent = 2))
|
||||||
if not isinstance(content, dict):
|
if not isinstance(content, dict):
|
||||||
sys.stderr.write(
|
sys.stderr.write(
|
||||||
"Compose file does not contain a top level object: %s\n"
|
"Compose file does not contain a top level object: %s\n" % filename
|
||||||
% filename
|
|
||||||
)
|
)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
content = normalize(content)
|
content = normalize(content)
|
||||||
@ -1654,9 +1601,7 @@ class PodmanCompose:
|
|||||||
# Solution is to remove 'include' key from compose obj. This doesn't break
|
# Solution is to remove 'include' key from compose obj. This doesn't break
|
||||||
# having `include` present and correctly processed in included files
|
# having `include` present and correctly processed in included files
|
||||||
del compose["include"]
|
del compose["include"]
|
||||||
resolved_services = self._resolve_profiles(
|
resolved_services = self._resolve_profiles(compose.get("services", {}), set(args.profile))
|
||||||
compose.get("services", {}), set(args.profile)
|
|
||||||
)
|
|
||||||
compose["services"] = resolved_services
|
compose["services"] = resolved_services
|
||||||
if not getattr(args, "no_normalize", None):
|
if not getattr(args, "no_normalize", None):
|
||||||
compose = normalize_final(compose, self.dirname)
|
compose = normalize_final(compose, self.dirname)
|
||||||
@ -1674,14 +1619,11 @@ class PodmanCompose:
|
|||||||
if project_name is None:
|
if project_name is None:
|
||||||
# More strict then actually needed for simplicity: podman requires [a-zA-Z0-9][a-zA-Z0-9_.-]*
|
# More strict then actually needed for simplicity: podman requires [a-zA-Z0-9][a-zA-Z0-9_.-]*
|
||||||
project_name = (
|
project_name = (
|
||||||
self.environ.get("COMPOSE_PROJECT_NAME", None)
|
self.environ.get("COMPOSE_PROJECT_NAME", None) or dir_basename.lower()
|
||||||
or dir_basename.lower()
|
|
||||||
)
|
)
|
||||||
project_name = norm_re.sub("", project_name)
|
project_name = norm_re.sub("", project_name)
|
||||||
if not project_name:
|
if not project_name:
|
||||||
raise RuntimeError(
|
raise RuntimeError(f"Project name [{dir_basename}] normalized to empty")
|
||||||
f"Project name [{dir_basename}] normalized to empty"
|
|
||||||
)
|
|
||||||
|
|
||||||
self.project_name = project_name
|
self.project_name = project_name
|
||||||
self.environ.update({"COMPOSE_PROJECT_NAME": self.project_name})
|
self.environ.update({"COMPOSE_PROJECT_NAME": self.project_name})
|
||||||
@ -1695,15 +1637,11 @@ class PodmanCompose:
|
|||||||
|
|
||||||
# NOTE: maybe add "extends.service" to _deps at this stage
|
# NOTE: maybe add "extends.service" to _deps at this stage
|
||||||
flat_deps(services, with_extends=True)
|
flat_deps(services, with_extends=True)
|
||||||
service_names = sorted(
|
service_names = sorted([(len(srv["_deps"]), name) for name, srv in services.items()])
|
||||||
[(len(srv["_deps"]), name) for name, srv in services.items()]
|
|
||||||
)
|
|
||||||
service_names = [name for _, name in service_names]
|
service_names = [name for _, name in service_names]
|
||||||
resolve_extends(services, service_names, self.environ)
|
resolve_extends(services, service_names, self.environ)
|
||||||
flat_deps(services)
|
flat_deps(services)
|
||||||
service_names = sorted(
|
service_names = sorted([(len(srv["_deps"]), name) for name, srv in services.items()])
|
||||||
[(len(srv["_deps"]), name) for name, srv in services.items()]
|
|
||||||
)
|
|
||||||
service_names = [name for _, name in service_names]
|
service_names = [name for _, name in service_names]
|
||||||
nets = compose.get("networks", None) or {}
|
nets = compose.get("networks", None) or {}
|
||||||
if not nets:
|
if not nets:
|
||||||
@ -1719,9 +1657,7 @@ class PodmanCompose:
|
|||||||
allnets = set()
|
allnets = set()
|
||||||
for name, srv in services.items():
|
for name, srv in services.items():
|
||||||
srv_nets = srv.get("networks", None) or default_net
|
srv_nets = srv.get("networks", None) or default_net
|
||||||
srv_nets = (
|
srv_nets = list(srv_nets.keys()) if is_dict(srv_nets) else norm_as_list(srv_nets)
|
||||||
list(srv_nets.keys()) if is_dict(srv_nets) else norm_as_list(srv_nets)
|
|
||||||
)
|
|
||||||
allnets.update(srv_nets)
|
allnets.update(srv_nets)
|
||||||
given_nets = set(nets.keys())
|
given_nets = set(nets.keys())
|
||||||
missing_nets = allnets - given_nets
|
missing_nets = allnets - given_nets
|
||||||
@ -1772,12 +1708,10 @@ class PodmanCompose:
|
|||||||
labels = norm_as_list(cnt.get("labels", None))
|
labels = norm_as_list(cnt.get("labels", None))
|
||||||
cnt["ports"] = norm_ports(cnt.get("ports", None))
|
cnt["ports"] = norm_ports(cnt.get("ports", None))
|
||||||
labels.extend(podman_compose_labels)
|
labels.extend(podman_compose_labels)
|
||||||
labels.extend(
|
labels.extend([
|
||||||
[
|
f"com.docker.compose.container-number={num}",
|
||||||
f"com.docker.compose.container-number={num}",
|
"com.docker.compose.service=" + service_name,
|
||||||
"com.docker.compose.service=" + service_name,
|
])
|
||||||
]
|
|
||||||
)
|
|
||||||
cnt["labels"] = labels
|
cnt["labels"] = labels
|
||||||
cnt["_service"] = service_name
|
cnt["_service"] = service_name
|
||||||
cnt["_project"] = project_name
|
cnt["_project"] = project_name
|
||||||
@ -1791,9 +1725,7 @@ class PodmanCompose:
|
|||||||
and mnt_dict["source"] not in self.vols
|
and mnt_dict["source"] not in self.vols
|
||||||
):
|
):
|
||||||
vol_name = mnt_dict["source"]
|
vol_name = mnt_dict["source"]
|
||||||
raise RuntimeError(
|
raise RuntimeError(f"volume [{vol_name}] not defined in top level")
|
||||||
f"volume [{vol_name}] not defined in top level"
|
|
||||||
)
|
|
||||||
self.container_names_by_service = container_names_by_service
|
self.container_names_by_service = container_names_by_service
|
||||||
self.all_services = set(container_names_by_service.keys())
|
self.all_services = set(container_names_by_service.keys())
|
||||||
container_by_name = {c["name"]: c for c in given_containers}
|
container_by_name = {c["name"]: c for c in given_containers}
|
||||||
@ -1824,9 +1756,7 @@ class PodmanCompose:
|
|||||||
|
|
||||||
for name, config in defined_services.items():
|
for name, config in defined_services.items():
|
||||||
service_profiles = set(config.get("profiles", []))
|
service_profiles = set(config.get("profiles", []))
|
||||||
if not service_profiles or requested_profiles.intersection(
|
if not service_profiles or requested_profiles.intersection(service_profiles):
|
||||||
service_profiles
|
|
||||||
):
|
|
||||||
services[name] = config
|
services[name] = config
|
||||||
return services
|
return services
|
||||||
|
|
||||||
@ -1836,9 +1766,7 @@ class PodmanCompose:
|
|||||||
subparsers = parser.add_subparsers(title="command", dest="command")
|
subparsers = parser.add_subparsers(title="command", dest="command")
|
||||||
subparser = subparsers.add_parser("help", help="show help")
|
subparser = subparsers.add_parser("help", help="show help")
|
||||||
for cmd_name, cmd in self.commands.items():
|
for cmd_name, cmd in self.commands.items():
|
||||||
subparser = subparsers.add_parser(
|
subparser = subparsers.add_parser(cmd_name, help=cmd.desc) # pylint: disable=protected-access
|
||||||
cmd_name, help=cmd.desc
|
|
||||||
) # pylint: disable=protected-access
|
|
||||||
for cmd_parser in cmd._parse_args: # pylint: disable=protected-access
|
for cmd_parser in cmd._parse_args: # pylint: disable=protected-access
|
||||||
cmd_parser(subparser)
|
cmd_parser(subparser)
|
||||||
self.global_args = parser.parse_args()
|
self.global_args = parser.parse_args()
|
||||||
@ -1932,9 +1860,7 @@ class PodmanCompose:
|
|||||||
action="store_true",
|
action="store_true",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--parallel",
|
"--parallel", type=int, default=os.environ.get("COMPOSE_PARALLEL_LIMIT", sys.maxsize)
|
||||||
type=int,
|
|
||||||
default=os.environ.get("COMPOSE_PARALLEL_LIMIT", sys.maxsize)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -2179,12 +2105,10 @@ async def build_one(compose, args, cnt):
|
|||||||
|
|
||||||
args_list = norm_as_list(build_desc.get("args", {}))
|
args_list = norm_as_list(build_desc.get("args", {}))
|
||||||
for build_arg in args_list + args.build_arg:
|
for build_arg in args_list + args.build_arg:
|
||||||
build_args.extend(
|
build_args.extend((
|
||||||
(
|
"--build-arg",
|
||||||
"--build-arg",
|
build_arg,
|
||||||
build_arg,
|
))
|
||||||
)
|
|
||||||
)
|
|
||||||
build_args.append(ctx)
|
build_args.append(ctx)
|
||||||
status = await compose.podman.run([], "build", build_args)
|
status = await compose.podman.run([], "build", build_args)
|
||||||
return status
|
return status
|
||||||
@ -2243,9 +2167,7 @@ def get_excluded(compose, args):
|
|||||||
return excluded
|
return excluded
|
||||||
|
|
||||||
|
|
||||||
@cmd_run(
|
@cmd_run(podman_compose, "up", "Create and start the entire stack or some of its services")
|
||||||
podman_compose, "up", "Create and start the entire stack or some of its services"
|
|
||||||
)
|
|
||||||
async def compose_up(compose: PodmanCompose, args):
|
async def compose_up(compose: PodmanCompose, args):
|
||||||
proj_name = compose.project_name
|
proj_name = compose.project_name
|
||||||
excluded = get_excluded(compose, args)
|
excluded = get_excluded(compose, args)
|
||||||
@ -2256,17 +2178,19 @@ async def compose_up(compose: PodmanCompose, args):
|
|||||||
log("Build command failed")
|
log("Build command failed")
|
||||||
|
|
||||||
hashes = (
|
hashes = (
|
||||||
(await compose.podman.output(
|
(
|
||||||
[],
|
await compose.podman.output(
|
||||||
"ps",
|
[],
|
||||||
[
|
"ps",
|
||||||
"--filter",
|
[
|
||||||
f"label=io.podman.compose.project={proj_name}",
|
"--filter",
|
||||||
"-a",
|
f"label=io.podman.compose.project={proj_name}",
|
||||||
"--format",
|
"-a",
|
||||||
'{{ index .Labels "io.podman.compose.config-hash"}}',
|
"--format",
|
||||||
],
|
'{{ index .Labels "io.podman.compose.config-hash"}}',
|
||||||
))
|
],
|
||||||
|
)
|
||||||
|
)
|
||||||
.decode("utf-8")
|
.decode("utf-8")
|
||||||
.splitlines()
|
.splitlines()
|
||||||
)
|
)
|
||||||
@ -2301,9 +2225,7 @@ async def compose_up(compose: PodmanCompose, args):
|
|||||||
max_service_length = 0
|
max_service_length = 0
|
||||||
for cnt in compose.containers:
|
for cnt in compose.containers:
|
||||||
curr_length = len(cnt["_service"])
|
curr_length = len(cnt["_service"])
|
||||||
max_service_length = (
|
max_service_length = curr_length if curr_length > max_service_length else max_service_length
|
||||||
curr_length if curr_length > max_service_length else max_service_length
|
|
||||||
)
|
|
||||||
|
|
||||||
tasks = set()
|
tasks = set()
|
||||||
|
|
||||||
@ -2315,9 +2237,7 @@ async def compose_up(compose: PodmanCompose, args):
|
|||||||
color_idx = i % len(compose.console_colors)
|
color_idx = i % len(compose.console_colors)
|
||||||
color = compose.console_colors[color_idx]
|
color = compose.console_colors[color_idx]
|
||||||
space_suffix = " " * (max_service_length - len(cnt["_service"]) + 1)
|
space_suffix = " " * (max_service_length - len(cnt["_service"]) + 1)
|
||||||
log_formatter = "{}[{}]{}|\x1B[0m".format(
|
log_formatter = "{}[{}]{}|\x1b[0m".format(color, cnt["_service"], space_suffix)
|
||||||
color, cnt["_service"], space_suffix
|
|
||||||
)
|
|
||||||
if cnt["_service"] in excluded:
|
if cnt["_service"] in excluded:
|
||||||
log("** skipping: ", cnt["name"])
|
log("** skipping: ", cnt["name"])
|
||||||
continue
|
continue
|
||||||
@ -2325,7 +2245,7 @@ async def compose_up(compose: PodmanCompose, args):
|
|||||||
tasks.add(
|
tasks.add(
|
||||||
asyncio.create_task(
|
asyncio.create_task(
|
||||||
compose.podman.run([], "start", ["-a", cnt["name"]], log_formatter=log_formatter),
|
compose.podman.run([], "start", ["-a", cnt["name"]], log_formatter=log_formatter),
|
||||||
name=cnt["_service"]
|
name=cnt["_service"],
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -2384,7 +2304,11 @@ async def compose_down(compose, args):
|
|||||||
timeout = str_to_seconds(timeout_str)
|
timeout = str_to_seconds(timeout_str)
|
||||||
if timeout is not None:
|
if timeout is not None:
|
||||||
podman_stop_args.extend(["-t", str(timeout)])
|
podman_stop_args.extend(["-t", str(timeout)])
|
||||||
down_tasks.append(asyncio.create_task(compose.podman.run([], "stop", [*podman_stop_args, cnt["name"]]), name=cnt["name"]))
|
down_tasks.append(
|
||||||
|
asyncio.create_task(
|
||||||
|
compose.podman.run([], "stop", [*podman_stop_args, cnt["name"]]), name=cnt["name"]
|
||||||
|
)
|
||||||
|
)
|
||||||
await asyncio.gather(*down_tasks)
|
await asyncio.gather(*down_tasks)
|
||||||
for cnt in containers:
|
for cnt in containers:
|
||||||
if cnt["_service"] in excluded:
|
if cnt["_service"] in excluded:
|
||||||
@ -2392,17 +2316,19 @@ async def compose_down(compose, args):
|
|||||||
await compose.podman.run([], "rm", [cnt["name"]])
|
await compose.podman.run([], "rm", [cnt["name"]])
|
||||||
if args.remove_orphans:
|
if args.remove_orphans:
|
||||||
names = (
|
names = (
|
||||||
(await compose.podman.output(
|
(
|
||||||
[],
|
await compose.podman.output(
|
||||||
"ps",
|
[],
|
||||||
[
|
"ps",
|
||||||
"--filter",
|
[
|
||||||
f"label=io.podman.compose.project={compose.project_name}",
|
"--filter",
|
||||||
"-a",
|
f"label=io.podman.compose.project={compose.project_name}",
|
||||||
"--format",
|
"-a",
|
||||||
"{{ .Names }}",
|
"--format",
|
||||||
],
|
"{{ .Names }}",
|
||||||
))
|
],
|
||||||
|
)
|
||||||
|
)
|
||||||
.decode("utf-8")
|
.decode("utf-8")
|
||||||
.splitlines()
|
.splitlines()
|
||||||
)
|
)
|
||||||
@ -2470,23 +2396,18 @@ async def compose_run(compose, args):
|
|||||||
no_cache=False,
|
no_cache=False,
|
||||||
build_arg=[],
|
build_arg=[],
|
||||||
parallel=1,
|
parallel=1,
|
||||||
remove_orphans=True
|
remove_orphans=True,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
await compose.commands["up"](compose, up_args)
|
await compose.commands["up"](compose, up_args)
|
||||||
|
|
||||||
build_args = argparse.Namespace(
|
build_args = argparse.Namespace(
|
||||||
services=[args.service],
|
services=[args.service], if_not_exists=(not args.build), build_arg=[], **args.__dict__
|
||||||
if_not_exists=(not args.build),
|
|
||||||
build_arg=[],
|
|
||||||
**args.__dict__
|
|
||||||
)
|
)
|
||||||
await compose.commands["build"](compose, build_args)
|
await compose.commands["build"](compose, build_args)
|
||||||
|
|
||||||
# adjust one-off container options
|
# adjust one-off container options
|
||||||
name0 = "{}_{}_tmp{}".format(
|
name0 = "{}_{}_tmp{}".format(compose.project_name, args.service, random.randrange(0, 65536))
|
||||||
compose.project_name, args.service, random.randrange(0, 65536)
|
|
||||||
)
|
|
||||||
cnt["name"] = args.name or name0
|
cnt["name"] = args.name or name0
|
||||||
if args.entrypoint:
|
if args.entrypoint:
|
||||||
cnt["entrypoint"] = args.entrypoint
|
cnt["entrypoint"] = args.entrypoint
|
||||||
@ -2692,9 +2613,7 @@ async def compose_unpause(compose, args):
|
|||||||
await compose.podman.run([], "unpause", targets)
|
await compose.podman.run([], "unpause", targets)
|
||||||
|
|
||||||
|
|
||||||
@cmd_run(
|
@cmd_run(podman_compose, "kill", "Kill one or more running containers with a specific signal")
|
||||||
podman_compose, "kill", "Kill one or more running containers with a specific signal"
|
|
||||||
)
|
|
||||||
async def compose_kill(compose, args):
|
async def compose_kill(compose, args):
|
||||||
# to ensure that the user did not execute the command by mistake
|
# to ensure that the user did not execute the command by mistake
|
||||||
if not args.services and not args.all:
|
if not args.services and not args.all:
|
||||||
@ -2787,17 +2706,13 @@ def compose_up_parse(parser):
|
|||||||
help="Detached mode: Run container in the background, print new container name. \
|
help="Detached mode: Run container in the background, print new container name. \
|
||||||
Incompatible with --abort-on-container-exit.",
|
Incompatible with --abort-on-container-exit.",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument("--no-color", action="store_true", help="Produce monochrome output.")
|
||||||
"--no-color", action="store_true", help="Produce monochrome output."
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--quiet-pull",
|
"--quiet-pull",
|
||||||
action="store_true",
|
action="store_true",
|
||||||
help="Pull without printing progress information.",
|
help="Pull without printing progress information.",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument("--no-deps", action="store_true", help="Don't start linked services.")
|
||||||
"--no-deps", action="store_true", help="Don't start linked services."
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--force-recreate",
|
"--force-recreate",
|
||||||
action="store_true",
|
action="store_true",
|
||||||
@ -2893,9 +2808,7 @@ def compose_run_parse(parser):
|
|||||||
action="store_true",
|
action="store_true",
|
||||||
help="Detached mode: Run container in the background, print new container name.",
|
help="Detached mode: Run container in the background, print new container name.",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument("--name", type=str, default=None, help="Assign a name to the container")
|
||||||
"--name", type=str, default=None, help="Assign a name to the container"
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--entrypoint",
|
"--entrypoint",
|
||||||
type=str,
|
type=str,
|
||||||
@ -2919,9 +2832,7 @@ def compose_run_parse(parser):
|
|||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-u", "--user", type=str, default=None, help="Run as specified username or uid"
|
"-u", "--user", type=str, default=None, help="Run as specified username or uid"
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument("--no-deps", action="store_true", help="Don't start linked services")
|
||||||
"--no-deps", action="store_true", help="Don't start linked services"
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--rm",
|
"--rm",
|
||||||
action="store_true",
|
action="store_true",
|
||||||
@ -3047,21 +2958,15 @@ def compose_logs_parse(parser):
|
|||||||
action="store_true",
|
action="store_true",
|
||||||
help="Output the container name in the log",
|
help="Output the container name in the log",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument("--since", help="Show logs since TIMESTAMP", type=str, default=None)
|
||||||
"--since", help="Show logs since TIMESTAMP", type=str, default=None
|
parser.add_argument("-t", "--timestamps", action="store_true", help="Show timestamps.")
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"-t", "--timestamps", action="store_true", help="Show timestamps."
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--tail",
|
"--tail",
|
||||||
help="Number of lines to show from the end of the logs for each " "container.",
|
help="Number of lines to show from the end of the logs for each " "container.",
|
||||||
type=str,
|
type=str,
|
||||||
default="all",
|
default="all",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument("--until", help="Show logs until TIMESTAMP", type=str, default=None)
|
||||||
"--until", help="Show logs until TIMESTAMP", type=str, default=None
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"services", metavar="services", nargs="*", default=None, help="service names"
|
"services", metavar="services", nargs="*", default=None, help="service names"
|
||||||
)
|
)
|
||||||
@ -3086,9 +2991,7 @@ def compose_pull_parse(parser):
|
|||||||
default=False,
|
default=False,
|
||||||
help="Also pull unprefixed images for services which have a build section",
|
help="Also pull unprefixed images for services which have a build section",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument("services", metavar="services", nargs="*", help="services to pull")
|
||||||
"services", metavar="services", nargs="*", help="services to pull"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@cmd_parse(podman_compose, "push")
|
@cmd_parse(podman_compose, "push")
|
||||||
@ -3098,16 +3001,12 @@ def compose_push_parse(parser):
|
|||||||
action="store_true",
|
action="store_true",
|
||||||
help="Push what it can and ignores images with push failures. (not implemented)",
|
help="Push what it can and ignores images with push failures. (not implemented)",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument("services", metavar="services", nargs="*", help="services to push")
|
||||||
"services", metavar="services", nargs="*", help="services to push"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@cmd_parse(podman_compose, "ps")
|
@cmd_parse(podman_compose, "ps")
|
||||||
def compose_ps_parse(parser):
|
def compose_ps_parse(parser):
|
||||||
parser.add_argument(
|
parser.add_argument("-q", "--quiet", help="Only display container IDs", action="store_true")
|
||||||
"-q", "--quiet", help="Only display container IDs", action="store_true"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@cmd_parse(podman_compose, ["build", "up"])
|
@cmd_parse(podman_compose, ["build", "up"])
|
||||||
@ -3239,11 +3138,14 @@ def compose_format_parse(parser):
|
|||||||
help="Pretty-print container statistics to JSON or using a Go template",
|
help="Pretty-print container statistics to JSON or using a Go template",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def async_main():
|
async def async_main():
|
||||||
await podman_compose.run()
|
await podman_compose.run()
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
asyncio.run(async_main())
|
asyncio.run(async_main())
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
@ -71,9 +71,7 @@ def test_normalize_service():
|
|||||||
|
|
||||||
|
|
||||||
def test__parse_compose_file_when_multiple_composes() -> None:
|
def test__parse_compose_file_when_multiple_composes() -> None:
|
||||||
for base_template, override_template, expected_template in copy.deepcopy(
|
for base_template, override_template, expected_template in copy.deepcopy(test_cases_merges):
|
||||||
test_cases_merges
|
|
||||||
):
|
|
||||||
for key in test_keys:
|
for key in test_keys:
|
||||||
base, override, expected = template_to_expression(
|
base, override, expected = template_to_expression(
|
||||||
base_template, override_template, expected_template, key
|
base_template, override_template, expected_template, key
|
||||||
|
@ -243,9 +243,7 @@ test_cases_with_merges = [
|
|||||||
# running full parse over merged
|
# running full parse over merged
|
||||||
#
|
#
|
||||||
def test__parse_compose_file_when_multiple_composes() -> None:
|
def test__parse_compose_file_when_multiple_composes() -> None:
|
||||||
for test_input, test_override, expected_result in copy.deepcopy(
|
for test_input, test_override, expected_result in copy.deepcopy(test_cases_with_merges):
|
||||||
test_cases_with_merges
|
|
||||||
):
|
|
||||||
compose_test_1 = {"services": {"test-service": test_input}}
|
compose_test_1 = {"services": {"test-service": test_input}}
|
||||||
compose_test_2 = {"services": {"test-service": test_override}}
|
compose_test_2 = {"services": {"test-service": test_override}}
|
||||||
dump_yaml(compose_test_1, "test-compose-1.yaml")
|
dump_yaml(compose_test_1, "test-compose-1.yaml")
|
||||||
@ -273,9 +271,7 @@ def test__parse_compose_file_when_multiple_composes() -> None:
|
|||||||
assert compose_expected == actual_compose
|
assert compose_expected == actual_compose
|
||||||
|
|
||||||
|
|
||||||
def set_args(
|
def set_args(podman_compose: PodmanCompose, file_names: list[str], no_normalize: bool) -> None:
|
||||||
podman_compose: PodmanCompose, file_names: list[str], no_normalize: bool
|
|
||||||
) -> None:
|
|
||||||
podman_compose.global_args = argparse.Namespace()
|
podman_compose.global_args = argparse.Namespace()
|
||||||
podman_compose.global_args.file = file_names
|
podman_compose.global_args.file = file_names
|
||||||
podman_compose.global_args.project_name = None
|
podman_compose.global_args.project_name = None
|
||||||
|
4
setup.py
4
setup.py
@ -2,9 +2,7 @@ import os
|
|||||||
from setuptools import setup
|
from setuptools import setup
|
||||||
|
|
||||||
try:
|
try:
|
||||||
README = open(
|
README = open(os.path.join(os.path.dirname(__file__), "README.md"), encoding="utf-8").read()
|
||||||
os.path.join(os.path.dirname(__file__), "README.md"), encoding="utf-8"
|
|
||||||
).read()
|
|
||||||
except: # noqa: E722 # pylint: disable=bare-except
|
except: # noqa: E722 # pylint: disable=bare-except
|
||||||
README = ""
|
README = ""
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
Defines global pytest fixtures available to all tests.
|
Defines global pytest fixtures available to all tests.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# pylint: disable=redefined-outer-name
|
# pylint: disable=redefined-outer-name
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import os
|
import os
|
||||||
|
@ -77,9 +77,7 @@ def test_podman_compose_extends_w_empty_service():
|
|||||||
"python3",
|
"python3",
|
||||||
str(main_path.joinpath("podman_compose.py")),
|
str(main_path.joinpath("podman_compose.py")),
|
||||||
"-f",
|
"-f",
|
||||||
str(
|
str(main_path.joinpath("tests", "extends_w_empty_service", "docker-compose.yml")),
|
||||||
main_path.joinpath("tests", "extends_w_empty_service", "docker-compose.yml")
|
|
||||||
),
|
|
||||||
"up",
|
"up",
|
||||||
"-d",
|
"-d",
|
||||||
]
|
]
|
||||||
|
@ -3,6 +3,7 @@ test_podman_compose_config.py
|
|||||||
|
|
||||||
Tests the podman-compose config command which is used to return defined compose services.
|
Tests the podman-compose config command which is used to return defined compose services.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# pylint: disable=redefined-outer-name
|
# pylint: disable=redefined-outer-name
|
||||||
import os
|
import os
|
||||||
from test_podman_compose import capture
|
from test_podman_compose import capture
|
||||||
@ -50,9 +51,7 @@ def test_config_no_profiles(podman_compose_path, profile_compose_file):
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_config_profiles(
|
def test_config_profiles(podman_compose_path, profile_compose_file, profiles, expected_services):
|
||||||
podman_compose_path, profile_compose_file, profiles, expected_services
|
|
||||||
):
|
|
||||||
"""
|
"""
|
||||||
Tests podman-compose
|
Tests podman-compose
|
||||||
:param podman_compose_path: The fixture used to specify the path to the podman compose file.
|
:param podman_compose_path: The fixture used to specify the path to the podman compose file.
|
||||||
|
@ -3,6 +3,7 @@ test_podman_compose_up_down.py
|
|||||||
|
|
||||||
Tests the podman compose up and down commands used to create and remove services.
|
Tests the podman compose up and down commands used to create and remove services.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# pylint: disable=redefined-outer-name
|
# pylint: disable=redefined-outer-name
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
@ -17,7 +18,7 @@ def test_exit_from(podman_compose_path, test_path):
|
|||||||
podman_compose_path,
|
podman_compose_path,
|
||||||
"-f",
|
"-f",
|
||||||
os.path.join(test_path, "exit-from", "docker-compose.yaml"),
|
os.path.join(test_path, "exit-from", "docker-compose.yaml"),
|
||||||
"up"
|
"up",
|
||||||
]
|
]
|
||||||
|
|
||||||
out, _, return_code = capture(up_cmd + ["--exit-code-from", "sh1"])
|
out, _, return_code = capture(up_cmd + ["--exit-code-from", "sh1"])
|
||||||
@ -42,7 +43,7 @@ def test_run(podman_compose_path, test_path):
|
|||||||
"sleep",
|
"sleep",
|
||||||
"/bin/sh",
|
"/bin/sh",
|
||||||
"-c",
|
"-c",
|
||||||
"wget -q -O - http://web:8000/hosts"
|
"wget -q -O - http://web:8000/hosts",
|
||||||
]
|
]
|
||||||
|
|
||||||
out, _, return_code = capture(run_cmd)
|
out, _, return_code = capture(run_cmd)
|
||||||
@ -61,7 +62,7 @@ def test_run(podman_compose_path, test_path):
|
|||||||
"sleep",
|
"sleep",
|
||||||
"/bin/sh",
|
"/bin/sh",
|
||||||
"-c",
|
"-c",
|
||||||
"wget -q -O - http://web:8000/hosts"
|
"wget -q -O - http://web:8000/hosts",
|
||||||
]
|
]
|
||||||
|
|
||||||
out, _, return_code = capture(run_cmd)
|
out, _, return_code = capture(run_cmd)
|
||||||
@ -83,8 +84,6 @@ def test_run(podman_compose_path, test_path):
|
|||||||
|
|
||||||
|
|
||||||
def test_up_with_ports(podman_compose_path, test_path):
|
def test_up_with_ports(podman_compose_path, test_path):
|
||||||
|
|
||||||
|
|
||||||
up_cmd = [
|
up_cmd = [
|
||||||
"coverage",
|
"coverage",
|
||||||
"run",
|
"run",
|
||||||
@ -93,7 +92,7 @@ def test_up_with_ports(podman_compose_path, test_path):
|
|||||||
os.path.join(test_path, "ports", "docker-compose.yml"),
|
os.path.join(test_path, "ports", "docker-compose.yml"),
|
||||||
"up",
|
"up",
|
||||||
"-d",
|
"-d",
|
||||||
"--force-recreate"
|
"--force-recreate",
|
||||||
]
|
]
|
||||||
|
|
||||||
down_cmd = [
|
down_cmd = [
|
||||||
@ -103,21 +102,19 @@ def test_up_with_ports(podman_compose_path, test_path):
|
|||||||
"-f",
|
"-f",
|
||||||
os.path.join(test_path, "ports", "docker-compose.yml"),
|
os.path.join(test_path, "ports", "docker-compose.yml"),
|
||||||
"down",
|
"down",
|
||||||
"--volumes"
|
"--volumes",
|
||||||
]
|
]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
out, _, return_code = capture(up_cmd)
|
out, _, return_code = capture(up_cmd)
|
||||||
assert return_code == 0
|
assert return_code == 0
|
||||||
|
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
out, _, return_code = capture(down_cmd)
|
out, _, return_code = capture(down_cmd)
|
||||||
assert return_code == 0
|
assert return_code == 0
|
||||||
|
|
||||||
|
|
||||||
def test_down_with_vols(podman_compose_path, test_path):
|
def test_down_with_vols(podman_compose_path, test_path):
|
||||||
|
|
||||||
up_cmd = [
|
up_cmd = [
|
||||||
"coverage",
|
"coverage",
|
||||||
"run",
|
"run",
|
||||||
@ -125,7 +122,7 @@ def test_down_with_vols(podman_compose_path, test_path):
|
|||||||
"-f",
|
"-f",
|
||||||
os.path.join(test_path, "vol", "docker-compose.yaml"),
|
os.path.join(test_path, "vol", "docker-compose.yaml"),
|
||||||
"up",
|
"up",
|
||||||
"-d"
|
"-d",
|
||||||
]
|
]
|
||||||
|
|
||||||
down_cmd = [
|
down_cmd = [
|
||||||
@ -135,7 +132,7 @@ def test_down_with_vols(podman_compose_path, test_path):
|
|||||||
"-f",
|
"-f",
|
||||||
os.path.join(test_path, "vol", "docker-compose.yaml"),
|
os.path.join(test_path, "vol", "docker-compose.yaml"),
|
||||||
"down",
|
"down",
|
||||||
"--volumes"
|
"--volumes",
|
||||||
]
|
]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -157,8 +154,20 @@ def test_down_with_vols(podman_compose_path, test_path):
|
|||||||
|
|
||||||
|
|
||||||
def test_down_with_orphans(podman_compose_path, test_path):
|
def test_down_with_orphans(podman_compose_path, test_path):
|
||||||
|
container_id, _, return_code = capture([
|
||||||
container_id, _ , return_code = capture(["podman", "run", "--rm", "-d", "busybox", "/bin/busybox", "httpd", "-f", "-h", "/etc/", "-p", "8000"])
|
"podman",
|
||||||
|
"run",
|
||||||
|
"--rm",
|
||||||
|
"-d",
|
||||||
|
"busybox",
|
||||||
|
"/bin/busybox",
|
||||||
|
"httpd",
|
||||||
|
"-f",
|
||||||
|
"-h",
|
||||||
|
"/etc/",
|
||||||
|
"-p",
|
||||||
|
"8000",
|
||||||
|
])
|
||||||
|
|
||||||
down_cmd = [
|
down_cmd = [
|
||||||
"coverage",
|
"coverage",
|
||||||
@ -168,7 +177,7 @@ def test_down_with_orphans(podman_compose_path, test_path):
|
|||||||
os.path.join(test_path, "ports", "docker-compose.yml"),
|
os.path.join(test_path, "ports", "docker-compose.yml"),
|
||||||
"down",
|
"down",
|
||||||
"--volumes",
|
"--volumes",
|
||||||
"--remove-orphans"
|
"--remove-orphans",
|
||||||
]
|
]
|
||||||
|
|
||||||
out, _, return_code = capture(down_cmd)
|
out, _, return_code = capture(down_cmd)
|
||||||
@ -177,4 +186,3 @@ def test_down_with_orphans(podman_compose_path, test_path):
|
|||||||
_, _, exists = capture(["podman", "container", "exists", container_id.decode("utf-8")])
|
_, _, exists = capture(["podman", "container", "exists", container_id.decode("utf-8")])
|
||||||
|
|
||||||
assert exists == 1
|
assert exists == 1
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ test_podman_compose_up_down.py
|
|||||||
|
|
||||||
Tests the podman compose up and down commands used to create and remove services.
|
Tests the podman compose up and down commands used to create and remove services.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# pylint: disable=redefined-outer-name
|
# pylint: disable=redefined-outer-name
|
||||||
import os
|
import os
|
||||||
from test_podman_compose import capture
|
from test_podman_compose import capture
|
||||||
|
Loading…
Reference in New Issue
Block a user