# # Copyright (C) 2017 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # """Generates a make function approximating cygpath. We don't just call cygpath (unless directed by NDK_USE_CYGPATH=1) because we have to call this very often and doing so would be very slow. By doing this in make, we can be much faster. """ from __future__ import print_function import posixpath import re import sys def get_mounts(mount_output: str) -> list[tuple[str, str]]: """Parses the output of mount and returns a dict of mounts. Args: mount_output: The text output from mount(1). Returns: A list of tuples mapping cygwin paths to Windows paths. """ mount_regex = re.compile(r"^(\S+) on (\S+) .*$") # We use a list of tuples rather than a dict because we want to recurse on # the list later anyway. mounts: list[tuple[str, str]] = [] for line in mount_output.splitlines(): # Cygwin's mount doesn't use backslashes even in Windows paths, so no # need to replace here. match = mount_regex.search(line) if match is not None: win_path = match.group(1) cyg_path = match.group(2) if cyg_path == "/": # Since we're going to be using patsubst on these, we need to # make sure that the rule for / is applied last, otherwise # we'll replace all other cygwin paths with that one. mounts.insert(0, (cyg_path, win_path)) elif cyg_path.startswith("/cygdrive/"): # We need both /cygdrive/c and /cygdrive/C to point to C:. letter = posixpath.basename(cyg_path) lower_path = posixpath.join("/cygdrive", letter.lower()) upper_path = posixpath.join("/cygdrive", letter.upper()) mounts.append((lower_path, win_path)) mounts.append((upper_path, win_path)) else: mounts.append((cyg_path, win_path)) return mounts def make_cygpath_function(mounts: list[tuple[str, str]]) -> str: """Creates a make function that can be used in place of cygpath. Args: mounts: A list of tuples decribing filesystem mounts. Returns: The body of a function implementing cygpath in make as a string. """ # We're building a bunch of nested patsubst calls. Once we've written each # of the calls, we pass the function input to the inner most call. if not mounts: return "$1" cyg_path, win_path = mounts[0] if not cyg_path.endswith("/"): cyg_path += "/" if not win_path.endswith("/"): win_path += "/" other_mounts = mounts[1:] return "$(patsubst {}%,{}%,\n{})".format( cyg_path, win_path, make_cygpath_function(other_mounts) ) def main() -> None: # We're invoked from make and piped the output of `mount` so we can # determine what mappings to make. mount_output = sys.stdin.read() mounts = get_mounts(mount_output) print(make_cygpath_function(mounts)) if __name__ == "__main__": main()