# # Copyright (c) 2006 João Abecasis # 2006 Mark Evans # # # Distributed under the Boost Software License, Version 1.0. (See # accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) # # This is based on earlier work by João Abecasis described at # http://article.gmane.org/gmane.comp.lib.boost.devel/140966 import path ; import set ; # # Recursively find files matching a given pattern in a set of filesystem # trees. Files that match a file-skip pattern (parameter skip-patterns-or-files) # are pruned from the result set. Similarly, directories that match a # directory-skip pattern (parameter skip-patterns-or-dirs) are pruned. # The number of recursion levels can be limited with optional max-depth # argument. For example, max-depth of 1 limits the search to 1 level of # subdirectories. By default, there is no recursion limit. # # Example: # # [ recursive-find . : *.cpp *.h : bar* : bum* : 5 ] # # searches the current directory (of invoking jamfile) for *.cpp and *.h # files, excluding any files that match "bar*" and excluding any # directories that match "bum*". Subdirectory depth is limited to 5. # rule recursive-find ( search-dirs + # trees to search : patterns-or-files * # patterns to search for : skip-patterns-or-files * # patterns for files to be pruned : skip-patterns-or-dirs * # patterns for directories to be pruned : max-depth ? # maximum number of recursion levels ) { max-depth ?= -1 ; local all-nodes = [ path.glob $(search-dirs) : * ] ; local skipped-files ; if $(skip-patterns-or-files) { skipped-files = [ path.glob $(search-dirs) : $(skip-patterns-or-files) ] ; } local skipped-dirs ; if $(skip-patterns-or-dirs) { skipped-dirs = [ path.glob $(search-dirs) : $(skip-patterns-or-dirs) ] ; } local matching-nodes = [ path.glob $(search-dirs) : $(patterns-or-files) ] ; local potential-dirs = [ set.difference $(all-nodes) : $(skipped-dirs) ] ; # Remove files from potential-dirs list (hopefully to improve performance). # Wish path.glob had an option to return only directories or only files. local dirs ; for local p in $(potential-dirs) { if ! [ CHECK_IF_FILE $(p) ] { dirs += $(p) ; } } matching-nodes = [ set.difference $(matching-nodes) : $(skipped-files) ] ; if $(dirs) && ( $(max-depth) != 0 ) { matching-nodes += [ recursive-find $(dirs) : $(patterns-or-files) : $(skip-patterns-or-files) : $(skip-patterns-or-dirs) : [ CALC $(max-depth) - 1 ] ] ; } return $(matching-nodes) ; }