Commit dc1b0909d6ec96def686de11ac987892abf7538f

Ben Straub 2012-07-13T16:44:13

Create filtered_blob_contents out of parts on hand.

diff --git a/src/checkout.c b/src/checkout.c
index 907253f..1e02935 100644
--- a/src/checkout.c
+++ b/src/checkout.c
@@ -27,63 +27,70 @@ typedef struct tree_walk_data
 {
 	git_indexer_stats *stats;
 	git_repository *repo;
+	git_odb *odb;
 } tree_walk_data;
 
 
-static int apply_filters(git_buf *out,
-								 git_vector *filters,
-								 const void *data,
-								 size_t len)
+static int unfiltered_blob_contents(git_buf *out, git_repository *repo, const git_oid *blob_id)
 {
 	int retcode = GIT_ERROR;
-	git_buf origblob = GIT_BUF_INIT;
 
-	git_buf_clear(out);
-
-	if (!filters->length) {
-		/* No filters to apply; just copy the result */
-		git_buf_put(out, (const char *)data, len);
-		return 0;
+	git_blob *blob;
+	if (!git_blob_lookup(&blob, repo, blob_id)) {
+		const void *contents = git_blob_rawcontent(blob);
+		size_t len = git_blob_rawsize(blob);
+		git_buf_clear(out);
+		git_buf_set(out, (const char*)contents, len);
+		git_blob_free(blob);
+		retcode = 0;
 	}
-
-	git_buf_attach(&origblob, (char*)data, len);
-	retcode = git_filters_apply(out, &origblob, filters);
-	git_buf_detach(&origblob);
-
 	return retcode;
 }
 
-static int blob_contents_to_file(git_repository *repo, git_buf *fnbuf, const git_oid *id, int mode)
+static int filtered_blob_contents(git_buf *out, git_repository *repo, const git_oid *oid, const char *path)
 {
 	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);
+	git_buf unfiltered = GIT_BUF_INIT;
+	if (!unfiltered_blob_contents(&unfiltered, repo, oid)) {
 		git_vector filters = GIT_VECTOR_INIT;
-		int filter_count;
-
-		/* TODO: line-ending smudging */
-		filter_count = git_filters_load(&filters, repo,
-												  git_buf_cstr(fnbuf),
-												  GIT_FILTER_TO_WORKTREE);
+		int filter_count = git_filters_load(&filters, repo,
+														path, GIT_FILTER_TO_WORKTREE);
 		if (filter_count >= 0) {
-			git_buf filteredblob = GIT_BUF_INIT;
-			if (!apply_filters(&filteredblob, &filters, contents, len)) {
-				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_buf_clear(out);
+			if (!filter_count) {
+				git_buf_put(out, git_buf_cstr(&unfiltered), git_buf_len(&unfiltered));
+				retcode = 0;
+			} else {
+				retcode = git_filters_apply(out, &unfiltered, &filters);
 			}
-			git_buf_free(&filteredblob);
-			git_filters_free(&filters);
 		}
 
-		git_blob_free(blob);
+		git_filters_free(&filters);
+	}
+
+	git_buf_free(&unfiltered);
+	return retcode;
+}
+
+static int blob_contents_to_file(git_repository *repo, git_buf *fnbuf, const git_oid *id, int mode)
+{
+	int retcode = GIT_ERROR;
+
+	git_buf filteredcontents = GIT_BUF_INIT;
+	if (!filtered_blob_contents(&filteredcontents, repo, id, git_buf_cstr(fnbuf))) {
+		int fd = git_futils_creat_withpath(git_buf_cstr(fnbuf),
+													  GIT_DIR_MODE, mode);
+		if (fd >= 0) {
+			if (!p_write(fd, git_buf_cstr(&filteredcontents),
+							 git_buf_len(&filteredcontents)))
+				retcode = 0;
+			else
+				retcode = GIT_ERROR;
+			p_close(fd);
+		}
 	}
+	git_buf_free(&filteredcontents);
 
 	return retcode;
 }
@@ -94,26 +101,32 @@ static int checkout_walker(const char *path, git_tree_entry *entry, void *payloa
 	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? */
-		break;
-
-	case GIT_OBJ_BLOB:
-		{
-			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;
+	/* TODO: handle submodules  */
+
+	if (S_ISLNK(attr)) {
+		printf("It's a link!\n'");
+	} else {
+		switch(git_tree_entry_type(entry)) {
+		case GIT_OBJ_TREE:
+			/* Nothing to do; the blob handling creates necessary directories. */
+			break;
+
+		case GIT_OBJ_BLOB:
+			{
+				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:
-		retcode = -1;
-		break;
+		default:
+			retcode = -1;
+			break;
+		}
 	}
 
 	data->stats->processed++;
@@ -131,9 +144,15 @@ int git_checkout_force(git_repository *repo, git_indexer_stats *stats)
 	assert(repo);
 	if (!stats) stats = &dummy_stats;
 
+	if (git_repository_is_bare(repo)) {
+		giterr_set(GITERR_INVALID, "Checkout is not allowed for bare repositories");
+		return GIT_ERROR;
+	}
+
 	stats->total = stats->processed = 0;
 	payload.stats = stats;
 	payload.repo = repo;
+	if (git_repository_odb(&payload.odb, repo) < 0) return GIT_ERROR;
 
 	/* TODO: stats->total is never calculated. */
 
@@ -145,6 +164,7 @@ int git_checkout_force(git_repository *repo, git_indexer_stats *stats)
 		git_tree_free(tree);
 	}
 
+	git_odb_free(payload.odb);
 	return retcode;
 }