mirror of
https://github.com/facebook/sapling.git
synced 2024-10-10 08:47:12 +03:00
2e43c3b76d
Summary: This makes it easier to add some test coverage. There's no real functional change in this diff; the only code change is to throw a system_error instead of a thrift eden error wrapper class from the core globbing code. There's a little bit of code to restore this exception type in the callers in EdenServiceHandler; this is covered by existing integration tests, but I've also expanded that coverage to cover both variants of the glob thrift calls. Reviewed By: strager Differential Revision: D8776767 fbshipit-source-id: 3ea4ea642ae5108aa4b0153541bd3604f010b54c
132 lines
5.1 KiB
C++
132 lines
5.1 KiB
C++
/*
|
|
* Copyright (c) 2016-present, Facebook, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This source code is licensed under the BSD-style license found in the
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
*
|
|
*/
|
|
#pragma once
|
|
#include <folly/futures/Future.h>
|
|
#include "eden/fs/inodes/InodePtrFwd.h"
|
|
#include "eden/fs/model/Hash.h"
|
|
#include "eden/fs/model/Tree.h"
|
|
#include "eden/fs/model/git/GlobMatcher.h"
|
|
#include "eden/fs/store/ObjectStore.h"
|
|
#include "eden/fs/utils/PathFuncs.h"
|
|
|
|
namespace facebook {
|
|
namespace eden {
|
|
|
|
/** Represents the compiled state of a tree-walking glob operation.
|
|
* We split the glob into path components and build a tree of name
|
|
* matching operations.
|
|
* For non-recursive globs this allows an efficient walk and compare
|
|
* as we work through the tree. Path components that have no glob
|
|
* special characters can be looked up directly from the directory
|
|
* contents as a hash lookup, rather than by repeatedly matching the
|
|
* pattern against each entry.
|
|
*/
|
|
class GlobNode {
|
|
public:
|
|
// 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) {}
|
|
|
|
using PrefetchList = std::shared_ptr<folly::Synchronized<std::vector<Hash>>>;
|
|
|
|
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
|
|
// directory separator separated path component.
|
|
void parse(folly::StringPiece pattern);
|
|
|
|
// This is a recursive function to evaluate the compiled glob against
|
|
// the provided input path and inode.
|
|
// It returns the set of matching file names.
|
|
// Note: the caller is responsible for ensuring that this
|
|
// GlobNode exists until the returned Future is resolved.
|
|
// If prefetchFiles is true, each matching file will have its content
|
|
// prefetched via the ObjectStore layer. This will not change the
|
|
// materialization or overlay state for children that already have
|
|
// inodes assigned.
|
|
folly::Future<std::vector<RelativePath>> evaluate(
|
|
const ObjectStore* store,
|
|
RelativePathPiece rootPath,
|
|
TreeInodePtr root,
|
|
PrefetchList fileBlobsToPrefetch);
|
|
|
|
// This is the Tree version of the method above
|
|
folly::Future<std::vector<RelativePath>> evaluate(
|
|
const ObjectStore* store,
|
|
RelativePathPiece rootPath,
|
|
const std::shared_ptr<const Tree>& tree,
|
|
PrefetchList fileBlobsToPrefetch);
|
|
|
|
private:
|
|
// Returns the next glob node token.
|
|
// This is the text from the start of pattern up to the first
|
|
// slash, or the end of the string is there was no slash.
|
|
// pattern is advanced to the start of the next token.
|
|
// hasSpecials is set to true if the returned token contains
|
|
// any special glob characters, false otherwise.
|
|
static folly::StringPiece tokenize(
|
|
folly::StringPiece& pattern,
|
|
bool* hasSpecials);
|
|
// Look up the child corresponding to a token.
|
|
// Returns nullptr if it does not exist.
|
|
// This is a simple brute force walk of the vector; the cardinality
|
|
// of the glob nodes are typically very low so this is fine.
|
|
GlobNode* lookupToken(
|
|
std::vector<std::unique_ptr<GlobNode>>* container,
|
|
folly::StringPiece token);
|
|
// Evaluates any recursive glob entries associated with this node.
|
|
// This is a recursive function which evaluates the current GlobNode against
|
|
// the recursive set of children.
|
|
// By contrast, evaluate() walks down through the GlobNodes AND the
|
|
// inode children.
|
|
// The difference is because a pattern like "**/foo" must be recursively
|
|
// matched against all the children of the inode.
|
|
template <typename ROOT>
|
|
folly::Future<std::vector<RelativePath>> evaluateRecursiveComponentImpl(
|
|
const ObjectStore* store,
|
|
RelativePathPiece rootPath,
|
|
ROOT&& root,
|
|
PrefetchList fileBlobsToPrefetch);
|
|
|
|
template <typename ROOT>
|
|
folly::Future<std::vector<RelativePath>> evaluateImpl(
|
|
const ObjectStore* store,
|
|
RelativePathPiece rootPath,
|
|
ROOT&& root,
|
|
PrefetchList fileBlobsToPrefetch);
|
|
|
|
// The pattern fragment for this node
|
|
std::string pattern_;
|
|
// The compiled pattern
|
|
GlobMatcher matcher_;
|
|
// List of non-** child rules
|
|
std::vector<std::unique_ptr<GlobNode>> children_;
|
|
// 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};
|
|
// true when both of the following hold:
|
|
// - this node is "**" or "*"
|
|
// - it was created with includeDotfiles=true.
|
|
bool alwaysMatch_{false};
|
|
};
|
|
} // namespace eden
|
|
} // namespace facebook
|