unleashed-firmware/scripts/fbt/util.py

113 lines
2.9 KiB
Python
Raw Normal View History

import os
import re
import subprocess
import sys
import webbrowser
from pathlib import Path, PurePosixPath
import SCons
from SCons.Errors import StopError
from SCons.Subst import quote_spaces
WINPATHSEP_RE = re.compile(r"\\([^\"'\\]|$)")
# Used by default when globbing for files with GlobRecursive
# Excludes all files ending with ~, usually created by editors as backup files
GLOB_FILE_EXCLUSION = ["*~"]
# List of environment variables to proxy to child processes
FORWARDED_ENV_VARIABLES = [
# CI/CD variables
"WORKFLOW_BRANCH_OR_TAG",
"DIST_SUFFIX",
2023-12-19 13:27:23 +00:00
"FORCE_NO_DIRTY",
# Python & other tools
"HOME",
"APPDATA",
"PYTHONHOME",
"PYTHONNOUSERSITE",
"TMP",
"TEMP",
"USERPROFILE",
"LOCALAPPDATA",
# ccache
"CCACHE_DISABLE",
# Colors for tools
"TERM",
# Toolchain
"FBT_TOOLCHAIN_PATH",
"UFBT_HOME",
]
def tempfile_arg_esc_func(arg):
arg = quote_spaces(arg)
if SCons.Platform.platform_default() != "win32":
return arg
# GCC requires double Windows slashes, let's use UNIX separator
return WINPATHSEP_RE.sub(r"/\1", arg)
def wrap_tempfile(env, command):
env[command] = '${TEMPFILE("' + env[command] + '","$' + command + 'STR")}'
def link_dir(target_path, source_path, is_windows):
# print(f"link_dir: {target_path} -> {source_path}")
if os.path.lexists(target_path) or os.path.exists(target_path):
os.unlink(target_path)
if is_windows:
# Crete junction
import _winapi
if not os.path.isdir(source_path):
raise StopError(f"Source directory {source_path} is not a directory")
if not os.path.exists(target_path):
_winapi.CreateJunction(source_path, target_path)
else:
os.symlink(source_path, target_path)
def single_quote(arg_list):
return " ".join(f"'{arg}'" if " " in arg else str(arg) for arg in arg_list)
def resolve_real_dir_node(node):
if isinstance(node, SCons.Node.FS.EntryProxy):
node = node.get()
for repo_dir in node.get_all_rdirs():
if os.path.exists(repo_dir.abspath):
return repo_dir
raise StopError(f"Can't find absolute path for {node.name} ({node})")
class PosixPathWrapper:
def __init__(self, pathobj):
self.pathobj = pathobj
@staticmethod
def fixup_separators(path):
if SCons.Platform.platform_default() == "win32":
return path.replace(os.path.sep, os.path.altsep)
return path
@staticmethod
def fix_path(path):
return str(PurePosixPath(Path(path).as_posix()))
def __call__(self, target, source, env, for_signature):
if for_signature:
return self.pathobj
return self.fix_path(env.subst(self.pathobj))
def open_browser_action(target, source, env):
if sys.platform == "darwin":
subprocess.run(["open", source[0].abspath])
else:
webbrowser.open(source[0].abspath)