diff options
author | Edward Thomson <ethomson@edwardthomson.com> | 2018-03-19 20:10:31 +0000 |
---|---|---|
committer | Edward Thomson <ethomson@edwardthomson.com> | 2018-11-04 09:21:48 +0000 |
commit | d73043a27aaae4f7608de1a85e426bf89ea7fba3 (patch) | |
tree | efbfba7639834dc6228d8ce166a6901589f38daa /src | |
parent | 02b1083ab779e4d8d2279dea1a4ae38ec1d2e47b (diff) | |
download | libgit2-d73043a27aaae4f7608de1a85e426bf89ea7fba3.tar.gz |
reader: a generic way to read files from repos
Similar to the `git_iterator` interface, the `git_reader` interface will
allow us to read file contents from an arbitrary repository-backed data
source (trees, index, or working directory).
Diffstat (limited to 'src')
-rw-r--r-- | src/reader.c | 202 | ||||
-rw-r--r-- | src/reader.h | 102 |
2 files changed, 304 insertions, 0 deletions
diff --git a/src/reader.c b/src/reader.c new file mode 100644 index 000000000..754b90a3b --- /dev/null +++ b/src/reader.c @@ -0,0 +1,202 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "reader.h" + +#include "fileops.h" +#include "blob.h" + +#include "git2/tree.h" +#include "git2/blob.h" +#include "git2/index.h" +#include "git2/repository.h" + +/* tree reader */ + +typedef struct { + git_reader reader; + git_tree *tree; +} tree_reader; + +static int tree_reader_read( + git_buf *out, + git_reader *_reader, + const char *filename) +{ + tree_reader *reader = (tree_reader *)_reader; + git_tree_entry *tree_entry = NULL; + git_blob *blob = NULL; + int error; + + if ((error = git_tree_entry_bypath(&tree_entry, reader->tree, filename)) < 0 || + (error = git_blob_lookup(&blob, git_tree_owner(reader->tree), git_tree_entry_id(tree_entry))) < 0 || + (error = git_buf_set(out, git_blob_rawcontent(blob), git_blob_rawsize(blob))) < 0) + goto done; + +done: + git_blob_free(blob); + git_tree_entry_free(tree_entry); + return error; +} + +static void tree_reader_free(git_reader *_reader) +{ + GIT_UNUSED(_reader); +} + +int git_reader_for_tree(git_reader **out, git_tree *tree) +{ + tree_reader *reader; + + assert(out && tree); + + reader = git__calloc(1, sizeof(tree_reader)); + GITERR_CHECK_ALLOC(reader); + + reader->reader.read = tree_reader_read; + reader->reader.free = tree_reader_free; + reader->tree = tree; + + *out = (git_reader *)reader; + return 0; +} + +/* workdir reader */ + +typedef struct { + git_reader reader; + git_repository *repo; +} workdir_reader; + +static int workdir_reader_read( + git_buf *out, + git_reader *_reader, + const char *filename) +{ + workdir_reader *reader = (workdir_reader *)_reader; + git_buf path = GIT_BUF_INIT; + int error; + + if ((error = git_buf_joinpath(&path, + git_repository_workdir(reader->repo), filename)) < 0) + goto done; + + /* TODO: should we read the filtered data? */ + error = git_futils_readbuffer(out, path.ptr); + +done: + git_buf_dispose(&path); + return error; +} + +static void workdir_reader_free(git_reader *_reader) +{ + GIT_UNUSED(_reader); +} + +int git_reader_for_workdir(git_reader **out, git_repository *repo) +{ + workdir_reader *reader; + + assert(out && repo); + + reader = git__calloc(1, sizeof(workdir_reader)); + GITERR_CHECK_ALLOC(reader); + + reader->reader.read = workdir_reader_read; + reader->reader.free = workdir_reader_free; + reader->repo = repo; + + *out = (git_reader *)reader; + return 0; +} + +/* index reader */ + +typedef struct { + git_reader reader; + git_repository *repo; + git_index *index; +} index_reader; + +static int index_reader_read( + git_buf *out, + git_reader *_reader, + const char *filename) +{ + index_reader *reader = (index_reader *)_reader; + const git_index_entry *entry; + git_blob *blob; + int error; + + if ((entry = git_index_get_bypath(reader->index, filename, 0)) == NULL) + return GIT_ENOTFOUND; + + if ((error = git_blob_lookup(&blob, reader->repo, &entry->id)) < 0) + goto done; + + error = git_blob__getbuf(out, blob); + +done: + git_blob_free(blob); + return error; +} + +static void index_reader_free(git_reader *_reader) +{ + GIT_UNUSED(_reader); +} + +int git_reader_for_index( + git_reader **out, + git_repository *repo, + git_index *index) +{ + index_reader *reader; + int error; + + assert(out && repo); + + reader = git__calloc(1, sizeof(index_reader)); + GITERR_CHECK_ALLOC(reader); + + reader->reader.read = index_reader_read; + reader->reader.free = index_reader_free; + reader->repo = repo; + + if (index) { + reader->index = index; + } else { + error = git_repository_index__weakptr(&reader->index, repo); + + if (error < 0) { + git__free(reader); + return error; + } + } + + *out = (git_reader *)reader; + return 0; +} + +/* generic */ + +int git_reader_read(git_buf *out, git_reader *reader, const char *filename) +{ + assert(out && reader && filename); + + return reader->read(out, reader, filename); +} + +void git_reader_free(git_reader *reader) +{ + if (!reader) + return; + + reader->free(reader); + git__free(reader); +} diff --git a/src/reader.h b/src/reader.h new file mode 100644 index 000000000..18c7f59ee --- /dev/null +++ b/src/reader.h @@ -0,0 +1,102 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_reader_h__ +#define INCLUDE_reader_h__ + +#include "common.h" + +typedef struct git_reader git_reader; + +/* + * The `git_reader` structure is a generic interface for reading the + * contents of a file by its name, and implementations are provided + * for reading out of a tree, the index, and the working directory. + * + * Note that the reader implementation is meant to have a short + * lifecycle and does not increase the refcount of the object that + * it's reading. Callers should ensure that they do not use a + * reader after disposing the underlying object that it reads. + */ +struct git_reader { + int (*read)(git_buf *out, git_reader *reader, const char *filename); + void (*free)(git_reader *reader); +}; + +/** + * Create a `git_reader` that will allow random access to the given + * tree. Paths requested via `git_reader_read` will be rooted at this + * tree, callers are not expected to recurse through tree lookups. Thus, + * you can request to read `/src/foo.c` and the tree provided to this + * function will be searched to find another tree named `src`, which + * will then be opened to find `foo.c`. + * + * @param out The reader for the given tree + * @param tree The tree object to read + * @return 0 on success, or an error code < 0 + */ +extern int git_reader_for_tree( + git_reader **out, + git_tree *tree); + +/** + * Create a `git_reader` that will allow random access to the given + * index, or the repository's index. + * + * @param out The reader for the given index + * @param repo The repository containing the index + * @param index The index to read, or NULL to use the repository's index + * @return 0 on success, or an error code < 0 + */ +extern int git_reader_for_index( + git_reader **out, + git_repository *repo, + git_index *index); + +/** + * Create a `git_reader` that will allow random access to the given + * repository's working directory. Note that the contents are read + * in repository format, meaning any workdir -> odb filters are + * applied. + * + * If `validate_index` is set to true, reads of files will hash the + * on-disk contents and ensure that the resulting object ID matches + * the repository's index. This ensures that the working directory + * is unmodified from the index contents. + * + * @param out The reader for the given working directory + * @param repo The repository containing the working directory + * @param validate_index If true, the working directory contents will + * be compared to the index contents during read to ensure that + * the working directory is unmodified. + * @return 0 on success, or an error code < 0 + */ +extern int git_reader_for_workdir( + git_reader **out, + git_repository *repo); + +/** + * Read the given filename from the reader and populate the given buffer + * with the contents and the given oid with the object ID. + * + * @param out The buffer to populate with the file contents + * @param out_id The oid to populate with the object ID + * @param reader The reader to read + * @param filename The filename to read from the reader + */ +extern int git_reader_read( + git_buf *out, + git_reader *reader, + const char *filename); + +/** + * Free the given reader and any associated objects. + * + * @param reader The reader to free + */ +extern void git_reader_free(git_reader *reader); + +#endif |