]>
Commit | Line | Data |
---|---|---|
ed09aef0 JS |
1 | #include "cache.h" |
2 | #include "commit.h" | |
abef3a16 | 3 | #include "tag.h" |
3125fe52 | 4 | #include "pkt-line.h" |
ed09aef0 JS |
5 | |
6 | static int is_shallow = -1; | |
6035d6aa NTND |
7 | static struct stat shallow_stat; |
8 | static char *alternate_shallow_file; | |
9 | ||
10 | void set_alternate_shallow_file(const char *path) | |
11 | { | |
12 | if (is_shallow != -1) | |
13 | die("BUG: is_repository_shallow must not be called before set_alternate_shallow_file"); | |
14 | free(alternate_shallow_file); | |
15 | alternate_shallow_file = path ? xstrdup(path) : NULL; | |
16 | } | |
ed09aef0 JS |
17 | |
18 | int register_shallow(const unsigned char *sha1) | |
19 | { | |
20 | struct commit_graft *graft = | |
21 | xmalloc(sizeof(struct commit_graft)); | |
22 | struct commit *commit = lookup_commit(sha1); | |
23 | ||
24 | hashcpy(graft->sha1, sha1); | |
25 | graft->nr_parent = -1; | |
26 | if (commit && commit->object.parsed) | |
27 | commit->parents = NULL; | |
28 | return register_commit_graft(graft, 0); | |
29 | } | |
30 | ||
f43117a6 | 31 | int is_repository_shallow(void) |
ed09aef0 JS |
32 | { |
33 | FILE *fp; | |
34 | char buf[1024]; | |
6035d6aa | 35 | const char *path = alternate_shallow_file; |
ed09aef0 JS |
36 | |
37 | if (is_shallow >= 0) | |
38 | return is_shallow; | |
39 | ||
6035d6aa NTND |
40 | if (!path) |
41 | path = git_path("shallow"); | |
42 | /* | |
43 | * fetch-pack sets '--shallow-file ""' as an indicator that no | |
44 | * shallow file should be used. We could just open it and it | |
45 | * will likely fail. But let's do an explicit check instead. | |
46 | */ | |
47 | if (!*path || | |
48 | stat(path, &shallow_stat) || | |
49 | (fp = fopen(path, "r")) == NULL) { | |
ed09aef0 JS |
50 | is_shallow = 0; |
51 | return is_shallow; | |
52 | } | |
53 | is_shallow = 1; | |
54 | ||
55 | while (fgets(buf, sizeof(buf), fp)) { | |
56 | unsigned char sha1[20]; | |
57 | if (get_sha1_hex(buf, sha1)) | |
58 | die("bad shallow line: %s", buf); | |
59 | register_shallow(sha1); | |
60 | } | |
61 | fclose(fp); | |
62 | return is_shallow; | |
63 | } | |
64 | ||
f53514bc JS |
65 | struct commit_list *get_shallow_commits(struct object_array *heads, int depth, |
66 | int shallow_flag, int not_shallow_flag) | |
ed09aef0 JS |
67 | { |
68 | int i = 0, cur_depth = 0; | |
69 | struct commit_list *result = NULL; | |
3cd47459 | 70 | struct object_array stack = OBJECT_ARRAY_INIT; |
ed09aef0 JS |
71 | struct commit *commit = NULL; |
72 | ||
73 | while (commit || i < heads->nr || stack.nr) { | |
74 | struct commit_list *p; | |
75 | if (!commit) { | |
76 | if (i < heads->nr) { | |
77 | commit = (struct commit *) | |
abef3a16 | 78 | deref_tag(heads->objects[i++].item, NULL, 0); |
affeef12 | 79 | if (!commit || commit->object.type != OBJ_COMMIT) { |
ed09aef0 JS |
80 | commit = NULL; |
81 | continue; | |
82 | } | |
d64d6c9f AJ |
83 | if (!commit->util) |
84 | commit->util = xmalloc(sizeof(int)); | |
85 | *(int *)commit->util = 0; | |
ed09aef0 JS |
86 | cur_depth = 0; |
87 | } else { | |
88 | commit = (struct commit *) | |
89 | stack.objects[--stack.nr].item; | |
90 | cur_depth = *(int *)commit->util; | |
91 | } | |
92 | } | |
dec38c81 MK |
93 | if (parse_commit(commit)) |
94 | die("invalid commit"); | |
ed09aef0 | 95 | cur_depth++; |
682c7d2f NTND |
96 | if (cur_depth >= depth) { |
97 | commit_list_insert(commit, &result); | |
98 | commit->object.flags |= shallow_flag; | |
99 | commit = NULL; | |
100 | continue; | |
101 | } | |
102 | commit->object.flags |= not_shallow_flag; | |
ed09aef0 JS |
103 | for (p = commit->parents, commit = NULL; p; p = p->next) { |
104 | if (!p->item->util) { | |
105 | int *pointer = xmalloc(sizeof(int)); | |
106 | p->item->util = pointer; | |
107 | *pointer = cur_depth; | |
108 | } else { | |
109 | int *pointer = p->item->util; | |
110 | if (cur_depth >= *pointer) | |
111 | continue; | |
112 | *pointer = cur_depth; | |
113 | } | |
4b796951 MK |
114 | if (p->next) |
115 | add_object_array(&p->item->object, | |
116 | NULL, &stack); | |
117 | else { | |
118 | commit = p->item; | |
119 | cur_depth = *(int *)commit->util; | |
f53514bc | 120 | } |
ed09aef0 JS |
121 | } |
122 | } | |
123 | ||
124 | return result; | |
125 | } | |
6035d6aa NTND |
126 | |
127 | void check_shallow_file_for_update(void) | |
128 | { | |
129 | struct stat st; | |
130 | ||
131 | if (!is_shallow) | |
132 | return; | |
133 | else if (is_shallow == -1) | |
134 | die("BUG: shallow must be initialized by now"); | |
135 | ||
136 | if (stat(git_path("shallow"), &st)) | |
137 | die("shallow file was removed during fetch"); | |
138 | else if (st.st_mtime != shallow_stat.st_mtime | |
139 | #ifdef USE_NSEC | |
140 | || ST_MTIME_NSEC(st) != ST_MTIME_NSEC(shallow_stat) | |
141 | #endif | |
142 | ) | |
143 | die("shallow file was changed during fetch"); | |
144 | } | |
3125fe52 NTND |
145 | |
146 | struct write_shallow_data { | |
147 | struct strbuf *out; | |
148 | int use_pack_protocol; | |
149 | int count; | |
150 | }; | |
151 | ||
152 | static int write_one_shallow(const struct commit_graft *graft, void *cb_data) | |
153 | { | |
154 | struct write_shallow_data *data = cb_data; | |
155 | const char *hex = sha1_to_hex(graft->sha1); | |
6a3bbb4d NTND |
156 | if (graft->nr_parent != -1) |
157 | return 0; | |
3125fe52 NTND |
158 | data->count++; |
159 | if (data->use_pack_protocol) | |
160 | packet_buf_write(data->out, "shallow %s", hex); | |
161 | else { | |
162 | strbuf_addstr(data->out, hex); | |
163 | strbuf_addch(data->out, '\n'); | |
164 | } | |
165 | return 0; | |
166 | } | |
167 | ||
168 | int write_shallow_commits(struct strbuf *out, int use_pack_protocol) | |
169 | { | |
170 | struct write_shallow_data data; | |
171 | data.out = out; | |
172 | data.use_pack_protocol = use_pack_protocol; | |
173 | data.count = 0; | |
174 | for_each_commit_graft(write_one_shallow, &data); | |
175 | return data.count; | |
176 | } | |
177 | ||
08ea65ad NTND |
178 | char *setup_temporary_shallow(void) |
179 | { | |
180 | struct strbuf sb = STRBUF_INIT; | |
181 | int fd; | |
182 | ||
183 | if (write_shallow_commits(&sb, 0)) { | |
184 | struct strbuf path = STRBUF_INIT; | |
185 | strbuf_addstr(&path, git_path("shallow_XXXXXX")); | |
186 | fd = xmkstemp(path.buf); | |
187 | if (write_in_full(fd, sb.buf, sb.len) != sb.len) | |
188 | die_errno("failed to write to %s", | |
189 | path.buf); | |
190 | close(fd); | |
191 | strbuf_release(&sb); | |
192 | return strbuf_detach(&path, NULL); | |
193 | } | |
194 | /* | |
195 | * is_repository_shallow() sees empty string as "no shallow | |
196 | * file". | |
197 | */ | |
198 | return xstrdup(""); | |
199 | } | |
200 | ||
3125fe52 NTND |
201 | void setup_alternate_shallow(struct lock_file *shallow_lock, |
202 | const char **alternate_shallow_file) | |
203 | { | |
204 | struct strbuf sb = STRBUF_INIT; | |
205 | int fd; | |
206 | ||
207 | check_shallow_file_for_update(); | |
208 | fd = hold_lock_file_for_update(shallow_lock, git_path("shallow"), | |
209 | LOCK_DIE_ON_ERROR); | |
210 | if (write_shallow_commits(&sb, 0)) { | |
211 | if (write_in_full(fd, sb.buf, sb.len) != sb.len) | |
212 | die_errno("failed to write to %s", | |
213 | shallow_lock->filename); | |
214 | *alternate_shallow_file = shallow_lock->filename; | |
215 | } else | |
216 | /* | |
217 | * is_repository_shallow() sees empty string as "no | |
218 | * shallow file". | |
219 | */ | |
220 | *alternate_shallow_file = ""; | |
221 | strbuf_release(&sb); | |
222 | } |