From 30ae764b1e11f10b5fca723a876a0f3de3ca11ab Mon Sep 17 00:00:00 2001 From: Daniel Barkalow Date: Mon, 10 Sep 2007 23:02:45 -0400 Subject: Modularize commit-walker This turns the extern functions to be provided by the backend into a struct of pointers, renames the functions to be more namespace-friendly, and updates http-fetch to this interface. It removes the unused include from http-push.c. It makes git-http-fetch a builtin (with the implementation a separate file, accessible directly). Signed-off-by: Daniel Barkalow Signed-off-by: Junio C Hamano --- walker.c | 318 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 318 insertions(+) create mode 100644 walker.c (limited to 'walker.c') diff --git a/walker.c b/walker.c new file mode 100644 index 0000000000..5c65ea494d --- /dev/null +++ b/walker.c @@ -0,0 +1,318 @@ +#include "cache.h" +#include "walker.h" +#include "commit.h" +#include "tree.h" +#include "tree-walk.h" +#include "tag.h" +#include "blob.h" +#include "refs.h" +#include "strbuf.h" + +static unsigned char current_commit_sha1[20]; + +void walker_say(struct walker *walker, const char *fmt, const char *hex) +{ + if (walker->get_verbosely) + fprintf(stderr, fmt, hex); +} + +static void report_missing(const struct object *obj) +{ + char missing_hex[41]; + strcpy(missing_hex, sha1_to_hex(obj->sha1));; + fprintf(stderr, "Cannot obtain needed %s %s\n", + obj->type ? typename(obj->type): "object", missing_hex); + if (!is_null_sha1(current_commit_sha1)) + fprintf(stderr, "while processing commit %s.\n", + sha1_to_hex(current_commit_sha1)); +} + +static int process(struct walker *walker, struct object *obj); + +static int process_tree(struct walker *walker, struct tree *tree) +{ + struct tree_desc desc; + struct name_entry entry; + + if (parse_tree(tree)) + return -1; + + init_tree_desc(&desc, tree->buffer, tree->size); + while (tree_entry(&desc, &entry)) { + struct object *obj = NULL; + + /* submodule commits are not stored in the superproject */ + if (S_ISGITLINK(entry.mode)) + continue; + if (S_ISDIR(entry.mode)) { + struct tree *tree = lookup_tree(entry.sha1); + if (tree) + obj = &tree->object; + } + else { + struct blob *blob = lookup_blob(entry.sha1); + if (blob) + obj = &blob->object; + } + if (!obj || process(walker, obj)) + return -1; + } + free(tree->buffer); + tree->buffer = NULL; + tree->size = 0; + return 0; +} + +#define COMPLETE (1U << 0) +#define SEEN (1U << 1) +#define TO_SCAN (1U << 2) + +static struct commit_list *complete = NULL; + +static int process_commit(struct walker *walker, struct commit *commit) +{ + if (parse_commit(commit)) + return -1; + + while (complete && complete->item->date >= commit->date) { + pop_most_recent_commit(&complete, COMPLETE); + } + + if (commit->object.flags & COMPLETE) + return 0; + + hashcpy(current_commit_sha1, commit->object.sha1); + + walker_say(walker, "walk %s\n", sha1_to_hex(commit->object.sha1)); + + if (walker->get_tree) { + if (process(walker, &commit->tree->object)) + return -1; + if (!walker->get_all) + walker->get_tree = 0; + } + if (walker->get_history) { + struct commit_list *parents = commit->parents; + for (; parents; parents = parents->next) { + if (process(walker, &parents->item->object)) + return -1; + } + } + return 0; +} + +static int process_tag(struct walker *walker, struct tag *tag) +{ + if (parse_tag(tag)) + return -1; + return process(walker, tag->tagged); +} + +static struct object_list *process_queue = NULL; +static struct object_list **process_queue_end = &process_queue; + +static int process_object(struct walker *walker, struct object *obj) +{ + if (obj->type == OBJ_COMMIT) { + if (process_commit(walker, (struct commit *)obj)) + return -1; + return 0; + } + if (obj->type == OBJ_TREE) { + if (process_tree(walker, (struct tree *)obj)) + return -1; + return 0; + } + if (obj->type == OBJ_BLOB) { + return 0; + } + if (obj->type == OBJ_TAG) { + if (process_tag(walker, (struct tag *)obj)) + return -1; + return 0; + } + return error("Unable to determine requirements " + "of type %s for %s", + typename(obj->type), sha1_to_hex(obj->sha1)); +} + +static int process(struct walker *walker, struct object *obj) +{ + if (obj->flags & SEEN) + return 0; + obj->flags |= SEEN; + + if (has_sha1_file(obj->sha1)) { + /* We already have it, so we should scan it now. */ + obj->flags |= TO_SCAN; + } + else { + if (obj->flags & COMPLETE) + return 0; + walker->prefetch(walker, obj->sha1); + } + + object_list_insert(obj, process_queue_end); + process_queue_end = &(*process_queue_end)->next; + return 0; +} + +static int loop(struct walker *walker) +{ + struct object_list *elem; + + while (process_queue) { + struct object *obj = process_queue->item; + elem = process_queue; + process_queue = elem->next; + free(elem); + if (!process_queue) + process_queue_end = &process_queue; + + /* If we are not scanning this object, we placed it in + * the queue because we needed to fetch it first. + */ + if (! (obj->flags & TO_SCAN)) { + if (walker->fetch(walker, obj->sha1)) { + report_missing(obj); + return -1; + } + } + if (!obj->type) + parse_object(obj->sha1); + if (process_object(walker, obj)) + return -1; + } + return 0; +} + +static int interpret_target(struct walker *walker, char *target, unsigned char *sha1) +{ + if (!get_sha1_hex(target, sha1)) + return 0; + if (!check_ref_format(target)) { + if (!walker->fetch_ref(walker, target, sha1)) { + return 0; + } + } + return -1; +} + +static int mark_complete(const char *path, const unsigned char *sha1, int flag, void *cb_data) +{ + struct commit *commit = lookup_commit_reference_gently(sha1, 1); + if (commit) { + commit->object.flags |= COMPLETE; + insert_by_date(commit, &complete); + } + return 0; +} + +int walker_targets_stdin(char ***target, const char ***write_ref) +{ + int targets = 0, targets_alloc = 0; + struct strbuf buf; + *target = NULL; *write_ref = NULL; + strbuf_init(&buf); + while (1) { + char *rf_one = NULL; + char *tg_one; + + read_line(&buf, stdin, '\n'); + if (buf.eof) + break; + tg_one = buf.buf; + rf_one = strchr(tg_one, '\t'); + if (rf_one) + *rf_one++ = 0; + + if (targets >= targets_alloc) { + targets_alloc = targets_alloc ? targets_alloc * 2 : 64; + *target = xrealloc(*target, targets_alloc * sizeof(**target)); + *write_ref = xrealloc(*write_ref, targets_alloc * sizeof(**write_ref)); + } + (*target)[targets] = xstrdup(tg_one); + (*write_ref)[targets] = rf_one ? xstrdup(rf_one) : NULL; + targets++; + } + return targets; +} + +void walker_targets_free(int targets, char **target, const char **write_ref) +{ + while (targets--) { + free(target[targets]); + if (write_ref && write_ref[targets]) + free((char *) write_ref[targets]); + } +} + +int walker_fetch(struct walker *walker, int targets, char **target, + const char **write_ref, const char *write_ref_log_details) +{ + struct ref_lock **lock = xcalloc(targets, sizeof(struct ref_lock *)); + unsigned char *sha1 = xmalloc(targets * 20); + char *msg; + int ret; + int i; + + save_commit_buffer = 0; + track_object_refs = 0; + + for (i = 0; i < targets; i++) { + if (!write_ref || !write_ref[i]) + continue; + + lock[i] = lock_ref_sha1(write_ref[i], NULL); + if (!lock[i]) { + error("Can't lock ref %s", write_ref[i]); + goto unlock_and_fail; + } + } + + if (!walker->get_recover) + for_each_ref(mark_complete, NULL); + + for (i = 0; i < targets; i++) { + if (interpret_target(walker, target[i], &sha1[20 * i])) { + error("Could not interpret %s as something to pull", target[i]); + goto unlock_and_fail; + } + if (process(walker, lookup_unknown_object(&sha1[20 * i]))) + goto unlock_and_fail; + } + + if (loop(walker)) + goto unlock_and_fail; + + if (write_ref_log_details) { + msg = xmalloc(strlen(write_ref_log_details) + 12); + sprintf(msg, "fetch from %s", write_ref_log_details); + } else { + msg = NULL; + } + for (i = 0; i < targets; i++) { + if (!write_ref || !write_ref[i]) + continue; + ret = write_ref_sha1(lock[i], &sha1[20 * i], msg ? msg : "fetch (unknown)"); + lock[i] = NULL; + if (ret) + goto unlock_and_fail; + } + free(msg); + + return 0; + +unlock_and_fail: + for (i = 0; i < targets; i++) + if (lock[i]) + unlock_ref(lock[i]); + + return -1; +} + +void walker_free(struct walker *walker) +{ + walker->cleanup(walker); + free(walker); +} -- cgit v1.2.3 From 5f48741a5a47643bf1b46ba1d23688f2ef8b1216 Mon Sep 17 00:00:00 2001 From: Sam Vilain Date: Tue, 18 Dec 2007 01:00:43 +1300 Subject: Clarify error response from 'git fetch' for bad responses This error message prints the reponse from the server at this point. Label it as such in the output. Signed-off-by: Sam Vilain Signed-off-by: Junio C Hamano --- walker.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'walker.c') diff --git a/walker.c b/walker.c index 397b80de9e..adc3e80ce1 100644 --- a/walker.c +++ b/walker.c @@ -274,7 +274,7 @@ int walker_fetch(struct walker *walker, int targets, char **target, for (i = 0; i < targets; i++) { if (interpret_target(walker, target[i], &sha1[20 * i])) { - error("Could not interpret %s as something to pull", target[i]); + error("Could not interpret response from server '%s' as something to pull", target[i]); goto unlock_and_fail; } if (process(walker, lookup_unknown_object(&sha1[20 * i]))) -- cgit v1.2.3 From 7914053ba9901be1f1530f46e8e2e6ee6f4ae5b1 Mon Sep 17 00:00:00 2001 From: Martin Koegler Date: Mon, 25 Feb 2008 22:46:06 +0100 Subject: Remove unused object-ref code Signed-off-by: Martin Koegler Signed-off-by: Junio C Hamano --- walker.c | 1 - 1 file changed, 1 deletion(-) (limited to 'walker.c') diff --git a/walker.c b/walker.c index adc3e80ce1..c10eca8826 100644 --- a/walker.c +++ b/walker.c @@ -256,7 +256,6 @@ int walker_fetch(struct walker *walker, int targets, char **target, int i; save_commit_buffer = 0; - track_object_refs = 0; for (i = 0; i < targets; i++) { if (!write_ref || !write_ref[i]) -- cgit v1.2.3 From c13b2633f49e3e61b37973204793a4d9ef981175 Mon Sep 17 00:00:00 2001 From: Daniel Barkalow Date: Sat, 26 Apr 2008 15:53:09 -0400 Subject: Make walker.fetch_ref() take a struct ref. This simplifies a few things, makes a few things slightly more complicated, but, more importantly, allows that, when struct ref can represent a symref, http_fetch_ref() can return one. Incidentally makes the string that http_fetch_ref() gets include "refs/" (if appropriate), because that's how the name field of struct ref works. As far as I can tell, the usage in walker:interpret_target() wouldn't have worked previously, if it ever would have been used, which it wouldn't (since the fetch process uses the hash instead of the name of the ref there). Signed-off-by: Daniel Barkalow Signed-off-by: Junio C Hamano --- walker.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'walker.c') diff --git a/walker.c b/walker.c index c10eca8826..fa96a7c7d2 100644 --- a/walker.c +++ b/walker.c @@ -190,9 +190,14 @@ static int interpret_target(struct walker *walker, char *target, unsigned char * if (!get_sha1_hex(target, sha1)) return 0; if (!check_ref_format(target)) { - if (!walker->fetch_ref(walker, target, sha1)) { + struct ref *ref = alloc_ref(strlen(target)); + strcpy(ref->name, target); + if (!walker->fetch_ref(walker, ref)) { + hashcpy(sha1, ref->old_sha1); + free(ref); return 0; } + free(ref); } return -1; } -- cgit v1.2.3 From 737922aa648c43bc6a61170bee5bfd46ff953f32 Mon Sep 17 00:00:00 2001 From: Krzysztof Kowalczyk Date: Sat, 10 May 2008 16:26:58 -0700 Subject: alloc_ref_from_str(): factor out a common pattern of alloc_ref from string Also fix an underallocation in walker.c::interpret_target(). Signed-off-by: Krzysztof Kowalczyk Signed-off-by: Junio C Hamano --- walker.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'walker.c') diff --git a/walker.c b/walker.c index fa96a7c7d2..31de6c16bd 100644 --- a/walker.c +++ b/walker.c @@ -190,8 +190,7 @@ static int interpret_target(struct walker *walker, char *target, unsigned char * if (!get_sha1_hex(target, sha1)) return 0; if (!check_ref_format(target)) { - struct ref *ref = alloc_ref(strlen(target)); - strcpy(ref->name, target); + struct ref *ref = alloc_ref_from_str(target); if (!walker->fetch_ref(walker, ref)) { hashcpy(sha1, ref->old_sha1); free(ref); -- cgit v1.2.3 From 541fc218e6541ae94b3b1bc9e613f7bc879f6841 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Wed, 4 Jun 2008 14:38:58 -0400 Subject: Fix "git clone http://$URL" to check out the worktree when asked The builtin-clone now does the http commit walking and the tree unpacking in the same process, and the commit walker leaves the in-core objects in a funny state. When forgetting the data read from the tree object, the object should be marked "not parsed yet" for later users. Acked-by: Linus Torvalds Signed-off-by: Junio C Hamano --- walker.c | 1 + 1 file changed, 1 insertion(+) (limited to 'walker.c') diff --git a/walker.c b/walker.c index 31de6c16bd..0e68ee6d2e 100644 --- a/walker.c +++ b/walker.c @@ -59,6 +59,7 @@ static int process_tree(struct walker *walker, struct tree *tree) free(tree->buffer); tree->buffer = NULL; tree->size = 0; + tree->object.parsed = 0; return 0; } -- cgit v1.2.3 From f285a2d7ed6548666989406de8f0e7233eb84368 Mon Sep 17 00:00:00 2001 From: Brandon Casey Date: Thu, 9 Oct 2008 14:12:12 -0500 Subject: Replace calls to strbuf_init(&foo, 0) with STRBUF_INIT initializer Many call sites use strbuf_init(&foo, 0) to initialize local strbuf variable "foo" which has not been accessed since its declaration. These can be replaced with a static initialization using the STRBUF_INIT macro which is just as readable, saves a function call, and takes up fewer lines. Signed-off-by: Brandon Casey Signed-off-by: Shawn O. Pearce --- walker.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'walker.c') diff --git a/walker.c b/walker.c index 0e68ee6d2e..6b4cf70c6a 100644 --- a/walker.c +++ b/walker.c @@ -215,9 +215,8 @@ static int mark_complete(const char *path, const unsigned char *sha1, int flag, int walker_targets_stdin(char ***target, const char ***write_ref) { int targets = 0, targets_alloc = 0; - struct strbuf buf; + struct strbuf buf = STRBUF_INIT; *target = NULL; *write_ref = NULL; - strbuf_init(&buf, 0); while (1) { char *rf_one = NULL; char *tg_one; -- cgit v1.2.3 From 59c69c0c656ebce2f7ce870b4913512597a98390 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= Date: Sat, 18 Oct 2008 10:44:18 +0200 Subject: make alloc_ref_from_str() the new alloc_ref() With all calls to alloc_ref() gone, we can remove it and then we're free to give alloc_ref_from_str() the shorter name. It's a much nicer interface, as the callers always need to have a name string when they allocate a ref anyway and don't need to calculate and pass its length+1 any more. Signed-off-by: Rene Scharfe Signed-off-by: Junio C Hamano --- walker.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'walker.c') diff --git a/walker.c b/walker.c index 6b4cf70c6a..679adab6a0 100644 --- a/walker.c +++ b/walker.c @@ -191,7 +191,7 @@ static int interpret_target(struct walker *walker, char *target, unsigned char * if (!get_sha1_hex(target, sha1)) return 0; if (!check_ref_format(target)) { - struct ref *ref = alloc_ref_from_str(target); + struct ref *ref = alloc_ref(target); if (!walker->fetch_ref(walker, ref)) { hashcpy(sha1, ref->old_sha1); free(ref); -- cgit v1.2.3 From ba19a808aa871f0eb20aaeeb205e086b04b726dc Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 10 Feb 2009 17:42:04 -0800 Subject: Drop double-semicolon in C The worst offenders are "continue;;" and "break;;" in switch statements. Signed-off-by: Junio C Hamano --- walker.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'walker.c') diff --git a/walker.c b/walker.c index 679adab6a0..e57630e983 100644 --- a/walker.c +++ b/walker.c @@ -18,7 +18,7 @@ void walker_say(struct walker *walker, const char *fmt, const char *hex) static void report_missing(const struct object *obj) { char missing_hex[41]; - strcpy(missing_hex, sha1_to_hex(obj->sha1));; + strcpy(missing_hex, sha1_to_hex(obj->sha1)); fprintf(stderr, "Cannot obtain needed %s %s\n", obj->type ? typename(obj->type): "object", missing_hex); if (!is_null_sha1(current_commit_sha1)) -- cgit v1.2.3 From 24deea5273709f3685f981c33468a0cead6cc147 Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Wed, 22 Jul 2009 23:51:55 +0200 Subject: janitor: useless checks before free Signed-off-by: Pierre Habouzit Signed-off-by: Junio C Hamano --- walker.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'walker.c') diff --git a/walker.c b/walker.c index e57630e983..11d9052ed8 100644 --- a/walker.c +++ b/walker.c @@ -245,7 +245,7 @@ void walker_targets_free(int targets, char **target, const char **write_ref) { while (targets--) { free(target[targets]); - if (write_ref && write_ref[targets]) + if (write_ref) free((char *) write_ref[targets]); } } -- cgit v1.2.3 From 47e44ed1dc17d3a94ec4bf8dd29810ab7882041c Mon Sep 17 00:00:00 2001 From: Thiago Farina Date: Fri, 26 Nov 2010 23:58:14 -0200 Subject: commit: Add commit_list prefix in two function names. Add commit_list prefix to insert_by_date function and to sort_by_date, so it's clear that these functions refer to commit_list structure. Signed-off-by: Thiago Farina Signed-off-by: Junio C Hamano --- walker.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'walker.c') diff --git a/walker.c b/walker.c index 11d9052ed8..dce7128daf 100644 --- a/walker.c +++ b/walker.c @@ -207,7 +207,7 @@ static int mark_complete(const char *path, const unsigned char *sha1, int flag, struct commit *commit = lookup_commit_reference_gently(sha1, 1); if (commit) { commit->object.flags |= COMPLETE; - insert_by_date(commit, &complete); + commit_list_insert_by_date(commit, &complete); } return 0; } -- cgit v1.2.3