diff options
| author | Kenneth Heafield <github@kheafield.com> | 2012-05-12 14:01:52 -0400 | 
|---|---|---|
| committer | Kenneth Heafield <github@kheafield.com> | 2012-05-12 14:01:52 -0400 | 
| commit | 3faecf9a00512dcbc8712c4bca9adae72fb64410 (patch) | |
| tree | 9761b50d12f81a675fb7cbc663ceebad15079f78 /jam-files/boost-build/util/path.py | |
| parent | c806a8fff63043f63773874986301f2822a2b552 (diff) | |
Give in and copy bjam into cdec source code
Diffstat (limited to 'jam-files/boost-build/util/path.py')
| -rw-r--r-- | jam-files/boost-build/util/path.py | 904 | 
1 files changed, 904 insertions, 0 deletions
| diff --git a/jam-files/boost-build/util/path.py b/jam-files/boost-build/util/path.py new file mode 100644 index 00000000..222b96bf --- /dev/null +++ b/jam-files/boost-build/util/path.py @@ -0,0 +1,904 @@ +# 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 + +from b2.util import bjam_signature + +@bjam_signature((["path", "root"],)) +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) + +@bjam_signature((["native"],)) +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) + +@bjam_signature((["path"],)) +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 +     +# +#   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. +# +def all_parents(path, upper_limit=None, cwd=None): + +    if not cwd: +        cwd = os.getcwd() + +    path_abs = os.path.join(cwd, path) + +    if upper_limit: +        upper_limit = os.path.join(cwd, upper_limit) + +    result = [] +    while path_abs and path_abs != upper_limit: +        (head, tail) = os.path.split(path) +        path = os.path.join(path, "..")         +        result.append(path) +        path_abs = head + +    if upper_limit and path_abs != upper_limit: +        raise BaseException("'%s' is not a prefix of '%s'" % (upper_limit, path)) + +    return result +     +#  Search for 'pattern' in parent directories of 'dir', up till and including +#  'upper_limit', if it is specified, or till the filesystem root otherwise. +# +def glob_in_parents(dir, patterns, upper_limit=None): + +    result = [] +    parent_dirs = all_parents(dir, upper_limit) + +    for p in parent_dirs: +        result = glob(p, patterns) +        if result: break + +    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 glob(roots, ["*"]) 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 "." | 
