11from ..settings import Settings
22from fastapi import HTTPException
33import os
4- import fnmatch
54import pathlib
65import re
76
87settings = Settings ()
98PROJECT_NAME_PATTERN = re .compile (r"^[A-Za-z0-9._-]+$" )
9+ COMPOSE_FILE_PATTERNS = (
10+ "compose.yml" ,
11+ "compose.yaml" ,
12+ "docker-compose.yml" ,
13+ "docker-compose.yaml" ,
14+ )
1015
1116
1217def get_compose_base_dir ():
@@ -33,6 +38,12 @@ def _ensure_within_compose_base(path, must_exist=False):
3338 return resolved
3439
3540
41+ def _resolve_compose_descendant (* path_parts , must_exist = False ):
42+ base_dir = get_compose_base_path ().resolve ()
43+ candidate = base_dir .joinpath (* path_parts )
44+ return _ensure_within_compose_base (candidate , must_exist = must_exist )
45+
46+
3647def _validated_project_name (project_name ):
3748 if not isinstance (project_name , str ):
3849 raise HTTPException (400 , "Invalid project name." )
@@ -53,18 +64,13 @@ def resolve_compose_project_path(project_name):
5364 Resolve a compose project directory from a project name.
5465 """
5566 validated_name = _validated_project_name (project_name )
56- project_dir = _ensure_within_compose_base (
57- get_compose_base_path () / validated_name
58- )
67+ project_dir = _resolve_compose_descendant (validated_name )
5968 return os .fspath (project_dir )
6069
6170
6271def resolve_compose_project_dir (project_name , must_exist = False ):
6372 validated_name = _validated_project_name (project_name )
64- return _ensure_within_compose_base (
65- get_compose_base_path () / validated_name ,
66- must_exist = must_exist ,
67- )
73+ return _resolve_compose_descendant (validated_name , must_exist = must_exist )
6874
6975
7076def resolve_compose_file (project_name , filename = "docker-compose.yml" , must_exist = False ):
@@ -76,7 +82,7 @@ def resolve_compose_file(project_name, filename="docker-compose.yml", must_exist
7682 return compose_file
7783
7884
79- def _collect_yml_files (root_dir ):
85+ def _compose_file_matches (root_dir ):
8086 """
8187 Find docker compose files inside a validated compose directory.
8288 """
@@ -85,16 +91,9 @@ def _collect_yml_files(root_dir):
8591 return {}
8692
8793 matches = {}
88- for root , _ , filenames in os .walk (os .fspath (safe_root ), followlinks = False ):
89- for _ in set ().union (
90- fnmatch .filter (filenames , "compose.yml" ),
91- fnmatch .filter (filenames , "compose.yaml" ),
92- fnmatch .filter (filenames , "docker-compose.yml" ),
93- fnmatch .filter (filenames , "docker-compose.yaml" ),
94- ):
95- candidate = _ensure_within_compose_base (
96- pathlib .Path (root ) / _ , must_exist = True
97- )
94+ for pattern in COMPOSE_FILE_PATTERNS :
95+ for candidate in safe_root .rglob (pattern ):
96+ candidate = _ensure_within_compose_base (candidate , must_exist = True )
9897 key = candidate .parent .name
9998 matches [key ] = os .fspath (candidate )
10099 return matches
@@ -104,14 +103,15 @@ def find_yml_files():
104103 """
105104 Find docker compose files under the compose base directory.
106105 """
107- return _collect_yml_files (get_compose_base_path ())
106+ return _compose_file_matches (get_compose_base_path ())
108107
109108
110109def find_project_yml_files (project_name ):
111110 """
112111 Find docker compose files for a single validated project.
113112 """
114- return _collect_yml_files (get_compose_base_path () / _validated_project_name (project_name ))
113+ project_dir = resolve_compose_project_dir (project_name )
114+ return _compose_file_matches (project_dir )
115115
116116
117117def resolve_project_compose_manifest (project_name ):
0 commit comments