[PATCH] Fix parallel pull dependancy tracking.
[git.git] / pull.c
1 #include "pull.h"
2
3 #include "cache.h"
4 #include "commit.h"
5 #include "tree.h"
6 #include "tag.h"
7 #include "blob.h"
8 #include "refs.h"
9
10 const char *write_ref = NULL;
11
12 const unsigned char *current_ref = NULL;
13
14 int get_tree = 0;
15 int get_history = 0;
16 int get_all = 0;
17 int get_verbosely = 0;
18 static unsigned char current_commit_sha1[20];
19
20 void pull_say(const char *fmt, const char *hex) 
21 {
22         if (get_verbosely)
23                 fprintf(stderr, fmt, hex);
24 }
25
26 static void report_missing(const char *what, const unsigned char *missing)
27 {
28         char missing_hex[41];
29
30         strcpy(missing_hex, sha1_to_hex(missing));;
31         fprintf(stderr,
32                 "Cannot obtain needed %s %s\nwhile processing commit %s.\n",
33                 what, missing_hex, sha1_to_hex(current_commit_sha1));
34 }
35
36 static int make_sure_we_have_it(const char *what, unsigned char *sha1)
37 {
38         int status = 0;
39
40         if (!has_sha1_file(sha1)) {
41                 status = fetch(sha1);
42                 if (status && what)
43                         report_missing(what, sha1);
44         }
45         return status;
46 }
47
48 static int process(unsigned char *sha1, const char *type);
49
50 static int process_tree(struct tree *tree)
51 {
52         struct tree_entry_list *entries;
53
54         if (parse_tree(tree))
55                 return -1;
56
57         for (entries = tree->entries; entries; entries = entries->next) {
58                 if (process(entries->item.any->sha1,
59                             entries->directory ? tree_type : blob_type))
60                         return -1;
61         }
62         return 0;
63 }
64
65 static int process_commit(struct commit *commit)
66 {
67         if (parse_commit(commit))
68                 return -1;
69
70         memcpy(current_commit_sha1, commit->object.sha1, 20);
71
72         if (get_tree) {
73                 if (process(commit->tree->object.sha1, tree_type))
74                         return -1;
75                 if (!get_all)
76                         get_tree = 0;
77         }
78         if (get_history) {
79                 struct commit_list *parents = commit->parents;
80                 for (; parents; parents = parents->next) {
81                         if (has_sha1_file(parents->item->object.sha1))
82                                 continue;
83                         if (process(parents->item->object.sha1,
84                                     commit_type))
85                                 return -1;
86                 }
87         }
88         return 0;
89 }
90
91 static int process_tag(struct tag *tag)
92 {
93         if (parse_tag(tag))
94                 return -1;
95         return process(tag->tagged->sha1, NULL);
96 }
97
98 static struct object_list *process_queue = NULL;
99 static struct object_list **process_queue_end = &process_queue;
100
101 static int process_object(struct object *obj)
102 {
103         if (obj->type == commit_type) {
104                 if (process_commit((struct commit *)obj))
105                         return -1;
106                 return 0;
107         }
108         if (obj->type == tree_type) {
109                 if (process_tree((struct tree *)obj))
110                         return -1;
111                 return 0;
112         }
113         if (obj->type == blob_type) {
114                 return 0;
115         }
116         if (obj->type == tag_type) {
117                 if (process_tag((struct tag *)obj))
118                         return -1;
119                 return 0;
120         }
121         return error("Unable to determine requirements "
122                      "of type %s for %s",
123                      obj->type, sha1_to_hex(obj->sha1));
124 }
125
126 static int process(unsigned char *sha1, const char *type)
127 {
128         struct object *obj = lookup_object_type(sha1, type);
129         if (has_sha1_file(sha1)) {
130                 /* We already have it, so we should scan it now. */
131                 return process_object(obj);
132         }
133         if (object_list_contains(process_queue, obj))
134                 return 0;
135         object_list_insert(obj, process_queue_end);
136         process_queue_end = &(*process_queue_end)->next;
137
138         //fprintf(stderr, "prefetch %s\n", sha1_to_hex(sha1));
139         prefetch(sha1);
140                 
141         return 0;
142 }
143
144 static int loop(void)
145 {
146         while (process_queue) {
147                 struct object *obj = process_queue->item;
148                 /*
149                 fprintf(stderr, "%d objects to pull\n", 
150                         object_list_length(process_queue));
151                 */
152                 process_queue = process_queue->next;
153                 if (!process_queue)
154                         process_queue_end = &process_queue;
155
156                 //fprintf(stderr, "fetch %s\n", sha1_to_hex(obj->sha1));
157                 
158                 if (make_sure_we_have_it(obj->type ?: "object", 
159                                          obj->sha1))
160                         return -1;
161                 if (!obj->type)
162                         parse_object(obj->sha1);
163                 if (process_object(obj))
164                         return -1;
165         }
166         return 0;
167 }
168
169 static int interpret_target(char *target, unsigned char *sha1)
170 {
171         if (!get_sha1_hex(target, sha1))
172                 return 0;
173         if (!check_ref_format(target)) {
174                 if (!fetch_ref(target, sha1)) {
175                         return 0;
176                 }
177         }
178         return -1;
179 }
180
181
182 int pull(char *target)
183 {
184         unsigned char sha1[20];
185         int fd = -1;
186
187         if (write_ref && current_ref) {
188                 fd = lock_ref_sha1(write_ref, current_ref);
189                 if (fd < 0)
190                         return -1;
191         }
192
193         if (interpret_target(target, sha1))
194                 return error("Could not interpret %s as something to pull",
195                              target);
196         if (process(sha1, NULL))
197                 return -1;
198         if (loop())
199                 return -1;
200         
201         if (write_ref) {
202                 if (current_ref) {
203                         write_ref_sha1(write_ref, fd, sha1);
204                 } else {
205                         write_ref_sha1_unlocked(write_ref, sha1);
206                 }
207         }
208         return 0;
209 }