1*9e94795aSAndroid Build Coastguard Worker#!/usr/bin/env python3 2*9e94795aSAndroid Build Coastguard Worker# 3*9e94795aSAndroid Build Coastguard Worker# Copyright (C) 2009 The Android Open Source Project 4*9e94795aSAndroid Build Coastguard Worker# 5*9e94795aSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 6*9e94795aSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 7*9e94795aSAndroid Build Coastguard Worker# You may obtain a copy of the License at 8*9e94795aSAndroid Build Coastguard Worker# 9*9e94795aSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 10*9e94795aSAndroid Build Coastguard Worker# 11*9e94795aSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 12*9e94795aSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 13*9e94795aSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14*9e94795aSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 15*9e94795aSAndroid Build Coastguard Worker# limitations under the License. 16*9e94795aSAndroid Build Coastguard Worker# 17*9e94795aSAndroid Build Coastguard Worker 18*9e94795aSAndroid Build Coastguard Worker# 19*9e94795aSAndroid Build Coastguard Worker# Finds files with the specified name under a particular directory, stopping 20*9e94795aSAndroid Build Coastguard Worker# the search in a given subdirectory when the file is found. 21*9e94795aSAndroid Build Coastguard Worker# 22*9e94795aSAndroid Build Coastguard Worker 23*9e94795aSAndroid Build Coastguard Workerimport os 24*9e94795aSAndroid Build Coastguard Workerimport sys 25*9e94795aSAndroid Build Coastguard Worker 26*9e94795aSAndroid Build Coastguard Workerdef perform_find(mindepth, prune, dirlist, filenames): 27*9e94795aSAndroid Build Coastguard Worker result = [] 28*9e94795aSAndroid Build Coastguard Worker pruneleaves = set(map(lambda x: os.path.split(x)[1], prune)) 29*9e94795aSAndroid Build Coastguard Worker seen = set() 30*9e94795aSAndroid Build Coastguard Worker for rootdir in dirlist: 31*9e94795aSAndroid Build Coastguard Worker rootdepth = rootdir.count("/") 32*9e94795aSAndroid Build Coastguard Worker for root, dirs, files in os.walk(rootdir, followlinks=True): 33*9e94795aSAndroid Build Coastguard Worker # prune 34*9e94795aSAndroid Build Coastguard Worker check_prune = False 35*9e94795aSAndroid Build Coastguard Worker for d in dirs: 36*9e94795aSAndroid Build Coastguard Worker if d in pruneleaves: 37*9e94795aSAndroid Build Coastguard Worker check_prune = True 38*9e94795aSAndroid Build Coastguard Worker break 39*9e94795aSAndroid Build Coastguard Worker if check_prune: 40*9e94795aSAndroid Build Coastguard Worker i = 0 41*9e94795aSAndroid Build Coastguard Worker while i < len(dirs): 42*9e94795aSAndroid Build Coastguard Worker if dirs[i] in prune: 43*9e94795aSAndroid Build Coastguard Worker del dirs[i] 44*9e94795aSAndroid Build Coastguard Worker else: 45*9e94795aSAndroid Build Coastguard Worker i += 1 46*9e94795aSAndroid Build Coastguard Worker # mindepth 47*9e94795aSAndroid Build Coastguard Worker if mindepth > 0: 48*9e94795aSAndroid Build Coastguard Worker depth = 1 + root.count("/") - rootdepth 49*9e94795aSAndroid Build Coastguard Worker if depth < mindepth: 50*9e94795aSAndroid Build Coastguard Worker continue 51*9e94795aSAndroid Build Coastguard Worker # match 52*9e94795aSAndroid Build Coastguard Worker for filename in filenames: 53*9e94795aSAndroid Build Coastguard Worker if filename in files: 54*9e94795aSAndroid Build Coastguard Worker result.append(os.path.join(root, filename)) 55*9e94795aSAndroid Build Coastguard Worker del dirs[:] 56*9e94795aSAndroid Build Coastguard Worker 57*9e94795aSAndroid Build Coastguard Worker # filter out inodes that have already been seen due to symlink loops 58*9e94795aSAndroid Build Coastguard Worker i = 0 59*9e94795aSAndroid Build Coastguard Worker while i < len(dirs): 60*9e94795aSAndroid Build Coastguard Worker st = os.stat(os.path.join(root, dirs[i])) 61*9e94795aSAndroid Build Coastguard Worker key = (st.st_dev, st.st_ino) 62*9e94795aSAndroid Build Coastguard Worker if key in seen: 63*9e94795aSAndroid Build Coastguard Worker del dirs[i] 64*9e94795aSAndroid Build Coastguard Worker else: 65*9e94795aSAndroid Build Coastguard Worker i += 1 66*9e94795aSAndroid Build Coastguard Worker seen.add(key) 67*9e94795aSAndroid Build Coastguard Worker 68*9e94795aSAndroid Build Coastguard Worker return result 69*9e94795aSAndroid Build Coastguard Worker 70*9e94795aSAndroid Build Coastguard Workerdef usage(): 71*9e94795aSAndroid Build Coastguard Worker sys.stderr.write("""Usage: %(progName)s [<options>] [--dir=<dir>] <filenames> 72*9e94795aSAndroid Build Coastguard WorkerOptions: 73*9e94795aSAndroid Build Coastguard Worker --mindepth=<mindepth> 74*9e94795aSAndroid Build Coastguard Worker Both behave in the same way as their find(1) equivalents. 75*9e94795aSAndroid Build Coastguard Worker --prune=<dirname> 76*9e94795aSAndroid Build Coastguard Worker Avoids returning results from inside any directory called <dirname> 77*9e94795aSAndroid Build Coastguard Worker (e.g., "*/out/*"). May be used multiple times. 78*9e94795aSAndroid Build Coastguard Worker --dir=<dir> 79*9e94795aSAndroid Build Coastguard Worker Add a directory to search. May be repeated multiple times. For backwards 80*9e94795aSAndroid Build Coastguard Worker compatibility, if no --dir argument is provided then all but the last entry 81*9e94795aSAndroid Build Coastguard Worker in <filenames> are treated as directories. 82*9e94795aSAndroid Build Coastguard Worker""" % { 83*9e94795aSAndroid Build Coastguard Worker "progName": os.path.split(sys.argv[0])[1], 84*9e94795aSAndroid Build Coastguard Worker }) 85*9e94795aSAndroid Build Coastguard Worker sys.exit(1) 86*9e94795aSAndroid Build Coastguard Worker 87*9e94795aSAndroid Build Coastguard Workerdef main(argv): 88*9e94795aSAndroid Build Coastguard Worker mindepth = -1 89*9e94795aSAndroid Build Coastguard Worker prune = [] 90*9e94795aSAndroid Build Coastguard Worker dirlist = [] 91*9e94795aSAndroid Build Coastguard Worker i=1 92*9e94795aSAndroid Build Coastguard Worker while i<len(argv) and len(argv[i])>2 and argv[i][0:2] == "--": 93*9e94795aSAndroid Build Coastguard Worker arg = argv[i] 94*9e94795aSAndroid Build Coastguard Worker if arg.startswith("--mindepth="): 95*9e94795aSAndroid Build Coastguard Worker try: 96*9e94795aSAndroid Build Coastguard Worker mindepth = int(arg[len("--mindepth="):]) 97*9e94795aSAndroid Build Coastguard Worker except ValueError: 98*9e94795aSAndroid Build Coastguard Worker usage() 99*9e94795aSAndroid Build Coastguard Worker elif arg.startswith("--prune="): 100*9e94795aSAndroid Build Coastguard Worker p = arg[len("--prune="):] 101*9e94795aSAndroid Build Coastguard Worker if len(p) == 0: 102*9e94795aSAndroid Build Coastguard Worker usage() 103*9e94795aSAndroid Build Coastguard Worker prune.append(p) 104*9e94795aSAndroid Build Coastguard Worker elif arg.startswith("--dir="): 105*9e94795aSAndroid Build Coastguard Worker d = arg[len("--dir="):] 106*9e94795aSAndroid Build Coastguard Worker if len(d) == 0: 107*9e94795aSAndroid Build Coastguard Worker usage() 108*9e94795aSAndroid Build Coastguard Worker dirlist.append(d) 109*9e94795aSAndroid Build Coastguard Worker else: 110*9e94795aSAndroid Build Coastguard Worker usage() 111*9e94795aSAndroid Build Coastguard Worker i += 1 112*9e94795aSAndroid Build Coastguard Worker if len(dirlist) == 0: # backwards compatibility 113*9e94795aSAndroid Build Coastguard Worker if len(argv)-i < 2: # need both <dirlist> and <filename> 114*9e94795aSAndroid Build Coastguard Worker usage() 115*9e94795aSAndroid Build Coastguard Worker dirlist = argv[i:-1] 116*9e94795aSAndroid Build Coastguard Worker filenames = [argv[-1]] 117*9e94795aSAndroid Build Coastguard Worker else: 118*9e94795aSAndroid Build Coastguard Worker if len(argv)-i < 1: # need <filename> 119*9e94795aSAndroid Build Coastguard Worker usage() 120*9e94795aSAndroid Build Coastguard Worker filenames = argv[i:] 121*9e94795aSAndroid Build Coastguard Worker results = list(set(perform_find(mindepth, prune, dirlist, filenames))) 122*9e94795aSAndroid Build Coastguard Worker results.sort() 123*9e94795aSAndroid Build Coastguard Worker for r in results: 124*9e94795aSAndroid Build Coastguard Worker print(r) 125*9e94795aSAndroid Build Coastguard Worker 126*9e94795aSAndroid Build Coastguard Workerif __name__ == "__main__": 127*9e94795aSAndroid Build Coastguard Worker main(sys.argv) 128