clone: factor out checking for an alternate path

In a later patch we want to determine if a path is suitable as an alternate from other commands than builtin/clone. Move the checking functionality of `add_one_reference` to `compute_alternate_path` that is defined in cache.h. Signed-off-by: Stefan Beller <sbeller@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Stefan Beller committed Aug 15, 2016 at 14:53 UTC 9eeea7d2bc8132cfaa1b79271c077e80317f3ae1
3 files changed +86 -34
builtin/clone.c
+9 -34
@@ -282,44 +282,19 @@ static void strip_trailing_slashes(char *dir)
282
283 static int add_one_reference(struct string_list_item *item, void *cb_data)
284 {
285 - char *ref_git;
286 - const char *repo;
287 - struct strbuf alternate = STRBUF_INIT;
288 -
289 - /* Beware: read_gitfile(), real_path() and mkpath() return static buffer */
290 - ref_git = xstrdup(real_path(item->string));
291 -
292 - repo = read_gitfile(ref_git);
293 - if (!repo)
294 - repo = read_gitfile(mkpath("%s/.git", ref_git));
295 - if (repo) {
296 - free(ref_git);
297 - ref_git = xstrdup(repo);
298 - }
299 -
300 - if (!repo && is_directory(mkpath("%s/.git/objects", ref_git))) {
301 - char *ref_git_git = mkpathdup("%s/.git", ref_git);
302 - free(ref_git);
303 - ref_git = ref_git_git;
304 - } else if (!is_directory(mkpath("%s/objects", ref_git))) {
305 - struct strbuf sb = STRBUF_INIT;
306 - if (get_common_dir(&sb, ref_git))
307 - die(_("reference repository '%s' as a linked checkout is not supported yet."),
308 - item->string);
309 - die(_("reference repository '%s' is not a local repository."),
310 - item->string);
311 - }
285 + struct strbuf err = STRBUF_INIT;
286 + struct strbuf sb = STRBUF_INIT;
287 + char *ref_git = compute_alternate_path(item->string, &err);
288
313 - if (!access(mkpath("%s/shallow", ref_git), F_OK))
314 - die(_("reference repository '%s' is shallow"), item->string);
289 + if (!ref_git)
290 + die("%s", err.buf);
291
316 - if (!access(mkpath("%s/info/grafts", ref_git), F_OK))
317 - die(_("reference repository '%s' is grafted"), item->string);
292 + strbuf_addf(&sb, "%s/objects", ref_git);
293 + add_to_alternates_file(sb.buf);
294
319 - strbuf_addf(&alternate, "%s/objects", ref_git);
320 - add_to_alternates_file(alternate.buf);
321 - strbuf_release(&alternate);
295 free(ref_git);
296 + strbuf_release(&err);
297 + strbuf_release(&sb);
298 return 0;
299 }
300
cache.h
+1
@@ -1342,6 +1342,7 @@ extern struct alternate_object_database {
1342 } *alt_odb_list;
1343 extern void prepare_alt_odb(void);
1344 extern void read_info_alternates(const char * relative_base, int depth);
1345 +extern char *compute_alternate_path(const char *path, struct strbuf *err);
1346 extern void add_to_alternates_file(const char *reference);
1347 typedef int alt_odb_fn(struct alternate_object_database *, void *);
1348 extern int foreach_alt_odb(alt_odb_fn, void*);
sha1_file.c
+76
@@ -425,6 +425,82 @@ void add_to_alternates_file(const char *reference)
425 free(alts);
426 }
427
428 +/*
429 + * Compute the exact path an alternate is at and returns it. In case of
430 + * error NULL is returned and the human readable error is added to `err`
431 + * `path` may be relative and should point to $GITDIR.
432 + * `err` must not be null.
433 + */
434 +char *compute_alternate_path(const char *path, struct strbuf *err)
435 +{
436 + char *ref_git = NULL;
437 + const char *repo, *ref_git_s;
438 + int seen_error = 0;
439 +
440 + ref_git_s = real_path_if_valid(path);
441 + if (!ref_git_s) {
442 + seen_error = 1;
443 + strbuf_addf(err, _("path '%s' does not exist"), path);
444 + goto out;
445 + } else
446 + /*
447 + * Beware: read_gitfile(), real_path() and mkpath()
448 + * return static buffer
449 + */
450 + ref_git = xstrdup(ref_git_s);
451 +
452 + repo = read_gitfile(ref_git);
453 + if (!repo)
454 + repo = read_gitfile(mkpath("%s/.git", ref_git));
455 + if (repo) {
456 + free(ref_git);
457 + ref_git = xstrdup(repo);
458 + }
459 +
460 + if (!repo && is_directory(mkpath("%s/.git/objects", ref_git))) {
461 + char *ref_git_git = mkpathdup("%s/.git", ref_git);
462 + free(ref_git);
463 + ref_git = ref_git_git;
464 + } else if (!is_directory(mkpath("%s/objects", ref_git))) {
465 + struct strbuf sb = STRBUF_INIT;
466 + seen_error = 1;
467 + if (get_common_dir(&sb, ref_git)) {
468 + strbuf_addf(err,
469 + _("reference repository '%s' as a linked "
470 + "checkout is not supported yet."),
471 + path);
472 + goto out;
473 + }
474 +
475 + strbuf_addf(err, _("reference repository '%s' is not a "
476 + "local repository."), path);
477 + goto out;
478 + }
479 +
480 + if (!access(mkpath("%s/shallow", ref_git), F_OK)) {
481 + strbuf_addf(err, _("reference repository '%s' is shallow"),
482 + path);
483 + seen_error = 1;
484 + goto out;
485 + }
486 +
487 + if (!access(mkpath("%s/info/grafts", ref_git), F_OK)) {
488 + strbuf_addf(err,
489 + _("reference repository '%s' is grafted"),
490 + path);
491 + seen_error = 1;
492 + goto out;
493 + }
494 +
495 +out:
496 + if (seen_error) {
497 + free(ref_git);
498 + ref_git = NULL;
499 + }
500 +
501 + return ref_git;
502 +}
503 +
504 int foreach_alt_odb(alt_odb_fn fn, void *cb)
505 {
506 struct alternate_object_database *ent;