sapling/eden/fs/model/git/GitIgnore.h
Adam Simpkins b7ff172fc6 initial framework for gitignore file handling
Summary:
This adds some initial code for handling gitignore files.

I did check to see if there were APIs from libgit2 that we could leverage for
this, but it does not look like we can easily use their functionality.  The
libgit2 ignore code seems to tightly coupled with their repository data
structures, and it requires that you actually have a git repository.

This code isn't quite 100% compatible with git's semantics yet.  In particular:

- For now we are just using fnmatch() to do the matching.  This is currently
  inefficient as we have to do string allocations on each match attempt.  This
  also doesn't quite match git's behavior, particularly with regard to "**"
  inside patterns.

- The code currently does not have a mechanism for indicating if a path refers
  to a directory or not, so trailing slashes in the pattern are not honored
  correctly.

We will probably need to implement our own fnmatch-like function in the future
to solve these issues.

Reviewed By: bolinfest

Differential Revision: D4156480

fbshipit-source-id: 8ceaefd3805358ae2edc29bfc316e5c8f2fb7d31
2016-11-21 15:26:07 -08:00

109 lines
3.3 KiB
C++

/*
* Copyright (c) 2016, 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/Range.h>
#include <vector>
#include "eden/utils/PathFuncs.h"
namespace facebook {
namespace eden {
class GitIgnorePattern;
/**
* A GitIgnore object represents the contents of a single .gitignore file
*
* To determine if a path should be included or excluded, you normally must
* search through multiple separate GitIgnore objects. These should be
* processed in the following order (from highest precedence to lowest):
*
* - The .gitignore file in the directory containing the path.
* - The .gitignore file in each subsequent parent directory, all the way up to
* the root of the repository.
* - Any eden client-wide exclude file
* - The user's personal exclude file.
*
* At each step, the GitIgnore object may return that the path was explicitly
* excluded, explicitly included, or was not matched. If the path was
* explicitly excluded or included, stop and use that result. Otherwise
* proceed to the next highest precedence GitIgnore object.
*/
class GitIgnore {
public:
enum MatchResult {
EXCLUDE,
INCLUDE,
NO_MATCH,
};
GitIgnore();
virtual ~GitIgnore();
GitIgnore(GitIgnore&&) = default;
/**
* Move assignment operator.
*
* Note that this operator is not thread safe. Callers are responsible for
* providing synchronization between this operation and anyone else using the
* GitIgnore object from other threads.
*/
GitIgnore& operator=(GitIgnore&&) = default;
/**
* Parse the contents of a gitignore file.
*
* Generally you should call this method exactly once immediately
* after constructing a GitIgnore object.
*
* If loadFile() is called more than once, subsequent calls replace the
* contents loaded by previous calls.
*
* loadFile() is not thread safe. Callers are responsible for providing
* synchronization between loadFile() and match() operations done in multiple
* threads.
*/
void loadFile(folly::StringPiece contents);
/**
* Check to see if a patch matches any patterns in this GitIgnore object.
*
* The input path should be relative to the directory where this .gitignore
* file exists. (For repository-wide .gitignore files or for user's personal
* .gitignore files the path should be relative to the root of the
* repository.)
*
* It is safe to call match() from multiple threads concurrently on the same
* GitIgnore object, provide no modifying operations are being done to the
* GitIgnore object at the same time.
*/
MatchResult match(RelativePathPiece path) const;
/**
* Get a human-readable description of a MatchResult enum value.
*
* This is mostly for testing and logging.
*/
static std::string matchString(MatchResult result);
private:
GitIgnore(GitIgnore const&) = delete;
GitIgnore& operator=(GitIgnore const&) = delete;
/*
* The patterns loaded from the gitignore file. These are sorted from
* highest to lowest precedence (the reverse of the order they are actually
* listed in the .gitignore file).
*/
std::vector<GitIgnorePattern> rules_;
};
}
}