diff options
-rw-r--r-- | libbuild2/bash/rule.cxx | 2 | ||||
-rw-r--r-- | libbuild2/cc/install-rule.cxx | 2 | ||||
-rw-r--r-- | libbuild2/cc/link-rule.cxx | 4 | ||||
-rw-r--r-- | libbuild2/file.hxx | 5 | ||||
-rw-r--r-- | libbuild2/filesystem.hxx | 3 | ||||
-rw-r--r-- | libbuild2/parser.cxx | 73 | ||||
-rw-r--r-- | tests/name/pattern.testscript | 56 |
7 files changed, 109 insertions, 36 deletions
diff --git a/libbuild2/bash/rule.cxx b/libbuild2/bash/rule.cxx index 6e96b34..be7b2ff 100644 --- a/libbuild2/bash/rule.cxx +++ b/libbuild2/bash/rule.cxx @@ -473,7 +473,7 @@ namespace build2 { if (!*md.for_install) fail << "incompatible " << t << " build" << - info << "target already built not for install"; + info << "target already updated but not for install"; } else md.for_install = true; diff --git a/libbuild2/cc/install-rule.cxx b/libbuild2/cc/install-rule.cxx index 46764a6..c4f924a 100644 --- a/libbuild2/cc/install-rule.cxx +++ b/libbuild2/cc/install-rule.cxx @@ -281,7 +281,7 @@ namespace build2 // if (!*md.for_install) fail << "incompatible " << t << " build" << - info << "target already built not for install"; + info << "target already updated but not for install"; } else md.for_install = true; diff --git a/libbuild2/cc/link-rule.cxx b/libbuild2/cc/link-rule.cxx index a669f37..d43e7e8 100644 --- a/libbuild2/cc/link-rule.cxx +++ b/libbuild2/cc/link-rule.cxx @@ -2598,8 +2598,8 @@ namespace build2 // if (*md->for_install != *d.for_install) fail << "incompatible " << *l << " build" << - info << "library is built " << (*md->for_install ? "" : "not ") - << "for install"; + info << "target is already updated but " + << (*md->for_install ? "" : "not ") << "for install"; } auto newer = [&d, l] () diff --git a/libbuild2/file.hxx b/libbuild2/file.hxx index 36e4c00..ff8a821 100644 --- a/libbuild2/file.hxx +++ b/libbuild2/file.hxx @@ -30,8 +30,9 @@ namespace build2 // export.build -- export stub // export/ -- exported buildfiles // - // The build/, bootstrap/, root/, and config.build entries are in .gitignore - // as generated by bdep-new. + // The build/, /bootstrap/, /root/, and config.build entries are in + // .gitignore as generated by bdep-new (note that build/ is ignored + // recursively; see below). // // The rest of the filesystem entries are shared between the project and the // modules that it loads. In particular, if a project loads module named diff --git a/libbuild2/filesystem.hxx b/libbuild2/filesystem.hxx index 7b45a08..44f5d92 100644 --- a/libbuild2/filesystem.hxx +++ b/libbuild2/filesystem.hxx @@ -24,6 +24,9 @@ namespace build2 { using butl::entry_type; + using butl::dir_entry; + using butl::dir_iterator; + using butl::auto_rmfile; using butl::auto_rmdir; diff --git a/libbuild2/parser.cxx b/libbuild2/parser.cxx index 53f808c..cb1bccc 100644 --- a/libbuild2/parser.cxx +++ b/libbuild2/parser.cxx @@ -2385,9 +2385,16 @@ namespace build2 // size_t b (0), e (0); for (size_t m (0), n (text.size ()); - next_word (text, n, b, e, m, '\n', '\r'), b != n; - sloc.line++) + next_word (text, n, b, e, m, '\n', '\r'), b != n; ) { + // Treat consecutive \r\n (CRLF) as if they were a single + // delimiter. + // + if (b != 0 && text[b - 1] == '\r' && + e != n && text[e] == '\n' && + m != 2) + continue; + s.assign (text, b, e - b); if (!trim (s).empty ()) @@ -2401,6 +2408,8 @@ namespace build2 break; } } + + sloc.line++; } if (b == e) @@ -6998,7 +7007,13 @@ namespace build2 // The directory/value must not be empty if we have a type. // if (d.empty () && v.empty () && !t.empty ()) - fail (loc) << "typed empty name"; + { + // We sneak +/- in type if in pattern_mode::detect (think {+{}}). + // + fail (loc) << (t == "+" ? "empty name pattern inclusion group" : + t == "-" ? "empty name pattern exclusion group" : + "typed empty name"); + } ns.emplace_back (move (p), move (d), move (t), move (v), pat); return ns.back (); @@ -7258,7 +7273,9 @@ namespace build2 (root_ != nullptr && root_->root_extra != nullptr && m.to_directory () && - exists (d.sp / m / root_->root_extra->buildignore_file))) + exists (m.relative () + ? d.sp / m / root_->root_extra->buildignore_file + : m / root_->root_extra->buildignore_file))) return !interm; // Note that we have to make copies of the extension since there will @@ -7314,9 +7331,11 @@ namespace build2 return true; }); + path pat (move (p)); + try { - path_search (path (move (p)), + path_search (pat, process, *sp, path_match_flags::follow_symlinks, @@ -7324,7 +7343,8 @@ namespace build2 } catch (const system_error& e) { - fail (l) << "unable to scan " << *sp << ": " << e; + fail (l) << "unable to scan for '" + << (pat.relative () ? *sp / pat : pat) << "': " << e; } }; @@ -7569,7 +7589,10 @@ namespace build2 // and look for some wildcards since the pattern can be the result of an // expansion (or, worse, concatenation). Thus pattern_mode::detect: we // are going to ask parse_names() to detect for us if the first name is - // a pattern. And if it is, to refrain from adding pair/dir/type. + // a pattern. And if it is, to refrain from adding pair/dir/type (note: + // for the pattern inclusions and exclusions the name's type member will + // be set to "+" and "-", respectively, and will later be cleared by + // expand_name_pattern()). // optional<const target_type*> pat_tt ( parse_names ( @@ -8313,16 +8336,42 @@ namespace build2 fail (loc) << "invalid path '" << e.path << "'"; } - count = parse_names_trailer ( - t, tt, ns, pmode, what, separators, pairn, *pp1, dp1, tp1, cross); + // Note that for a pattern inclusion group (see above) we make sure + // that the resulting patterns are simple names, passing NULL as the + // directory path (the names' type members will still be set to "+" + // thought; see the parse_names_trailer::parse() lambda + // implementation for details). + // + assert (!pinc || (tp1 != nullptr && *tp1 == "+")); - // If empty group or empty name, then this is not a pattern inclusion - // group (see above). + count = parse_names_trailer ( + t, tt, + ns, + pmode, + what, + separators, pairn, + *pp1, (!pinc ? dp1 : nullptr), tp1, + cross); + + // If empty group, then this is not a pattern inclusion group. // if (pinc) { - if (count != 0 && (count > 1 || !ns.back ().empty ())) + if (count != 0) + { + // Note that we can never end up with the empty name here. For + // example, for the below constructs the above + // parse_names_trailer() call would fail with appropriate + // diagnostics since the empty name's type will be set to "+" + // (see above for details): + // + // foo/{hxx cxx}{+{}} + // foo/{+{}} + // + assert (count > 1 || !ns.back ().empty ()); + pattern_detected (ttp); + } ppat = pinc = false; } diff --git a/tests/name/pattern.testscript b/tests/name/pattern.testscript index c1a4ce4..acad250 100644 --- a/tests/name/pattern.testscript +++ b/tests/name/pattern.testscript @@ -105,59 +105,70 @@ EOI : { touch foo.txt; - $* <'print *.txt' >'foo.txt' : simple-file + $* <'print *.txt' >'foo.txt' : simple-file mkdir foo; - $* <'print */' >/'foo/' : simple-dir + $* <'print */' >/'foo/' : simple-dir touch foo.txt; - $* <'print {*.txt}' >'foo.txt' : group + $* <'print {*.txt}' >'foo.txt' : group touch foo.txt; - $* <'print {+*.txt}' >'foo.txt' : plus-prefixed + $* <'print {+*.txt}' >'foo.txt' : plus-prefixed mkdir dir && touch dir/foo.txt; - $* <'print dir/{*.txt}' >'dir/foo.txt' : dir + $* <'print dir/{*.txt}' >'dir/foo.txt' : dir touch foo.txt; - $* <'print file{*.txt}' >'file{foo.txt}' : type + $* <'print file{*.txt}' >'file{foo.txt}' : type touch foo.txt; - $* <'print x@{*.txt}' >'x@foo.txt' : pair + $* <'print x@{*.txt}' >'x@foo.txt' : pair touch bar.txt; - $* <'print x@dir/file{f*.txt}' >'' : empty + $* <'print x@dir/file{f*.txt}' >'' : empty mkdir dir && touch dir/foo.txt; - $* <'print **.txt' >/'dir/foo.txt' : recursive + $* <'print **.txt' >/'dir/foo.txt' : recursive mkdir dir && touch dir/foo.txt; - $* <'print d*/*.txt' >/'dir/foo.txt' : multi-pattern + $* <'print d*/*.txt' >/'dir/foo.txt' : multi-pattern touch foo.txt bar.txt; - $* <'print {*.txt -bar.txt}' >'foo.txt' : exclude-non-pattern + $* <'print {*.txt -bar.txt}' >'foo.txt' : exclude-non-pattern mkdir baz; touch foo.txt bar.txt baz/fox.txt baz/box.txt; - $* <'print {**.txt -b*.txt -b*/*}' >'foo.txt' : exclude-pattern + $* <'print {**.txt -b*.txt -b*/*}' >'foo.txt' : exclude-pattern touch foo.txt bar.txt baz.txt; - $* <'print {*.txt -{*z.txt bar.txt}}' >'foo.txt' : exclude-group + $* <'print {*.txt -{*z.txt bar.txt}}' >'foo.txt' : exclude-group touch bar.txt; - $* <'print {f*.txt +bar.txt}' >'bar.txt' : include-non-wildcard + $* <'print {f*.txt +bar.txt}' >'bar.txt' : include-non-wildcard touch bar.txt; - $* <'print {f*.txt +b*.txt}' >'bar.txt' : include-pattern + $* <'print {f*.txt +b*.txt}' >'bar.txt' : include-pattern mkdir bar; - $* <'print {f*/ +{b*/}}' >/'bar/' : include-group + $* <'print {f*/ +{b*/}}' >/'bar/' : include-group + + mkdir -p foo/bar; + $* <'print $path.canonicalize(foo/{+{b*/}})' >/'foo/bar/' : include-group-first touch foo.txt fox.txt; - $* <'print {*.txt -f*.txt +*x.txt}' >'fox.txt' : include-exclude-order + $* <'print {*.txt -f*.txt +*x.txt}' >'fox.txt' : include-exclude-order touch foo.txt; - $* <'print {+foo.txt} {+bar.txt}' >'foo.txt' : non-wildcard + $* <'print {+foo.txt} {+bar.txt}' >'foo.txt' : non-wildcard + + mkdir -p foo/bar; + touch foo/bar/baz.txt; + $* <'print {$src_base/foo/**}' >/"$~/foo/bar/baz.txt" : abs-path-pattern + + mkdir -p foo/bar; + touch foo/bar/baz.txt; + $* <'print $src_base/foo/{**}' >/"$~/foo/bar/baz.txt" : abs-start-dir } : escaping @@ -309,6 +320,15 @@ EOI print {+{$pats}} EOI + : pattern-via-expansion-list-subdir + : + mkdir baz; + touch baz/foo.txt baz/bar.hxx; + $* <<EOI >'baz/bar.hxx baz/foo.txt' + pats = '*.hxx' '*.txt' + print baz/{+{$pats}} + EOI + : pattern-via-expansion-type : touch foo.txt; |