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