Checkout: read blob objects to file. Properly handling file modes. Still needs line- ending transformations.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
diff --git a/src/checkout.c b/src/checkout.c
index cd4bc5a..ff4a8f8 100644
--- a/src/checkout.c
+++ b/src/checkout.c
@@ -12,10 +12,12 @@
#include "git2/refs.h"
#include "git2/tree.h"
#include "git2/commit.h"
+#include "git2/blob.h"
#include "common.h"
#include "refs.h"
#include "buffer.h"
+#include "repository.h"
GIT_BEGIN_DECL
@@ -46,6 +48,7 @@ static int get_head_tree(git_tree **out, git_repository *repo)
typedef struct tree_walk_data
{
git_indexer_stats *stats;
+ git_repository *repo;
} tree_walk_data;
@@ -57,18 +60,51 @@ static int count_walker(const char *path, git_tree_entry *entry, void *payload)
return 0;
}
+static int blob_contents_to_file(git_repository *repo, git_buf *fnbuf, const git_oid *id, int mode)
+{
+ int retcode = GIT_ERROR;
+
+ git_blob *blob;
+ if (!git_blob_lookup(&blob, repo, id)) {
+ const void *contents = git_blob_rawcontent(blob);
+ size_t len = git_blob_rawsize(blob);
+
+ /* TODO: line-ending smudging */
+
+ int fd = git_futils_creat_withpath(git_buf_cstr(fnbuf),
+ GIT_DIR_MODE, mode);
+ if (fd >= 0) {
+ retcode = (!p_write(fd, contents, len)) ? 0 : GIT_ERROR;
+ p_close(fd);
+ }
+
+ git_blob_free(blob);
+ }
+
+ return retcode;
+}
+
static int checkout_walker(const char *path, git_tree_entry *entry, void *payload)
{
int retcode = 0;
tree_walk_data *data = (tree_walk_data*)payload;
+ int attr = git_tree_entry_attributes(entry);
switch(git_tree_entry_type(entry)) {
case GIT_OBJ_TREE:
- /* TODO: mkdir */
+ /* TODO: mkdir? */
break;
case GIT_OBJ_BLOB:
- /* TODO: create/populate file */
+ {
+ git_buf fnbuf = GIT_BUF_INIT;
+ git_buf_join_n(&fnbuf, '/', 3,
+ git_repository_workdir(data->repo),
+ path,
+ git_tree_entry_name(entry));
+ retcode = blob_contents_to_file(data->repo, &fnbuf, git_tree_entry_id(entry), attr);
+ git_buf_free(&fnbuf);
+ }
break;
default:
@@ -95,6 +131,7 @@ int git_checkout_force(git_repository *repo, git_indexer_stats *stats)
stats->total = stats->processed = 0;
payload.stats = stats;
+ payload.repo = repo;
if (!get_head_tree(&tree, repo)) {
/* Count all the tree nodes for progress information */