mirror of
https://github.com/facebook/sapling.git
synced 2024-10-07 07:17:55 +03:00
Make dotfile handling of GlobNode configurable
Summary: To provide the ability to ignore dotfiles, we update `GlobNode()` to take a `bool includeDotfiles` that is used to determine the options used to create the `GlobMatcher` associated with the node. Whereas the patterns `**` and `*` were assumed to always match, that is now true only when `includeDotfiles` is true, as well. Finally, this adds a special case when `**` is used as the `pattern` for a `GlobNode` and `includeDotfiles` is `false`. Because `GlobMatcher` does not accept `**` as input, we specify the pattern as `**/*` to `GlobMatcher`, which it accepts and is functionally equivalent in our case. This is safe because we only do this trick when `**` is specified as a leaf `GlobNode`. Reviewed By: wez Differential Revision: D7741508 fbshipit-source-id: 9e6a50cb4dab09be2497393c641f176c84316a07
This commit is contained in:
parent
bcfbc86081
commit
d6fccefb49
@ -440,7 +440,7 @@ void EdenServiceHandler::glob(
|
||||
auto rootInode = edenMount->getRootInode();
|
||||
|
||||
// Compile the list of globs into a tree
|
||||
GlobNode globRoot;
|
||||
GlobNode globRoot(/*includeDotfiles=*/true);
|
||||
for (auto& globString : *globs) {
|
||||
globRoot.parse(globString);
|
||||
}
|
||||
|
@ -23,12 +23,16 @@ using std::vector;
|
||||
namespace facebook {
|
||||
namespace eden {
|
||||
|
||||
GlobNode::GlobNode(StringPiece pattern, bool hasSpecials)
|
||||
: pattern_(pattern.str()), hasSpecials_(hasSpecials) {
|
||||
if (pattern == "**" || pattern == "*") {
|
||||
GlobNode::GlobNode(StringPiece pattern, bool includeDotfiles, bool hasSpecials)
|
||||
: pattern_(pattern.str()),
|
||||
includeDotfiles_(includeDotfiles),
|
||||
hasSpecials_(hasSpecials) {
|
||||
if (includeDotfiles && (pattern == "**" || pattern == "*")) {
|
||||
alwaysMatch_ = true;
|
||||
} else {
|
||||
auto compiled = GlobMatcher::create(pattern, GlobOptions::DEFAULT);
|
||||
auto options =
|
||||
includeDotfiles ? GlobOptions::DEFAULT : GlobOptions::IGNORE_DOTFILES;
|
||||
auto compiled = GlobMatcher::create(pattern, options);
|
||||
if (compiled.hasError()) {
|
||||
throw newEdenError(
|
||||
EINVAL,
|
||||
@ -42,6 +46,7 @@ GlobNode::GlobNode(StringPiece pattern, bool hasSpecials)
|
||||
|
||||
void GlobNode::parse(StringPiece pattern) {
|
||||
GlobNode* parent = this;
|
||||
string normalizedPattern;
|
||||
|
||||
while (!pattern.empty()) {
|
||||
StringPiece token;
|
||||
@ -51,7 +56,19 @@ void GlobNode::parse(StringPiece pattern) {
|
||||
if (pattern.startsWith("**")) {
|
||||
// Recursive match defeats most optimizations; we have to stop
|
||||
// tokenizing here.
|
||||
token = pattern;
|
||||
|
||||
// HACK: We special-case "**" if includeDotfiles=false. In this case, we
|
||||
// need to create a GlobMatcher for this pattern, but GlobMatcher is
|
||||
// designed to reject "**". As a workaround, we use "**/*", which is
|
||||
// functionally equivalent in this case because there are no other
|
||||
// "tokens" in the pattern following the "**" at this point.
|
||||
if (pattern == "**" && !includeDotfiles_) {
|
||||
normalizedPattern = "**/*";
|
||||
token = normalizedPattern;
|
||||
} else {
|
||||
token = pattern;
|
||||
}
|
||||
|
||||
pattern = StringPiece();
|
||||
container = &parent->recursiveChildren_;
|
||||
hasSpecials = true;
|
||||
@ -61,7 +78,8 @@ void GlobNode::parse(StringPiece pattern) {
|
||||
|
||||
auto node = lookupToken(container, token);
|
||||
if (!node) {
|
||||
container->emplace_back(std::make_unique<GlobNode>(token, hasSpecials));
|
||||
container->emplace_back(
|
||||
std::make_unique<GlobNode>(token, includeDotfiles_, hasSpecials));
|
||||
node = container->back().get();
|
||||
}
|
||||
|
||||
|
@ -27,11 +27,11 @@ namespace eden {
|
||||
*/
|
||||
class GlobNode {
|
||||
public:
|
||||
// Default constructor is intended to create the root of a set of globs
|
||||
// that will be parsed into the overall glob tree.
|
||||
GlobNode() = default;
|
||||
// Single parameter constructor is intended to create the root of a set of
|
||||
// globs that will be parsed into the overall glob tree.
|
||||
explicit GlobNode(bool includeDotfiles) : includeDotfiles_(includeDotfiles) {}
|
||||
|
||||
GlobNode(folly::StringPiece pattern, bool hasSpecials);
|
||||
GlobNode(folly::StringPiece pattern, bool includeDotfiles, bool hasSpecials);
|
||||
|
||||
// Compile and add a new glob pattern to the tree.
|
||||
// Compilation splits the pattern into nodes, with one node for each
|
||||
@ -82,13 +82,19 @@ class GlobNode {
|
||||
// List of ** child rules
|
||||
std::vector<std::unique_ptr<GlobNode>> recursiveChildren_;
|
||||
|
||||
// For a child GlobNode that is added to this GlobNode (presumably via
|
||||
// parse()), the GlobMatcher pattern associated with the child node should use
|
||||
// this value for its includeDotfiles parameter.
|
||||
bool includeDotfiles_;
|
||||
// If true, generate results for matches. Only applies
|
||||
// to non-recursive glob patterns.
|
||||
bool isLeaf_{false};
|
||||
// If false we can try a name lookup of pattern rather
|
||||
// than walking the children and applying the matcher
|
||||
bool hasSpecials_{false};
|
||||
// If true, this node is **
|
||||
// true when both of the following hold:
|
||||
// - this node is "**" or "*"
|
||||
// - it was created with includeDotfiles=true.
|
||||
bool alwaysMatch_{false};
|
||||
};
|
||||
} // namespace eden
|
||||
|
Loading…
Reference in New Issue
Block a user