| # Status: this module is ported on demand by however needs something |
| # from it. Functionality that is not needed by Python port will |
| # be dropped. |
| |
| # Copyright (C) Vladimir Prus 2002. Permission to copy, use, modify, sell and |
| # distribute this software is granted provided this copyright notice appears in |
| # all copies. This software is provided "as is" without express or implied |
| # warranty, and with no claim as to its suitability for any purpose. |
| |
| # Performs various path manipulations. Path are always in a 'normilized' |
| # representation. In it, a path may be either: |
| # |
| # - '.', or |
| # |
| # - ['/'] [ ( '..' '/' )* (token '/')* token ] |
| # |
| # In plain english, path can be rooted, '..' elements are allowed only |
| # at the beginning, and it never ends in slash, except for path consisting |
| # of slash only. |
| |
| import os.path |
| from utility import to_seq |
| from glob import glob as builtin_glob |
| |
| def root (path, root): |
| """ If 'path' is relative, it is rooted at 'root'. Otherwise, it's unchanged. |
| """ |
| if os.path.isabs (path): |
| return path |
| else: |
| return os.path.join (root, path) |
| |
| def make (native): |
| """ Converts the native path into normalized form. |
| """ |
| # TODO: make os selection here. |
| return make_UNIX (native) |
| |
| def make_UNIX (native): |
| |
| # VP: I have no idea now 'native' can be empty here! But it can! |
| assert (native) |
| |
| return os.path.normpath (native) |
| |
| def native (path): |
| """ Builds a native representation of the path. |
| """ |
| # TODO: make os selection here. |
| return native_UNIX (path) |
| |
| def native_UNIX (path): |
| return path |
| |
| |
| def pwd (): |
| """ Returns the current working directory. |
| # TODO: is it a good idea to use the current dir? Some use-cases |
| may not allow us to depend on the current dir. |
| """ |
| return make (os.getcwd ()) |
| |
| def is_rooted (path): |
| """ Tests if a path is rooted. |
| """ |
| return path and path [0] == '/' |
| |
| |
| ################################################################### |
| # Still to port. |
| # Original lines are prefixed with "# " |
| # |
| # # Copyright (C) Vladimir Prus 2002. Permission to copy, use, modify, sell and |
| # # distribute this software is granted provided this copyright notice appears in |
| # # all copies. This software is provided "as is" without express or implied |
| # # warranty, and with no claim as to its suitability for any purpose. |
| # |
| # # Performs various path manipulations. Path are always in a 'normilized' |
| # # representation. In it, a path may be either: |
| # # |
| # # - '.', or |
| # # |
| # # - ['/'] [ ( '..' '/' )* (token '/')* token ] |
| # # |
| # # In plain english, path can be rooted, '..' elements are allowed only |
| # # at the beginning, and it never ends in slash, except for path consisting |
| # # of slash only. |
| # |
| # import modules ; |
| # import sequence ; |
| # import regex ; |
| # import errors : error ; |
| # |
| # |
| # os = [ modules.peek : OS ] ; |
| # if [ modules.peek : UNIX ] |
| # { |
| # local uname = [ modules.peek : JAMUNAME ] ; |
| # switch $(uname) |
| # { |
| # case CYGWIN* : |
| # os = CYGWIN ; |
| # |
| # case * : |
| # os = UNIX ; |
| # } |
| # } |
| # |
| # # |
| # # Tests if a path is rooted. |
| # # |
| # rule is-rooted ( path ) |
| # { |
| # return [ MATCH "^(/)" : $(path) ] ; |
| # } |
| # |
| # # |
| # # Tests if a path has a parent. |
| # # |
| # rule has-parent ( path ) |
| # { |
| # if $(path) != / { |
| # return 1 ; |
| # } else { |
| # return ; |
| # } |
| # } |
| # |
| # # |
| # # Returns the path without any directory components. |
| # # |
| # rule basename ( path ) |
| # { |
| # return [ MATCH "([^/]+)$" : $(path) ] ; |
| # } |
| # |
| # # |
| # # Returns parent directory of the path. If no parent exists, error is issued. |
| # # |
| # rule parent ( path ) |
| # { |
| # if [ has-parent $(path) ] { |
| # |
| # if $(path) = . { |
| # return .. ; |
| # } else { |
| # |
| # # Strip everything at the end of path up to and including |
| # # the last slash |
| # local result = [ regex.match "((.*)/)?([^/]+)" : $(path) : 2 3 ] ; |
| # |
| # # Did we strip what we shouldn't? |
| # if $(result[2]) = ".." { |
| # return $(path)/.. ; |
| # } else { |
| # if ! $(result[1]) { |
| # if [ is-rooted $(path) ] { |
| # result = / ; |
| # } else { |
| # result = . ; |
| # } |
| # } |
| # return $(result[1]) ; |
| # } |
| # } |
| # } else { |
| # error "Path '$(path)' has no parent" ; |
| # } |
| # } |
| # |
| # # |
| # # Returns path2 such that "[ join path path2 ] = .". |
| # # The path may not contain ".." element or be rooted. |
| # # |
| # rule reverse ( path ) |
| # { |
| # if $(path) = . |
| # { |
| # return $(path) ; |
| # } |
| # else |
| # { |
| # local tokens = [ regex.split $(path) "/" ] ; |
| # local tokens2 ; |
| # for local i in $(tokens) { |
| # tokens2 += .. ; |
| # } |
| # return [ sequence.join $(tokens2) : "/" ] ; |
| # } |
| # } |
| # |
| # # |
| # # Auxillary rule: does all the semantic of 'join', except for error cheching. |
| # # The error checking is separated because this rule is recursive, and I don't |
| # # like the idea of checking the same input over and over. |
| # # |
| # local rule join-imp ( elements + ) |
| # { |
| # return [ NORMALIZE_PATH $(elements:J="/") ] ; |
| # } |
| # |
| # # |
| # # Contanenates the passed path elements. Generates an error if |
| # # any element other than the first one is rooted. |
| # # |
| # rule join ( elements + ) |
| # { |
| # if ! $(elements[2]) |
| # { |
| # return $(elements[1]) ; |
| # } |
| # else |
| # { |
| # for local e in $(elements[2-]) |
| # { |
| # if [ is-rooted $(e) ] |
| # { |
| # error only first element may be rooted ; |
| # } |
| # } |
| # return [ join-imp $(elements) ] ; |
| # } |
| # } |
| |
| |
| def glob (dirs, patterns): |
| """ Returns the list of files matching the given pattern in the |
| specified directory. Both directories and patterns are |
| supplied as portable paths. Each pattern should be non-absolute |
| path, and can't contain "." or ".." elements. Each slash separated |
| element of pattern can contain the following special characters: |
| - '?', which match any character |
| - '*', which matches arbitrary number of characters. |
| A file $(d)/e1/e2/e3 (where 'd' is in $(dirs)) matches pattern p1/p2/p3 |
| if and only if e1 matches p1, e2 matches p2 and so on. |
| |
| For example: |
| [ glob . : *.cpp ] |
| [ glob . : */build/Jamfile ] |
| """ |
| # { |
| # local result ; |
| # if $(patterns:D) |
| # { |
| # # When a pattern has a directory element, we first glob for |
| # # directory, and then glob for file name is the found directories. |
| # for local p in $(patterns) |
| # { |
| # # First glob for directory part. |
| # local globbed-dirs = [ glob $(dirs) : $(p:D) ] ; |
| # result += [ glob $(globbed-dirs) : $(p:D="") ] ; |
| # } |
| # } |
| # else |
| # { |
| # # When a pattern has not directory, we glob directly. |
| # # Take care of special ".." value. The "GLOB" rule simply ignores |
| # # the ".." element (and ".") element in directory listings. This is |
| # # needed so that |
| # # |
| # # [ glob libs/*/Jamfile ] |
| # # |
| # # don't return |
| # # |
| # # libs/../Jamfile (which is the same as ./Jamfile) |
| # # |
| # # On the other hand, when ".." is explicitly present in the pattern |
| # # we need to return it. |
| # # |
| # for local dir in $(dirs) |
| # { |
| # for local p in $(patterns) |
| # { |
| # if $(p) != ".." |
| # { |
| # result += [ sequence.transform make |
| # : [ GLOB [ native $(dir) ] : $(p) ] ] ; |
| # } |
| # else |
| # { |
| # result += [ path.join $(dir) .. ] ; |
| # } |
| # } |
| # } |
| # } |
| # return $(result) ; |
| # } |
| # |
| |
| # TODO: (PF) I replaced the code above by this. I think it should work but needs to be tested. |
| result = [] |
| dirs = to_seq (dirs) |
| patterns = to_seq (patterns) |
| |
| splitdirs = [] |
| for dir in dirs: |
| splitdirs += dir.split (os.pathsep) |
| |
| for dir in splitdirs: |
| for pattern in patterns: |
| p = os.path.join (dir, pattern) |
| import glob |
| result.extend (glob.glob (p)) |
| return result |
| |
| # # |
| # # Returns true is the specified file exists. |
| # # |
| # rule exists ( file ) |
| # { |
| # return [ path.glob $(file:D) : $(file:D=) ] ; |
| # } |
| # NATIVE_RULE path : exists ; |
| # |
| # |
| # |
| # # |
| # # Find out the absolute name of path and returns the list of all the parents, |
| # # starting with the immediate one. Parents are returned as relative names. |
| # # If 'upper_limit' is specified, directories above it will be pruned. |
| # # |
| # rule all-parents ( path : upper_limit ? : cwd ? ) |
| # { |
| # cwd ?= [ pwd ] ; |
| # local path_ele = [ regex.split [ root $(path) $(cwd) ] "/" ] ; |
| # |
| # if ! $(upper_limit) { |
| # upper_limit = / ; |
| # } |
| # local upper_ele = [ regex.split [ root $(upper_limit) $(cwd) ] "/" ] ; |
| # |
| # # Leave only elements in 'path_ele' below 'upper_ele' |
| # while $(path_ele) && $(upper_ele[1]) = $(path_ele[1]) { |
| # upper_ele = $(upper_ele[2-]) ; |
| # path_ele = $(path_ele[2-]) ; |
| # } |
| # |
| # # All upper elements removed ? |
| # if ! $(upper_ele) { |
| # # Create the relative paths to parents, number of elements in 'path_ele' |
| # local result ; |
| # for local i in $(path_ele) { |
| # path = [ parent $(path) ] ; |
| # result += $(path) ; |
| # } |
| # return $(result) ; |
| # } |
| # else { |
| # error "$(upper_limit) is not prefix of $(path)" ; |
| # } |
| # } |
| # |
| # |
| # # |
| # # Search for 'pattern' in parent directories of 'dir', up till and including |
| # # 'upper_limit', if it is specified, or till the filesystem root otherwise. |
| # # |
| # rule glob-in-parents ( dir : patterns + : upper-limit ? ) |
| # { |
| # local result ; |
| # local parent-dirs = [ all-parents $(dir) : $(upper-limit) ] ; |
| # |
| # while $(parent-dirs) && ! $(result) |
| # { |
| # result = [ glob $(parent-dirs[1]) : $(patterns) ] ; |
| # parent-dirs = $(parent-dirs[2-]) ; |
| # } |
| # return $(result) ; |
| # } |
| # |
| # # |
| # # Assuming 'child' is a subdirectory of 'parent', return the relative |
| # # path from 'parent' to 'child' |
| # # |
| # rule relative ( child parent ) |
| # { |
| # if $(parent) = "." |
| # { |
| # return $(child) ; |
| # } |
| # else |
| # { |
| # local split1 = [ regex.split $(parent) / ] ; |
| # local split2 = [ regex.split $(child) / ] ; |
| # |
| # while $(split1) |
| # { |
| # if $(split1[1]) = $(split2[1]) |
| # { |
| # split1 = $(split1[2-]) ; |
| # split2 = $(split2[2-]) ; |
| # } |
| # else |
| # { |
| # errors.error $(child) is not a subdir of $(parent) ; |
| # } |
| # } |
| # return [ join $(split2) ] ; |
| # } |
| # } |
| # |
| # # Returns the minimal path to path2 that is relative path1. |
| # # |
| # rule relative-to ( path1 path2 ) |
| # { |
| # local root_1 = [ regex.split [ reverse $(path1) ] / ] ; |
| # local split1 = [ regex.split $(path1) / ] ; |
| # local split2 = [ regex.split $(path2) / ] ; |
| # |
| # while $(split1) && $(root_1) |
| # { |
| # if $(split1[1]) = $(split2[1]) |
| # { |
| # root_1 = $(root_1[2-]) ; |
| # split1 = $(split1[2-]) ; |
| # split2 = $(split2[2-]) ; |
| # } |
| # else |
| # { |
| # split1 = ; |
| # } |
| # } |
| # return [ join . $(root_1) $(split2) ] ; |
| # } |
| |
| # Returns the list of paths which are used by the operating system |
| # for looking up programs |
| def programs_path (): |
| raw = [] |
| names = ['PATH', 'Path', 'path'] |
| |
| for name in names: |
| raw.append(os.environ.get (name, '')) |
| |
| result = [] |
| for elem in raw: |
| if elem: |
| for p in elem.split(os.path.pathsep): |
| result.append(make(p)) |
| |
| return result |
| |
| # rule make-NT ( native ) |
| # { |
| # local tokens = [ regex.split $(native) "[/\\]" ] ; |
| # local result ; |
| # |
| # # Handle paths ending with slashes |
| # if $(tokens[-1]) = "" |
| # { |
| # tokens = $(tokens[1--2]) ; # discard the empty element |
| # } |
| # |
| # result = [ path.join $(tokens) ] ; |
| # |
| # if [ regex.match "(^.:)" : $(native) ] |
| # { |
| # result = /$(result) ; |
| # } |
| # |
| # if $(native) = "" |
| # { |
| # result = "." ; |
| # } |
| # |
| # return $(result) ; |
| # } |
| # |
| # rule native-NT ( path ) |
| # { |
| # local result = [ MATCH "^/?(.*)" : $(path) ] ; |
| # result = [ sequence.join [ regex.split $(result) "/" ] : "\\" ] ; |
| # return $(result) ; |
| # } |
| # |
| # rule make-CYGWIN ( path ) |
| # { |
| # return [ make-NT $(path) ] ; |
| # } |
| # |
| # rule native-CYGWIN ( path ) |
| # { |
| # local result = $(path) ; |
| # if [ regex.match "(^/.:)" : $(path) ] # win absolute |
| # { |
| # result = [ MATCH "^/?(.*)" : $(path) ] ; # remove leading '/' |
| # } |
| # return [ native-UNIX $(result) ] ; |
| # } |
| # |
| # # |
| # # split-VMS: splits input native path into |
| # # device dir file (each part is optional), |
| # # example: |
| # # |
| # # dev:[dir]file.c => dev: [dir] file.c |
| # # |
| # rule split-path-VMS ( native ) |
| # { |
| # local matches = [ MATCH ([a-zA-Z0-9_-]+:)?(\\[[^\]]*\\])?(.*)?$ : $(native) ] ; |
| # local device = $(matches[1]) ; |
| # local dir = $(matches[2]) ; |
| # local file = $(matches[3]) ; |
| # |
| # return $(device) $(dir) $(file) ; |
| # } |
| # |
| # # |
| # # Converts a native VMS path into a portable path spec. |
| # # |
| # # Does not handle current-device absolute paths such |
| # # as "[dir]File.c" as it is not clear how to represent |
| # # them in the portable path notation. |
| # # |
| # # Adds a trailing dot (".") to the file part if no extension |
| # # is present (helps when converting it back into native path). |
| # # |
| # rule make-VMS ( native ) |
| # { |
| # if [ MATCH ^(\\[[a-zA-Z0-9]) : $(native) ] |
| # { |
| # errors.error "Can't handle default-device absolute paths: " $(native) ; |
| # } |
| # |
| # local parts = [ split-path-VMS $(native) ] ; |
| # local device = $(parts[1]) ; |
| # local dir = $(parts[2]) ; |
| # local file = $(parts[3]) ; |
| # local elems ; |
| # |
| # if $(device) |
| # { |
| # # |
| # # rooted |
| # # |
| # elems = /$(device) ; |
| # } |
| # |
| # if $(dir) = "[]" |
| # { |
| # # |
| # # Special case: current directory |
| # # |
| # elems = $(elems) "." ; |
| # } |
| # else if $(dir) |
| # { |
| # dir = [ regex.replace $(dir) "\\[|\\]" "" ] ; |
| # local dir_parts = [ regex.split $(dir) \\. ] ; |
| # |
| # if $(dir_parts[1]) = "" |
| # { |
| # # |
| # # Relative path |
| # # |
| # dir_parts = $(dir_parts[2--1]) ; |
| # } |
| # |
| # # |
| # # replace "parent-directory" parts (- => ..) |
| # # |
| # dir_parts = [ regex.replace-list $(dir_parts) : - : .. ] ; |
| # |
| # elems = $(elems) $(dir_parts) ; |
| # } |
| # |
| # if $(file) |
| # { |
| # if ! [ MATCH (\\.) : $(file) ] |
| # { |
| # # |
| # # Always add "." to end of non-extension file |
| # # |
| # file = $(file). ; |
| # } |
| # elems = $(elems) $(file) ; |
| # } |
| # |
| # local portable = [ path.join $(elems) ] ; |
| # |
| # return $(portable) ; |
| # } |
| # |
| # # |
| # # Converts a portable path spec into a native VMS path. |
| # # |
| # # Relies on having at least one dot (".") included in the file |
| # # name to be able to differentiate it ftom the directory part. |
| # # |
| # rule native-VMS ( path ) |
| # { |
| # local device = "" ; |
| # local dir = $(path) ; |
| # local file = "" ; |
| # local native ; |
| # local split ; |
| # |
| # # |
| # # Has device ? |
| # # |
| # if [ is-rooted $(dir) ] |
| # { |
| # split = [ MATCH ^/([^:]+:)/?(.*) : $(dir) ] ; |
| # device = $(split[1]) ; |
| # dir = $(split[2]) ; |
| # } |
| # |
| # # |
| # # Has file ? |
| # # |
| # # This is no exact science, just guess work: |
| # # |
| # # If the last part of the current path spec |
| # # includes some chars, followed by a dot, |
| # # optionally followed by more chars - |
| # # then it is a file (keep your fingers crossed). |
| # # |
| # split = [ regex.split $(dir) / ] ; |
| # local maybe_file = $(split[-1]) ; |
| # |
| # if [ MATCH ^([^.]+\\..*) : $(maybe_file) ] |
| # { |
| # file = $(maybe_file) ; |
| # dir = [ sequence.join $(split[1--2]) : / ] ; |
| # } |
| # |
| # # |
| # # Has dir spec ? |
| # # |
| # if $(dir) = "." |
| # { |
| # dir = "[]" ; |
| # } |
| # else if $(dir) |
| # { |
| # dir = [ regex.replace $(dir) \\.\\. - ] ; |
| # dir = [ regex.replace $(dir) / . ] ; |
| # |
| # if $(device) = "" |
| # { |
| # # |
| # # Relative directory |
| # # |
| # dir = "."$(dir) ; |
| # } |
| # dir = "["$(dir)"]" ; |
| # } |
| # |
| # native = [ sequence.join $(device) $(dir) $(file) ] ; |
| # |
| # return $(native) ; |
| # } |
| # |
| # |
| # rule __test__ ( ) { |
| # |
| # import assert ; |
| # import errors : try catch ; |
| # |
| # assert.true is-rooted "/" ; |
| # assert.true is-rooted "/foo" ; |
| # assert.true is-rooted "/foo/bar" ; |
| # assert.result : is-rooted "." ; |
| # assert.result : is-rooted "foo" ; |
| # assert.result : is-rooted "foo/bar" ; |
| # |
| # assert.true has-parent "foo" ; |
| # assert.true has-parent "foo/bar" ; |
| # assert.true has-parent "." ; |
| # assert.result : has-parent "/" ; |
| # |
| # assert.result "." : basename "." ; |
| # assert.result ".." : basename ".." ; |
| # assert.result "foo" : basename "foo" ; |
| # assert.result "foo" : basename "bar/foo" ; |
| # assert.result "foo" : basename "gaz/bar/foo" ; |
| # assert.result "foo" : basename "/gaz/bar/foo" ; |
| # |
| # assert.result "." : parent "foo" ; |
| # assert.result "/" : parent "/foo" ; |
| # assert.result "foo/bar" : parent "foo/bar/giz" ; |
| # assert.result ".." : parent "." ; |
| # assert.result ".." : parent "../foo" ; |
| # assert.result "../../foo" : parent "../../foo/bar" ; |
| # |
| # |
| # assert.result "." : reverse "." ; |
| # assert.result ".." : reverse "foo" ; |
| # assert.result "../../.." : reverse "foo/bar/giz" ; |
| # |
| # assert.result "foo" : join "foo" ; |
| # assert.result "/foo" : join "/" "foo" ; |
| # assert.result "foo/bar" : join "foo" "bar" ; |
| # assert.result "foo/bar" : join "foo/giz" "../bar" ; |
| # assert.result "foo/giz" : join "foo/bar/baz" "../../giz" ; |
| # assert.result ".." : join "." ".." ; |
| # assert.result ".." : join "foo" "../.." ; |
| # assert.result "../.." : join "../foo" "../.." ; |
| # assert.result "/foo" : join "/bar" "../foo" ; |
| # assert.result "foo/giz" : join "foo/giz" "." ; |
| # assert.result "." : join lib2 ".." ; |
| # assert.result "/" : join "/a" ".." ; |
| # |
| # assert.result /a/b : join /a/b/c .. ; |
| # |
| # assert.result "foo/bar/giz" : join "foo" "bar" "giz" ; |
| # assert.result "giz" : join "foo" ".." "giz" ; |
| # assert.result "foo/giz" : join "foo" "." "giz" ; |
| # |
| # try ; |
| # { |
| # join "a" "/b" ; |
| # } |
| # catch only first element may be rooted ; |
| # |
| # local CWD = "/home/ghost/build" ; |
| # assert.result : all-parents . : . : $(CWD) ; |
| # assert.result . .. ../.. ../../.. : all-parents "Jamfile" : "" : $(CWD) ; |
| # assert.result foo . .. ../.. ../../.. : all-parents "foo/Jamfile" : "" : $(CWD) ; |
| # assert.result ../Work .. ../.. ../../.. : all-parents "../Work/Jamfile" : "" : $(CWD) ; |
| # |
| # local CWD = "/home/ghost" ; |
| # assert.result . .. : all-parents "Jamfile" : "/home" : $(CWD) ; |
| # assert.result . : all-parents "Jamfile" : "/home/ghost" : $(CWD) ; |
| # |
| # assert.result "c/d" : relative "a/b/c/d" "a/b" ; |
| # assert.result "foo" : relative "foo" "." ; |
| # |
| # local save-os = [ modules.peek path : os ] ; |
| # modules.poke path : os : NT ; |
| # |
| # assert.result "foo/bar/giz" : make "foo/bar/giz" ; |
| # assert.result "foo/bar/giz" : make "foo\\bar\\giz" ; |
| # assert.result "foo" : make "foo/." ; |
| # assert.result "foo" : make "foo/bar/.." ; |
| # assert.result "/D:/My Documents" : make "D:\\My Documents" ; |
| # assert.result "/c:/boost/tools/build/new/project.jam" : make "c:\\boost\\tools\\build\\test\\..\\new\\project.jam" ; |
| # |
| # assert.result "foo\\bar\\giz" : native "foo/bar/giz" ; |
| # assert.result "foo" : native "foo" ; |
| # assert.result "D:\\My Documents\\Work" : native "/D:/My Documents/Work" ; |
| # |
| # modules.poke path : os : UNIX ; |
| # |
| # assert.result "foo/bar/giz" : make "foo/bar/giz" ; |
| # assert.result "/sub1" : make "/sub1/." ; |
| # assert.result "/sub1" : make "/sub1/sub2/.." ; |
| # assert.result "sub1" : make "sub1/." ; |
| # assert.result "sub1" : make "sub1/sub2/.." ; |
| # assert.result "/foo/bar" : native "/foo/bar" ; |
| # |
| # modules.poke path : os : VMS ; |
| # |
| # # |
| # # Don't really need to poke os before these |
| # # |
| # assert.result "disk:" "[dir]" "file" : split-path-VMS "disk:[dir]file" ; |
| # assert.result "disk:" "[dir]" "" : split-path-VMS "disk:[dir]" ; |
| # assert.result "disk:" "" "" : split-path-VMS "disk:" ; |
| # assert.result "disk:" "" "file" : split-path-VMS "disk:file" ; |
| # assert.result "" "[dir]" "file" : split-path-VMS "[dir]file" ; |
| # assert.result "" "[dir]" "" : split-path-VMS "[dir]" ; |
| # assert.result "" "" "file" : split-path-VMS "file" ; |
| # assert.result "" "" "" : split-path-VMS "" ; |
| # |
| # # |
| # # Special case: current directory |
| # # |
| # assert.result "" "[]" "" : split-path-VMS "[]" ; |
| # assert.result "disk:" "[]" "" : split-path-VMS "disk:[]" ; |
| # assert.result "" "[]" "file" : split-path-VMS "[]file" ; |
| # assert.result "disk:" "[]" "file" : split-path-VMS "disk:[]file" ; |
| # |
| # # |
| # # Make portable paths |
| # # |
| # assert.result "/disk:" : make "disk:" ; |
| # assert.result "foo/bar/giz" : make "[.foo.bar.giz]" ; |
| # assert.result "foo" : make "[.foo]" ; |
| # assert.result "foo" : make "[.foo.bar.-]" ; |
| # assert.result ".." : make "[.-]" ; |
| # assert.result ".." : make "[-]" ; |
| # assert.result "." : make "[]" ; |
| # assert.result "giz.h" : make "giz.h" ; |
| # assert.result "foo/bar/giz.h" : make "[.foo.bar]giz.h" ; |
| # assert.result "/disk:/my_docs" : make "disk:[my_docs]" ; |
| # assert.result "/disk:/boost/tools/build/new/project.jam" : make "disk:[boost.tools.build.test.-.new]project.jam" ; |
| # |
| # # |
| # # Special case (adds '.' to end of file w/o extension to |
| # # disambiguate from directory in portable path spec). |
| # # |
| # assert.result "Jamfile." : make "Jamfile" ; |
| # assert.result "dir/Jamfile." : make "[.dir]Jamfile" ; |
| # assert.result "/disk:/dir/Jamfile." : make "disk:[dir]Jamfile" ; |
| # |
| # # |
| # # Make native paths |
| # # |
| # assert.result "disk:" : native "/disk:" ; |
| # assert.result "[.foo.bar.giz]" : native "foo/bar/giz" ; |
| # assert.result "[.foo]" : native "foo" ; |
| # assert.result "[.-]" : native ".." ; |
| # assert.result "[.foo.-]" : native "foo/.." ; |
| # assert.result "[]" : native "." ; |
| # assert.result "disk:[my_docs.work]" : native "/disk:/my_docs/work" ; |
| # assert.result "giz.h" : native "giz.h" ; |
| # assert.result "disk:Jamfile." : native "/disk:Jamfile." ; |
| # assert.result "disk:[my_docs.work]Jamfile." : native "/disk:/my_docs/work/Jamfile." ; |
| # |
| # modules.poke path : os : $(save-os) ; |
| # |
| # } |
| |
| # |
| |
| |
| #def glob(dir, patterns): |
| # result = [] |
| # for pattern in patterns: |
| # result.extend(builtin_glob(os.path.join(dir, pattern))) |
| # return result |
| |
| def glob(dirs, patterns, exclude_patterns=None): |
| """Returns the list of files matching the given pattern in the |
| specified directory. Both directories and patterns are |
| supplied as portable paths. Each pattern should be non-absolute |
| path, and can't contain '.' or '..' elements. Each slash separated |
| element of pattern can contain the following special characters: |
| - '?', which match any character |
| - '*', which matches arbitrary number of characters. |
| A file $(d)/e1/e2/e3 (where 'd' is in $(dirs)) matches pattern p1/p2/p3 |
| if and only if e1 matches p1, e2 matches p2 and so on. |
| For example: |
| [ glob . : *.cpp ] |
| [ glob . : */build/Jamfile ] |
| """ |
| |
| assert(isinstance(patterns, list)) |
| assert(isinstance(dirs, list)) |
| |
| if not exclude_patterns: |
| exclude_patterns = [] |
| else: |
| assert(isinstance(exclude_patterns, list)) |
| |
| real_patterns = [os.path.join(d, p) for p in patterns for d in dirs] |
| real_exclude_patterns = [os.path.join(d, p) for p in exclude_patterns |
| for d in dirs] |
| |
| inc = [os.path.normpath(name) for p in real_patterns |
| for name in builtin_glob(p)] |
| exc = [os.path.normpath(name) for p in real_exclude_patterns |
| for name in builtin_glob(p)] |
| return [x for x in inc if x not in exc] |
| |
| def glob_tree(roots, patterns, exclude_patterns=None): |
| """Recursive version of GLOB. Builds the glob of files while |
| also searching in the subdirectories of the given roots. An |
| optional set of exclusion patterns will filter out the |
| matching entries from the result. The exclusions also apply |
| to the subdirectory scanning, such that directories that |
| match the exclusion patterns will not be searched.""" |
| |
| if not exclude_patterns: |
| exclude_patterns = [] |
| |
| result = glob(roots, patterns, exclude_patterns) |
| subdirs = [s for s in result if s != "." and s != ".." and os.path.isdir(s)] |
| if subdirs: |
| result.extend(glob_tree(subdirs, patterns, exclude_patterns)) |
| |
| return result |
| |
| def glob_in_parents(dir, patterns, upper_limit=None): |
| """Recursive version of GLOB which glob sall parent directories |
| of dir until the first match is found. Returns an empty result if no match |
| is found""" |
| |
| assert(isinstance(dir, str)) |
| assert(isinstance(patterns, list)) |
| |
| result = [] |
| |
| absolute_dir = os.path.join(os.getcwd(), dir) |
| absolute_dir = os.path.normpath(absolute_dir) |
| while absolute_dir: |
| new_dir = os.path.split(absolute_dir)[0] |
| if new_dir == absolute_dir: |
| break |
| result = glob([new_dir], patterns) |
| if result: |
| break |
| absolute_dir = new_dir |
| |
| return result |
| |
| |
| # The relpath functionality is written by |
| # Cimarron Taylor |
| def split(p, rest=[]): |
| (h,t) = os.path.split(p) |
| if len(h) < 1: return [t]+rest |
| if len(t) < 1: return [h]+rest |
| return split(h,[t]+rest) |
| |
| def commonpath(l1, l2, common=[]): |
| if len(l1) < 1: return (common, l1, l2) |
| if len(l2) < 1: return (common, l1, l2) |
| if l1[0] != l2[0]: return (common, l1, l2) |
| return commonpath(l1[1:], l2[1:], common+[l1[0]]) |
| |
| def relpath(p1, p2): |
| (common,l1,l2) = commonpath(split(p1), split(p2)) |
| p = [] |
| if len(l1) > 0: |
| p = [ '../' * len(l1) ] |
| p = p + l2 |
| if p: |
| return os.path.join( *p ) |
| else: |
| return "." |