240 lines
6.3 KiB
Python
240 lines
6.3 KiB
Python
#
|
|
# File : env_package.py
|
|
# This file is part of RT-Thread RTOS
|
|
#
|
|
# SPDX-License-Identifier: GPL-2.0+
|
|
#
|
|
# Change Logs:
|
|
# Date Author Notes
|
|
# 2026-06-12 CYFS Add shared package path helpers
|
|
#
|
|
|
|
import fnmatch
|
|
import os
|
|
|
|
|
|
def _same_path(path_a, path_b):
|
|
return os.path.normcase(os.path.abspath(path_a)) == os.path.normcase(os.path.abspath(path_b))
|
|
|
|
|
|
def _format_path(path, relative_to=None, pathsep=None):
|
|
if relative_to:
|
|
path = os.path.relpath(path, relative_to)
|
|
|
|
if pathsep:
|
|
path = path.replace(os.path.sep, pathsep)
|
|
if os.path.altsep:
|
|
path = path.replace(os.path.altsep, pathsep)
|
|
|
|
return path
|
|
|
|
|
|
def _marker_exists(package_path, marker):
|
|
if not marker:
|
|
return True
|
|
|
|
if isinstance(marker, (list, tuple)):
|
|
for item in marker:
|
|
if not _marker_exists(package_path, item):
|
|
return False
|
|
return True
|
|
|
|
return os.path.exists(os.path.join(package_path, marker))
|
|
|
|
|
|
def _unique_paths(paths):
|
|
unique_paths = []
|
|
seen = set()
|
|
|
|
for path in paths:
|
|
if not path:
|
|
continue
|
|
|
|
key = os.path.normcase(os.path.abspath(path))
|
|
if key in seen:
|
|
continue
|
|
|
|
seen.add(key)
|
|
unique_paths.append(path)
|
|
|
|
return unique_paths
|
|
|
|
|
|
def package_root_candidates(bsp_root):
|
|
bsp_root = os.path.abspath(bsp_root)
|
|
ancestors = []
|
|
current = bsp_root
|
|
|
|
while True:
|
|
if _is_rt_thread_bsp_dir(current):
|
|
break
|
|
|
|
ancestors.append(current)
|
|
|
|
parent = os.path.dirname(current)
|
|
if _same_path(parent, current):
|
|
break
|
|
|
|
current = parent
|
|
|
|
library_roots = [os.path.join(root, 'libraries') for root in ancestors]
|
|
package_roots = [os.path.join(root, 'packages') for root in ancestors]
|
|
|
|
return _unique_paths(library_roots + package_roots)
|
|
|
|
|
|
def package_candidates(bsp_root, package_name, extra_candidates=None):
|
|
candidates = []
|
|
for root in package_root_candidates(bsp_root):
|
|
candidates.append(os.path.join(root, package_name))
|
|
|
|
if extra_candidates:
|
|
candidates.extend(extra_candidates)
|
|
|
|
return _unique_paths(candidates)
|
|
|
|
|
|
def find_package_path(bsp_root, package_name, marker=None, extra_candidates=None,
|
|
relative_to=None, pathsep=None):
|
|
candidates = package_candidates(bsp_root, package_name, extra_candidates)
|
|
existing_paths = []
|
|
|
|
for path in candidates:
|
|
if not os.path.isdir(path):
|
|
continue
|
|
|
|
existing_paths.append(path)
|
|
if _marker_exists(path, marker):
|
|
return _format_path(path, relative_to, pathsep)
|
|
|
|
if existing_paths:
|
|
return _format_path(existing_paths[0], relative_to, pathsep)
|
|
|
|
fallback_path = os.path.join(os.path.abspath(bsp_root), 'packages', package_name)
|
|
return _format_path(fallback_path, relative_to, pathsep)
|
|
|
|
|
|
def package_exists(bsp_root, package_name, marker=None):
|
|
path = find_package_path(bsp_root, package_name, marker=marker)
|
|
return os.path.isdir(path) and _marker_exists(path, marker)
|
|
|
|
|
|
def packages_available(bsp_root, package_names):
|
|
for package_name in package_names:
|
|
if not package_exists(bsp_root, package_name):
|
|
return False
|
|
|
|
return True
|
|
|
|
|
|
def _package_name_match(name, package_name=None, package_prefix=None, package_pattern=None):
|
|
if package_name and name != package_name:
|
|
return False
|
|
|
|
if package_prefix and not name.startswith(package_prefix):
|
|
return False
|
|
|
|
if package_pattern and not fnmatch.fnmatch(name, package_pattern):
|
|
return False
|
|
|
|
return True
|
|
|
|
|
|
def find_package_root(bsp_root, package_name=None, package_prefix=None,
|
|
package_pattern=None, marker=None):
|
|
for root in package_root_candidates(bsp_root):
|
|
if not os.path.isdir(root):
|
|
continue
|
|
|
|
if package_name:
|
|
package_path = os.path.join(root, package_name)
|
|
if os.path.isdir(package_path) and _marker_exists(package_path, marker):
|
|
return root
|
|
continue
|
|
|
|
try:
|
|
names = os.listdir(root)
|
|
except OSError:
|
|
continue
|
|
|
|
for name in names:
|
|
package_path = os.path.join(root, name)
|
|
if not os.path.isdir(package_path):
|
|
continue
|
|
if not _package_name_match(name, package_name, package_prefix, package_pattern):
|
|
continue
|
|
if _marker_exists(package_path, marker):
|
|
return root
|
|
|
|
return None
|
|
|
|
|
|
def is_libraries_package(package_path):
|
|
return os.path.basename(os.path.dirname(os.path.abspath(package_path))).lower() == 'libraries'
|
|
|
|
|
|
def _get_existing_libraries_path(root):
|
|
exact_path = os.path.join(root, 'libraries')
|
|
if os.path.isdir(exact_path):
|
|
return exact_path
|
|
|
|
try:
|
|
for name in os.listdir(root):
|
|
path = os.path.join(root, name)
|
|
if name.lower() == 'libraries' and os.path.isdir(path):
|
|
return path
|
|
except OSError:
|
|
pass
|
|
|
|
return None
|
|
|
|
|
|
def _is_rt_thread_bsp_dir(path):
|
|
parent = os.path.dirname(path)
|
|
return (
|
|
os.path.basename(path).lower() == 'bsp'
|
|
and os.path.isdir(os.path.join(parent, 'bsp'))
|
|
and os.path.isfile(os.path.join(parent, 'include', 'rtdef.h'))
|
|
)
|
|
|
|
|
|
def find_libraries_path_upward(bsp_root):
|
|
current = os.path.abspath(bsp_root)
|
|
|
|
while True:
|
|
libraries_path = _get_existing_libraries_path(current)
|
|
if libraries_path:
|
|
return libraries_path
|
|
|
|
if _is_rt_thread_bsp_dir(current):
|
|
return None
|
|
|
|
parent = os.path.dirname(current)
|
|
if _same_path(parent, current):
|
|
return None
|
|
|
|
current = parent
|
|
|
|
|
|
def is_hal_sdk_package_bridge(package_path):
|
|
if os.path.isdir(os.path.join(package_path, '.git')):
|
|
return False
|
|
|
|
sconscript_path = os.path.join(package_path, 'SConscript')
|
|
if not os.path.isfile(sconscript_path):
|
|
return False
|
|
|
|
try:
|
|
with open(sconscript_path, 'r') as f:
|
|
content = f.read()
|
|
return (
|
|
'hal-sdk package source not found' in content
|
|
and (
|
|
'source_candidates' in content
|
|
or '_find_hal_sdk_libraries_path' in content
|
|
or 'libraries_path_prefix' in content
|
|
)
|
|
)
|
|
except Exception:
|
|
return False
|