1# Copyright 2024 The Chromium Authors 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5import pathlib 6import re 7import unicodedata 8from typing import Optional, Union 9 10# A path that can refer to files on a remote platform with potentially 11# a different Path flavour (e.g. Win vs Posix). 12AnyPath = pathlib.PurePath 13AnyPosixPath = pathlib.PurePosixPath 14AnyWindowsPath = pathlib.PureWindowsPath 15 16AnyPathLike = Union[str, AnyPath] 17 18# A path that only ever refers to files on the local host / runner platform. 19# Not that Path inherits from PurePath, and thus we can use a LocalPath in 20# all places a RemotePath is expected. 21LocalPath = pathlib.Path 22LocalPosixPath = pathlib.PosixPath 23 24LocalPathLike = Union[str, LocalPath] 25 26_UNSAFE_FILENAME_CHARS_RE = re.compile(r"[^a-zA-Z0-9+\-_.]") 27 28 29def safe_filename(name: str) -> str: 30 normalized_name = unicodedata.normalize("NFKD", name) 31 ascii_name = normalized_name.encode("ascii", "ignore").decode("ascii") 32 return _UNSAFE_FILENAME_CHARS_RE.sub("_", ascii_name) 33 34 35def try_resolve_existing_path(value: str) -> Optional[LocalPath]: 36 if not value: 37 return None 38 maybe_path = LocalPath(value) 39 if maybe_path.exists(): 40 return maybe_path 41 maybe_path = maybe_path.expanduser() 42 if maybe_path.exists(): 43 return maybe_path 44 return None 45