fix: podman-compose down should not stop the upstream dependencies.

Say there is an app service depends on a db service,
when we run `podman-compose down app`, the db service should not be stopped.

Signed-off-by: Songmin Li <lisongmin@protonmail.com>
This commit is contained in:
Songmin Li
2025-08-09 22:32:20 +08:00
parent f618ff3b6e
commit 4aa11de6bf
3 changed files with 68 additions and 1 deletions

View File

@@ -0,0 +1 @@
Fix `podman-compose down service` stops wrong dependents

View File

@@ -1433,6 +1433,16 @@ def rec_deps(
return deps
def calc_dependents(services: dict[str, Any]) -> None:
for name, srv in services.items():
deps: set[ServiceDependency] = srv.get("_deps", set())
for dep in deps:
if dep.name in services:
services[dep.name].setdefault("_dependents", set()).add(
ServiceDependency(name, dep.condition.value)
)
def flat_deps(services: dict[str, Any], with_extends: bool = False) -> None:
"""
create dependencies "_deps" or update it recursively for all services
@@ -1470,6 +1480,8 @@ def flat_deps(services: dict[str, Any], with_extends: bool = False) -> None:
for name, srv in services.items():
rec_deps(services, name)
calc_dependents(services)
###################
# Override and reset tags
@@ -3028,10 +3040,11 @@ def get_excluded(compose: PodmanCompose, args: argparse.Namespace) -> set[str]:
excluded = set()
if args.services:
excluded = set(compose.services)
dep_field = "_dependents" if args.command in ["down"] else "_deps"
for service in args.services:
# we need 'getattr' as compose_down_parse dose not configure 'no_deps'
if service in compose.services and not getattr(args, "no_deps", False):
excluded -= set(x.name for x in compose.services[service]["_deps"])
excluded -= set(x.name for x in compose.services[service].get(dep_field, set()))
excluded.discard(service)
log.debug("** excluding: %s", excluded)
return excluded

View File

@@ -0,0 +1,53 @@
import unittest
from typing import Any
from parameterized import parameterized
from podman_compose import flat_deps
class TestDependsOn(unittest.TestCase):
@parameterized.expand([
(
{
"service_a": {},
"service_b": {"depends_on": {"service_a": {"condition": "healthy"}}},
"service_c": {"depends_on": {"service_b": {"condition": "healthy"}}},
},
# dependencies
{
"service_a": set(),
"service_b": set(["service_a"]),
"service_c": set(["service_a", "service_b"]),
},
# dependents
{
"service_a": set(["service_b", "service_c"]),
"service_b": set(["service_c"]),
"service_c": set(),
},
),
])
def test_flat_deps(
self,
services: dict[str, Any],
deps: dict[str, set[str]],
dependents: dict[str, set[str]],
) -> None:
flat_deps(services)
self.assertEqual(
{
name: set([x.name for x in value.get("_deps", set())])
for name, value in services.items()
},
deps,
msg="Dependencies do not match",
)
self.assertEqual(
{
name: set([x.name for x in value.get("_dependents", set())])
for name, value in services.items()
},
dependents,
msg="Dependents do not match",
)