mirror of
https://github.com/boostorg/build.git
synced 2026-02-09 23:12:23 +00:00
* new/os.path.jam: (root): Renamed from 'root-relative-path'.
(join): Accept arbitrary list of elements.
* new/project.jam: Induced changes.
[SVN r13686]
388 lines
9.3 KiB
Plaintext
388 lines
9.3 KiB
Plaintext
# 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.
|
|
|
|
import modules ;
|
|
import sequence ;
|
|
import regex ;
|
|
import errors : error ;
|
|
|
|
# All path manipulations are done with 'normilized' representation. 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 containg
|
|
# of slash only.
|
|
#
|
|
|
|
os = [ modules.peek : OS ] ;
|
|
if [ modules.peek : UNIX ] {
|
|
os = UNIX ;
|
|
}
|
|
|
|
#
|
|
# Converts the native path into normalized form.
|
|
#
|
|
rule make ( native )
|
|
{
|
|
return [ make-$(os) $(native) ] ;
|
|
}
|
|
|
|
#
|
|
# Builds native representation of the path
|
|
#
|
|
rule native ( path )
|
|
{
|
|
return [ native-$(os) $(path) ] ;
|
|
}
|
|
|
|
#
|
|
# 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 + )
|
|
{
|
|
local path1 = $(elements[1]) ;
|
|
local path2 = $(elements[2]) ;
|
|
|
|
if $(elements[3-])
|
|
{
|
|
path2 = [ join $(elements[2-]) ] ;
|
|
}
|
|
if $(path1) = .
|
|
{
|
|
return $(path2) ;
|
|
}
|
|
else if $(path1) = /
|
|
{
|
|
return /$(path2) ;
|
|
}
|
|
else if $(path2) = .
|
|
{
|
|
return $(path1) ;
|
|
}
|
|
else
|
|
{
|
|
local parts = [ regex.match "((\.\./)*)(.*)" : $(path2) : 1 3 ] ;
|
|
|
|
if $(parts[1])
|
|
{
|
|
local up_tokens = [ regex.split $(parts[1]) "/" ] ;
|
|
for local i in $(up_tokens[1--2])
|
|
{
|
|
path1 = [ parent $(path1) ] ;
|
|
}
|
|
}
|
|
|
|
if $(path1) = .
|
|
{
|
|
return $(parts[2]) ;
|
|
}
|
|
else if $(path1) = /
|
|
{
|
|
return /$(parts[2]) ;
|
|
}
|
|
else
|
|
{
|
|
return $(path1)/$(parts[2]) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
#
|
|
# Contanenates the passed path elements. Generates an error if
|
|
# any element other than the first one is rooted.
|
|
#
|
|
rule join ( elements + )
|
|
{
|
|
for local e in $(elements[2-])
|
|
{
|
|
if [ is-rooted $(e) ]
|
|
{
|
|
error only first element may be rooted ;
|
|
}
|
|
}
|
|
return [ join-imp $(elements) ] ;
|
|
}
|
|
|
|
|
|
#
|
|
# If 'path' is relative, it is rooted at 'root'. Otherwise, it's unchanged.
|
|
#
|
|
rule root ( path root )
|
|
{
|
|
if [ is-rooted $(path) ] {
|
|
return $(path) ;
|
|
} else {
|
|
return [ join $(root) $(path) ] ;
|
|
}
|
|
}
|
|
|
|
#
|
|
# Returns the current working directory
|
|
#
|
|
rule pwd ( )
|
|
{
|
|
return [ make [ PWD ] ] ;
|
|
}
|
|
|
|
#
|
|
# Returns the list of files matching the given pattern in the specified directory.
|
|
#
|
|
rule glob ( dir : pattern + )
|
|
{
|
|
return [ sequence.transform make : [ GLOB [ native $(dir) ] : $(pattern) ] ] ;
|
|
}
|
|
|
|
#
|
|
# 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 rpath ;
|
|
if ! [ is-rooted $(path) ] {
|
|
rpath = [ root $(path) $(cwd) ] ;
|
|
} else {
|
|
rpath = $(path) ;
|
|
}
|
|
|
|
if ! $(upper_limit) {
|
|
upper_limit = / ;
|
|
} else {
|
|
if ! [ is-rooted $(upper_limit) ] {
|
|
upper_limit = [ root $(upper_limit) $(cwd) ] ;
|
|
}
|
|
}
|
|
|
|
# Leave only directory names below 'upper_limits'
|
|
# Assure pruned_path[2] will have no leading '/'
|
|
local pruned_path = [ regex.match "($(upper_limit))/*(.*)" : $(rpath) : 1 2 ] ;
|
|
if ! $(pruned_path) {
|
|
error "$(upper_limit) is not prefix of $(path)" ;
|
|
}
|
|
|
|
local tokens = [ regex.split $(pruned_path[2]) "/" ] ;
|
|
|
|
local result ;
|
|
for local i in $(tokens) {
|
|
path = [ parent $(path) ] ;
|
|
result += $(path) ;
|
|
}
|
|
return $(result) ;
|
|
}
|
|
|
|
#
|
|
# Implementation
|
|
#
|
|
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 = [ sequence.join $(tokens) : "/" ] ;
|
|
|
|
if [ regex.match "(^.:)" : $(native) ]
|
|
{
|
|
result = /$(result) ;
|
|
}
|
|
return $(result) ;
|
|
}
|
|
|
|
rule native-NT ( path )
|
|
{
|
|
local result = [ MATCH "^/?(.*)" : $(path) ] ;
|
|
result = [ sequence.join [ regex.split $(result) "/" ] : "\\" ] ;
|
|
return $(result) ;
|
|
}
|
|
|
|
rule make-UNIX ( native )
|
|
{
|
|
return $(native) ;
|
|
}
|
|
|
|
rule native-UNIX ( path )
|
|
{
|
|
return $(path) ;
|
|
}
|
|
|
|
|
|
|
|
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/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 "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 "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) ;
|
|
|
|
local os = NT ;
|
|
|
|
assert.result "foo/bar/giz" : make "foo/bar/giz" ;
|
|
assert.result "foo/bar/giz" : make "foo\\bar\\giz" ;
|
|
assert.result "/D:/My Documents" : make "D:\\My Documents" ;
|
|
assert.result "/c:/boost/tools/build/test/../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" ;
|
|
|
|
local os = UNIX ;
|
|
|
|
assert.result "foo/bar/giz" : make "foo/bar/giz" ;
|
|
assert.result "/foo/bar" : native "/foo/bar" ;
|
|
|
|
}
|