mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-07 10:46:01 +00:00
Add API to add a memory buffer to an index
git_index_add_frombuffer enables now to store a memory buffer in the odb and to store an entry in the index directly if the index is attached to a repository.
This commit is contained in:
parent
366e53d3da
commit
a275fbc0f7
@ -14,6 +14,9 @@ v0.22 + 1
|
|||||||
via `git_config_parse_path()` and `git_config_get_path()`
|
via `git_config_parse_path()` and `git_config_get_path()`
|
||||||
respectively.
|
respectively.
|
||||||
|
|
||||||
|
* `git_index_add_frombuffer()` can now create a blob from memory
|
||||||
|
buffer and add it to the index which is attached to a repository.
|
||||||
|
|
||||||
### API removals
|
### API removals
|
||||||
|
|
||||||
### Breaking API changes
|
### Breaking API changes
|
||||||
|
@ -456,6 +456,38 @@ GIT_EXTERN(int) git_index_entry_stage(const git_index_entry *entry);
|
|||||||
*/
|
*/
|
||||||
GIT_EXTERN(int) git_index_add_bypath(git_index *index, const char *path);
|
GIT_EXTERN(int) git_index_add_bypath(git_index *index, const char *path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add or update an index entry from a buffer in memory
|
||||||
|
*
|
||||||
|
* This method will create a blob in the repository that owns the
|
||||||
|
* index and then add the index entry to the index. The `path` of the
|
||||||
|
* entry represents the position of the blob relative to the
|
||||||
|
* repository's root folder.
|
||||||
|
*
|
||||||
|
* If a previous index entry exists that has the same path as the
|
||||||
|
* given 'entry', it will be replaced. Otherwise, the 'entry' will be
|
||||||
|
* added. The `id` and the `file_size` of the 'entry' are updated with the
|
||||||
|
* real value of the blob.
|
||||||
|
*
|
||||||
|
* This forces the file to be added to the index, not looking
|
||||||
|
* at gitignore rules. Those rules can be evaluated through
|
||||||
|
* the git_status APIs (in status.h) before calling this.
|
||||||
|
*
|
||||||
|
* If this file currently is the result of a merge conflict, this
|
||||||
|
* file will no longer be marked as conflicting. The data about
|
||||||
|
* the conflict will be moved to the "resolve undo" (REUC) section.
|
||||||
|
*
|
||||||
|
* @param index an existing index object
|
||||||
|
* @param entry filename to add
|
||||||
|
* @param buffer data to be written into the blob
|
||||||
|
* @param len length of the data
|
||||||
|
* @return 0 or an error code
|
||||||
|
*/
|
||||||
|
GIT_EXTERN(int) git_index_add_frombuffer(
|
||||||
|
git_index *index,
|
||||||
|
git_index_entry *entry,
|
||||||
|
const void *buffer, size_t len);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove an index entry corresponding to a file on disk
|
* Remove an index entry corresponding to a file on disk
|
||||||
*
|
*
|
||||||
|
60
src/index.c
60
src/index.c
@ -1082,6 +1082,58 @@ static int index_conflict_to_reuc(git_index *index, const char *path)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool valid_filemode(const int filemode)
|
||||||
|
{
|
||||||
|
return (filemode == GIT_FILEMODE_BLOB ||
|
||||||
|
filemode == GIT_FILEMODE_BLOB_EXECUTABLE ||
|
||||||
|
filemode == GIT_FILEMODE_LINK ||
|
||||||
|
filemode == GIT_FILEMODE_COMMIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
int git_index_add_frombuffer(
|
||||||
|
git_index *index, git_index_entry *source_entry,
|
||||||
|
const void *buffer, size_t len)
|
||||||
|
{
|
||||||
|
git_index_entry *entry = NULL;
|
||||||
|
int error = 0;
|
||||||
|
git_oid id;
|
||||||
|
|
||||||
|
assert(index && source_entry->path);
|
||||||
|
|
||||||
|
if (INDEX_OWNER(index) == NULL)
|
||||||
|
return create_index_error(-1,
|
||||||
|
"Could not initialize index entry. "
|
||||||
|
"Index is not backed up by an existing repository.");
|
||||||
|
|
||||||
|
if (!valid_filemode(source_entry->mode)) {
|
||||||
|
giterr_set(GITERR_INDEX, "invalid filemode");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index_entry_dup(&entry, INDEX_OWNER(index), source_entry) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
error = git_blob_create_frombuffer(&id, INDEX_OWNER(index), buffer, len);
|
||||||
|
if (error < 0) {
|
||||||
|
index_entry_free(entry);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
git_oid_cpy(&entry->id, &id);
|
||||||
|
entry->file_size = len;
|
||||||
|
|
||||||
|
if ((error = index_insert(index, &entry, 1)) < 0)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
/* Adding implies conflict was resolved, move conflict entries to REUC */
|
||||||
|
if ((error = index_conflict_to_reuc(index, entry->path)) < 0 && error != GIT_ENOTFOUND)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
git_tree_cache_invalidate_path(index->tree, entry->path);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int git_index_add_bypath(git_index *index, const char *path)
|
int git_index_add_bypath(git_index *index, const char *path)
|
||||||
{
|
{
|
||||||
git_index_entry *entry = NULL;
|
git_index_entry *entry = NULL;
|
||||||
@ -1116,14 +1168,6 @@ int git_index_remove_bypath(git_index *index, const char *path)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool valid_filemode(const int filemode)
|
|
||||||
{
|
|
||||||
return (filemode == GIT_FILEMODE_BLOB ||
|
|
||||||
filemode == GIT_FILEMODE_BLOB_EXECUTABLE ||
|
|
||||||
filemode == GIT_FILEMODE_LINK ||
|
|
||||||
filemode == GIT_FILEMODE_COMMIT);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int git_index_add(git_index *index, const git_index_entry *source_entry)
|
int git_index_add(git_index *index, const git_index_entry *source_entry)
|
||||||
{
|
{
|
||||||
|
@ -253,6 +253,128 @@ void test_index_tests__add(void)
|
|||||||
git_repository_free(repo);
|
git_repository_free(repo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_index_tests__add_frombuffer(void)
|
||||||
|
{
|
||||||
|
git_index *index;
|
||||||
|
git_repository *repo;
|
||||||
|
git_index_entry entry;
|
||||||
|
const git_index_entry *returned_entry;
|
||||||
|
|
||||||
|
git_oid id1;
|
||||||
|
git_blob *blob;
|
||||||
|
|
||||||
|
const char *content = "hey there\n";
|
||||||
|
|
||||||
|
cl_set_cleanup(&cleanup_myrepo, NULL);
|
||||||
|
|
||||||
|
/* Intialize a new repository */
|
||||||
|
cl_git_pass(git_repository_init(&repo, "./myrepo", 0));
|
||||||
|
|
||||||
|
/* Ensure we're the only guy in the room */
|
||||||
|
cl_git_pass(git_repository_index(&index, repo));
|
||||||
|
cl_assert(git_index_entrycount(index) == 0);
|
||||||
|
|
||||||
|
/* Store the expected hash of the file/blob
|
||||||
|
* This has been generated by executing the following
|
||||||
|
* $ echo "hey there" | git hash-object --stdin
|
||||||
|
*/
|
||||||
|
cl_git_pass(git_oid_fromstr(&id1, "a8233120f6ad708f843d861ce2b7228ec4e3dec6"));
|
||||||
|
|
||||||
|
/* Add the new file to the index */
|
||||||
|
memset(&entry, 0x0, sizeof(git_index_entry));
|
||||||
|
entry.mode = GIT_FILEMODE_BLOB;
|
||||||
|
entry.path = "test.txt";
|
||||||
|
cl_git_pass(git_index_add_frombuffer(index, &entry,
|
||||||
|
content, strlen(content)));
|
||||||
|
|
||||||
|
/* Wow... it worked! */
|
||||||
|
cl_assert(git_index_entrycount(index) == 1);
|
||||||
|
returned_entry = git_index_get_byindex(index, 0);
|
||||||
|
|
||||||
|
/* And the built-in hashing mechanism worked as expected */
|
||||||
|
cl_assert_equal_oid(&id1, &returned_entry->id);
|
||||||
|
/* And mode is the one asked */
|
||||||
|
cl_assert_equal_i(GIT_FILEMODE_BLOB, returned_entry->mode);
|
||||||
|
|
||||||
|
/* Test access by path instead of index */
|
||||||
|
cl_assert((returned_entry = git_index_get_bypath(index, "test.txt", 0)) != NULL);
|
||||||
|
cl_assert_equal_oid(&id1, &returned_entry->id);
|
||||||
|
|
||||||
|
/* Test the blob is in the repository */
|
||||||
|
cl_git_pass(git_blob_lookup(&blob, repo, &id1));
|
||||||
|
cl_assert_equal_s(
|
||||||
|
content, git_blob_rawcontent(blob));
|
||||||
|
git_blob_free(blob);
|
||||||
|
|
||||||
|
git_index_free(index);
|
||||||
|
git_repository_free(repo);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_index_tests__add_frombuffer_reset_entry(void)
|
||||||
|
{
|
||||||
|
git_index *index;
|
||||||
|
git_repository *repo;
|
||||||
|
git_index_entry entry;
|
||||||
|
const git_index_entry *returned_entry;
|
||||||
|
git_filebuf file = GIT_FILEBUF_INIT;
|
||||||
|
|
||||||
|
git_oid id1;
|
||||||
|
git_blob *blob;
|
||||||
|
const char *old_content = "here\n";
|
||||||
|
const char *content = "hey there\n";
|
||||||
|
|
||||||
|
cl_set_cleanup(&cleanup_myrepo, NULL);
|
||||||
|
|
||||||
|
/* Intialize a new repository */
|
||||||
|
cl_git_pass(git_repository_init(&repo, "./myrepo", 0));
|
||||||
|
cl_git_pass(git_repository_index(&index, repo));
|
||||||
|
cl_git_pass(git_futils_mkpath2file("myrepo/test.txt", 0777));
|
||||||
|
cl_git_pass(git_filebuf_open(&file, "myrepo/test.txt", 0, 0666));
|
||||||
|
cl_git_pass(git_filebuf_write(&file, old_content, strlen(old_content)));
|
||||||
|
cl_git_pass(git_filebuf_commit(&file));
|
||||||
|
|
||||||
|
/* Store the expected hash of the file/blob
|
||||||
|
* This has been generated by executing the following
|
||||||
|
* $ echo "hey there" | git hash-object --stdin
|
||||||
|
*/
|
||||||
|
cl_git_pass(git_oid_fromstr(&id1, "a8233120f6ad708f843d861ce2b7228ec4e3dec6"));
|
||||||
|
|
||||||
|
cl_git_pass(git_index_add_bypath(index, "test.txt"));
|
||||||
|
|
||||||
|
/* Add the new file to the index */
|
||||||
|
memset(&entry, 0x0, sizeof(git_index_entry));
|
||||||
|
entry.mode = GIT_FILEMODE_BLOB;
|
||||||
|
entry.path = "test.txt";
|
||||||
|
cl_git_pass(git_index_add_frombuffer(index, &entry,
|
||||||
|
content, strlen(content)));
|
||||||
|
|
||||||
|
/* Wow... it worked! */
|
||||||
|
cl_assert(git_index_entrycount(index) == 1);
|
||||||
|
returned_entry = git_index_get_byindex(index, 0);
|
||||||
|
|
||||||
|
/* And the built-in hashing mechanism worked as expected */
|
||||||
|
cl_assert_equal_oid(&id1, &returned_entry->id);
|
||||||
|
/* And mode is the one asked */
|
||||||
|
cl_assert_equal_i(GIT_FILEMODE_BLOB, returned_entry->mode);
|
||||||
|
|
||||||
|
/* Test access by path instead of index */
|
||||||
|
cl_assert((returned_entry = git_index_get_bypath(index, "test.txt", 0)) != NULL);
|
||||||
|
cl_assert_equal_oid(&id1, &returned_entry->id);
|
||||||
|
cl_assert_equal_i(0, returned_entry->dev);
|
||||||
|
cl_assert_equal_i(0, returned_entry->ino);
|
||||||
|
cl_assert_equal_i(0, returned_entry->uid);
|
||||||
|
cl_assert_equal_i(0, returned_entry->uid);
|
||||||
|
cl_assert_equal_i(10, returned_entry->file_size);
|
||||||
|
|
||||||
|
/* Test the blob is in the repository */
|
||||||
|
cl_git_pass(git_blob_lookup(&blob, repo, &id1));
|
||||||
|
cl_assert_equal_s(content, git_blob_rawcontent(blob));
|
||||||
|
git_blob_free(blob);
|
||||||
|
|
||||||
|
git_index_free(index);
|
||||||
|
git_repository_free(repo);
|
||||||
|
}
|
||||||
|
|
||||||
static void cleanup_1397(void *opaque)
|
static void cleanup_1397(void *opaque)
|
||||||
{
|
{
|
||||||
GIT_UNUSED(opaque);
|
GIT_UNUSED(opaque);
|
||||||
|
Loading…
Reference in New Issue
Block a user