# # 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. """ import posixpath import re import sys def get_mounts(mount_output): """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 = [] 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): """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 len(mounts) == 0: 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(): # 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()