merge-ort: record stage and auxiliary info for every path

Create a helper function, setup_path_info(), which can be used to record all the information we want in a merged_info or conflict_info. While there is currently only one caller of this new function, and some of its particular parameters are fixed, future callers of this function will be added later. Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Elijah Newren committed Dec 13, 2020 at 08:04 UTC 98bf98416726430b6cbc8670725f008588e478a7
1 file changed +90 -7
merge-ort.c
+90 -7
@@ -185,6 +185,26 @@ struct conflict_info {
185 unsigned match_mask:3;
186 };
187
188 +/*
189 + * For the next three macros, see warning for conflict_info.merged.
190 + *
191 + * In each of the below, mi is a struct merged_info*, and ci was defined
192 + * as a struct conflict_info* (but we need to verify ci isn't actually
193 + * pointed at a struct merged_info*).
194 + *
195 + * INITIALIZE_CI: Assign ci to mi but only if it's safe; set to NULL otherwise.
196 + * VERIFY_CI: Ensure that something we assigned to a conflict_info* is one.
197 + * ASSIGN_AND_VERIFY_CI: Similar to VERIFY_CI but do assignment first.
198 + */
199 +#define INITIALIZE_CI(ci, mi) do { \
200 + (ci) = (!(mi) || (mi)->clean) ? NULL : (struct conflict_info *)(mi); \
201 +} while (0)
202 +#define VERIFY_CI(ci) assert(ci && !ci->merged.clean);
203 +#define ASSIGN_AND_VERIFY_CI(ci, mi) do { \
204 + (ci) = (struct conflict_info *)(mi); \
205 + assert((ci) && !(mi)->clean); \
206 +} while (0)
207 +
208 static int err(struct merge_options *opt, const char *err, ...)
209 {
210 va_list params;
@@ -201,6 +221,65 @@ static int err(struct merge_options *opt, const char *err, ...)
221 return -1;
222 }
223
224 +static void setup_path_info(struct merge_options *opt,
225 + struct string_list_item *result,
226 + const char *current_dir_name,
227 + int current_dir_name_len,
228 + char *fullpath, /* we'll take over ownership */
229 + struct name_entry *names,
230 + struct name_entry *merged_version,
231 + unsigned is_null, /* boolean */
232 + unsigned df_conflict, /* boolean */
233 + unsigned filemask,
234 + unsigned dirmask,
235 + int resolved /* boolean */)
236 +{
237 + /* result->util is void*, so mi is a convenience typed variable */
238 + struct merged_info *mi;
239 +
240 + assert(!is_null || resolved);
241 + assert(!df_conflict || !resolved); /* df_conflict implies !resolved */
242 + assert(resolved == (merged_version != NULL));
243 +
244 + mi = xcalloc(1, resolved ? sizeof(struct merged_info) :
245 + sizeof(struct conflict_info));
246 + mi->directory_name = current_dir_name;
247 + mi->basename_offset = current_dir_name_len;
248 + mi->clean = !!resolved;
249 + if (resolved) {
250 + mi->result.mode = merged_version->mode;
251 + oidcpy(&mi->result.oid, &merged_version->oid);
252 + mi->is_null = !!is_null;
253 + } else {
254 + int i;
255 + struct conflict_info *ci;
256 +
257 + ASSIGN_AND_VERIFY_CI(ci, mi);
258 + for (i = MERGE_BASE; i <= MERGE_SIDE2; i++) {
259 + ci->pathnames[i] = fullpath;
260 + ci->stages[i].mode = names[i].mode;
261 + oidcpy(&ci->stages[i].oid, &names[i].oid);
262 + }
263 + ci->filemask = filemask;
264 + ci->dirmask = dirmask;
265 + ci->df_conflict = !!df_conflict;
266 + if (dirmask)
267 + /*
268 + * Assume is_null for now, but if we have entries
269 + * under the directory then when it is complete in
270 + * write_completed_directory() it'll update this.
271 + * Also, for D/F conflicts, we have to handle the
272 + * directory first, then clear this bit and process
273 + * the file to see how it is handled -- that occurs
274 + * near the top of process_entry().
275 + */
276 + mi->is_null = 1;
277 + }
278 + strmap_put(&opt->priv->paths, fullpath, mi);
279 + result->string = fullpath;
280 + result->util = mi;
281 +}
282 +
283 static int collect_merge_info_callback(int n,
284 unsigned long mask,
285 unsigned long dirmask,
@@ -215,10 +294,12 @@ static int collect_merge_info_callback(int n,
294 */
295 struct merge_options *opt = info->data;
296 struct merge_options_internal *opti = opt->priv;
218 - struct conflict_info *ci;
297 + struct string_list_item pi; /* Path Info */
298 + struct conflict_info *ci; /* typed alias to pi.util (which is void*) */
299 struct name_entry *p;
300 size_t len;
301 char *fullpath;
302 + const char *dirname = opti->current_dir_name;
303 unsigned filemask = mask & ~dirmask;
304 unsigned match_mask = 0; /* will be updated below */
305 unsigned mbase_null = !(mask & 1);
@@ -287,13 +368,15 @@ static int collect_merge_info_callback(int n,
368 make_traverse_path(fullpath, len + 1, info, p->path, p->pathlen);
369
370 /*
290 - * TODO: record information about the path other than all zeros,
291 - * so we can resolve later in process_entries.
371 + * Record information about the path so we can resolve later in
372 + * process_entries.
373 */
293 - ci = xcalloc(1, sizeof(struct conflict_info));
294 - ci->df_conflict = df_conflict;
374 + setup_path_info(opt, &pi, dirname, info->pathlen, fullpath,
375 + names, NULL, 0, df_conflict, filemask, dirmask, 0);
376 +
377 + ci = pi.util;
378 + VERIFY_CI(ci);
379 ci->match_mask = match_mask;
296 - strmap_put(&opti->paths, fullpath, ci);
380
381 /* If dirmask, recurse into subdirectories */
382 if (dirmask) {
@@ -337,7 +420,7 @@ static int collect_merge_info_callback(int n,
420 }
421
422 original_dir_name = opti->current_dir_name;
340 - opti->current_dir_name = fullpath;
423 + opti->current_dir_name = pi.string;
424 ret = traverse_trees(NULL, 3, t, &newinfo);
425 opti->current_dir_name = original_dir_name;
426