2
0
mirror of https://github.com/boostorg/build.git synced 2026-01-31 20:12:19 +00:00

Revamp path.glob.

The problem with the previous implementation is that it would iterate
over all elements in a dir even if 'pattern' had no metacharacters. First,
that was slow -- if you handed

  /cygdrive/w/My Documents/boost/test/a.cpp

to it, it would crawl all the way to the top, listing each directory and
checking each file. Second, it would fail, because Cygwin is broken and
does not show 'cygdrive' is the list of directory elements of '/'.

Now we check if a pattern has metacharacters, and if not, just do
a simple 'timestamp' call.

The new glob is implemented as new 'GLOB-RECURSIVELY' builtin. I've decided
to use builtin since otherwise, we'd need 'does this name exist' builtin,
and if we need new builtin, why don't implement all globbing in core.


[SVN r29163]
This commit is contained in:
Vladimir Prus
2005-05-24 07:57:56 +00:00
parent c7bce34d14
commit 4e9af774ce
6 changed files with 195 additions and 86 deletions

View File

@@ -94,7 +94,10 @@ rule load ( jamfile-location )
return $(module-name) ;
}
JAMROOT = project-root.jam Jamroot jamroot Jamroot.jam jamroot.jam ;
# Note the use of character groups, as opposed to listing
# 'Jamroot' and 'jamroot'. With the latter, we'd get duplicate
# matches on windows and would have to eliminate duplicates.
JAMROOT = project-root.jam [Jj]amroot [Jj]amroot.jam ;
# Loads parent of Jamfile at 'location'. Issues an error if nothing is found.
rule load-parent ( location )
{
@@ -301,7 +304,7 @@ local rule load-jamfile (
.jamfile-modules += $(jamfile-module) ;
mark-as-user $(jamfile-module) ;
modules.load $(jamfile-module) : [ path.native $(jamfile-to-load) ] : . ;
if $(jamfile-to-load:BS) in $(JAMROOT)
if $(jamfile-to-load:BS) = project-root.jam
{
jamfile = [ find-jamfile $(dir) : no-errors ] ;
if $(jamfile)
@@ -430,7 +433,8 @@ rule initialize (
# We search for parent/project-root only if jamfile was specified
# --- i.e
# if the project is not standalone.
if $(location) && ! $(basename) in $(JAMROOT)
if $(location) && ! $(basename) in
project-root.jam Jamroot jamroot Jamroot.jam Jamroot
{
parent-module = [ load-parent $(location) ] ;
}
@@ -889,11 +893,13 @@ module project-rules
{
import path ;
import project ;
import sequence ;
local location = [ project.attribute $(__name__) source-location ] ;
local result ;
local paths = [ path.glob $(location) : $(wildcards) ] ;
local paths = [ path.glob $(location) :
[ sequence.transform path.make : $(wildcards) ] ] ;
if $(wildcards:D)
{
# The paths we've found are relative to current directory,

View File

@@ -110,6 +110,12 @@ load_builtins()
);
}
{
char * args[] = { "patterns", "*", 0 };
bind_builtin( "GLOB-RECURSIVELY" , builtin_glob_recursive, 0, args );
}
duplicate_rule( "Includes" ,
bind_builtin( "INCLUDES" ,
builtin_depends, 1, 0 ) );
@@ -550,8 +556,9 @@ builtin_glob_back(
string_new( buf );
path_build( &f, buf, 0 );
if (globbing->case_insensitive)
if (globbing->case_insensitive) {
downcase_inplace( buf->value );
}
for( l = globbing->patterns; l; l = l->next )
{
@@ -619,6 +626,160 @@ builtin_glob(
return globbing.results;
}
static int has_wildcards(const char* str)
{
size_t index = strcspn(str, "[]*?");
if (str[index] == '\0')
return 0;
else
return 1;
}
/** If 'file' exists, append 'file' to 'list'.
Returns 'list'.
*/
static LIST* append_if_exists(LIST* list, char* file)
{
time_t time;
timestamp(file, &time);
if (time > 0)
return list_new(list, newstr(file));
else
return list;
}
LIST* glob1(char* dirname, char* pattern)
{
LIST* plist = list_new(L0, pattern);
struct globbing globbing;
globbing.results = L0;
globbing.patterns = plist;
globbing.case_insensitive
# if defined( OS_NT ) || defined( OS_CYGWIN )
= plist; /* always case-insensitive if any files can be found */
# else
= L0;
# endif
if ( globbing.case_insensitive )
{
globbing.patterns = downcase_list( plist );
}
file_dirscan( dirname, builtin_glob_back, &globbing );
if ( globbing.case_insensitive )
{
list_free( globbing.patterns );
}
list_free(plist);
return globbing.results;
}
LIST* glob_recursive(char* pattern)
{
LIST* result = L0;
/* Check if there's metacharacters in pattern */
if (!has_wildcards(pattern))
{
/* No metacharacters. Check if the path exists. */
result = append_if_exists(result, pattern);
}
else
{
/* Have metacharacters in the pattern. Split into dir/name */
PATHNAME path[1];
path_parse(pattern, path);
if (path->f_dir.ptr)
{
LIST* dirs = L0;
string dirname[1];
string basename[1];
string_new(dirname);
string_new(basename);
string_append_range(dirname, path->f_dir.ptr,
path->f_dir.ptr + path->f_dir.len);
path->f_grist.ptr = 0;
path->f_grist.len = 0;
path->f_dir.ptr = 0;
path->f_dir.len = 0;
path_build(path, basename, 0);
if (has_wildcards(dirname->value))
{
dirs = glob_recursive(dirname->value);
}
else
{
dirs = list_new(dirs, dirname->value);
}
if (has_wildcards(basename->value))
{
for(; dirs; dirs = dirs->next)
{
result = list_append(result,
glob1(dirs->string, basename->value));
}
}
else
{
string file_string[1];
string_new(file_string);
/** No wildcard in basename. */
for(; dirs; dirs = dirs->next)
{
path->f_dir.ptr = dirs->string;
path->f_dir.len = strlen(dirs->string);
path_build(path, file_string, 0);
result = append_if_exists(result, file_string->value);
string_truncate(file_string, 0);
}
string_free(file_string);
}
string_free(dirname);
string_free(basename);
}
else
{
/** No directory, just a pattern. */
result = list_append(result, glob1(".", pattern));
}
}
return result;
}
LIST *
builtin_glob_recursive(
PARSE *parse,
FRAME *frame )
{
LIST* result = L0;
LIST* l = lol_get( frame->args, 0 );
for(; l; l = l->next)
{
result = list_append(result, glob_recursive(l->string));
}
return result;
}
/*
* builtin_match() - MATCH rule, regexp matching
*/

View File

@@ -22,6 +22,7 @@ LIST *builtin_echo( PARSE *parse, FRAME *args );
LIST *builtin_exit( PARSE *parse, FRAME *args );
LIST *builtin_flags( PARSE *parse, FRAME *args );
LIST *builtin_glob( PARSE *parse, FRAME *args );
LIST *builtin_glob_recursive( PARSE *parse, FRAME *frame );
LIST *builtin_subst( PARSE *parse, FRAME *args );
LIST *builtin_match( PARSE *parse, FRAME *args );
LIST *builtin_hdrmacro( PARSE *parse, FRAME *args );

View File

@@ -12,6 +12,21 @@ if $(JAM_VERSION:J="") < 030109
EXIT ;
}
local required-rules = GLOB-RECURSIVELY ;
for local r in $(required-rules)
{
if ! $(r) in [ RULENAMES ]
{
ECHO "error: builtin rule '$(r)' is not present" ;
ECHO "error: you version of bjam is likely out of date" ;
ECHO "error: please get a fresh version from CVS." ;
EXIT ;
}
}
# Bootstrap the module system. Then bring the import rule into the global module.
#
SEARCH on <module@>modules.jam = $(.bootstrap-file:D) ;

View File

@@ -204,97 +204,23 @@ rule pwd ( )
rule glob ( dirs * : patterns + )
{
local result ;
local real-patterns ;
for local d in $(dirs)
{
for local p in $(patterns)
{
local pattern = [ path.root $(p) $(d) ] ;
result += [ glob-really [ path.native $(pattern) ] ] ;
real-patterns += [ path.native $(pattern) ] ;
}
}
# Windows is not case-sensitive, so if you're globbing
# for Jamroot and jamroot, the result will include 'Jamroot'
# twice. Remove duplicates.
return [ sequence.transform path.make : [ sequence.unique $(result) ] ] ;
return [ sequence.unique [ sequence.transform path.make :
[ GLOB-RECURSIVELY $(real-patterns) ] ] ] ;
}
# Looks for file matching 'pattern' in 'directory'.
# Does not recurse. Directory is in the native format.
rule glob-one ( dir : p )
{
local result ;
# 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.
#
if $(p) != ".."
{
# On cygwin, 'cygdrive' is a special directory and is
# not shown when listing '/'.
if $(dir) = / && $(p) = cygdrive
{
result = /cygdrive ;
}
else
{
result += [ GLOB $(dir) : $(p) ] ;
}
}
else
{
result += [ path.join $(dir) .. ] ;
}
return $(result) ;
}
# Searches for a single pattern and returns matches.
# Both pattern and result are in native format.
rule glob-really ( pattern )
{
local result ;
# The second condition protects again looping infinitely
# on '/' path.
if $(pattern:D) && $(pattern:D) != $(pattern)
{
# When the pattern has a directory element, we first glob for
# directory, and then glob for file name is the found directories.
# First glob for directory part.
local globbed-dirs = [ glob-really $(pattern:D) ] ;
for local dir in $(globbed-dirs)
{
local x = [ glob-one $(dir) : $(pattern:D="") ] ;
result += $(x) ;
}
}
else
{
if $(pattern:D) = $(pattern)
{
# Just return the result.
# FIXME: Maybe need to check that the directory
# is indeed present.
result = $(pattern) ;
}
else
{
result = [ glob-one . : $(pattern) ] ;
}
}
return $(result) ;
}
#
# Returns true is the specified file exists.

View File

@@ -20,9 +20,9 @@ t = Tester(
t.set_tree('startup')
if os.name == 'nt':
t.run_build_system(
status=1, stdout="You didn't set BOOST_ROOT", match = expect_substring)
#if os.name == 'nt':
# t.run_build_system(
# status=1, stdout="You didn't set BOOST_ROOT", match = expect_substring)
t.run_build_system(
extra_args = '-sBOOST_ROOT=.', status=1