Commit d73043a2 by Edward Thomson

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).
parent 02b1083a
/*
* 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);
}
/*
* 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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment