Merge branch 'mm/status-suggest-merge-abort'
[gitweb.git] / builtin / fetch.c
index f896aa1f881a0fd320999803fbf4770930342d49..acd0cf1755eb5afec9dc179b8dc1a93050579023 100644 (file)
@@ -15,6 +15,7 @@
 #include "submodule.h"
 #include "connected.h"
 #include "argv-array.h"
+#include "utf8.h"
 
 static const char * const builtin_fetch_usage[] = {
        N_("git fetch [<options>] [<repository> [<refspec>...]]"),
@@ -449,7 +450,132 @@ static int s_update_ref(const char *action,
                           : STORE_REF_ERROR_OTHER;
 }
 
-#define REFCOL_WIDTH  10
+static int refcol_width = 10;
+static int compact_format;
+
+static void adjust_refcol_width(const struct ref *ref)
+{
+       int max, rlen, llen, len;
+
+       /* uptodate lines are only shown on high verbosity level */
+       if (!verbosity && !oidcmp(&ref->peer_ref->old_oid, &ref->old_oid))
+               return;
+
+       max    = term_columns();
+       rlen   = utf8_strwidth(prettify_refname(ref->name));
+
+       llen   = utf8_strwidth(prettify_refname(ref->peer_ref->name));
+
+       /*
+        * rough estimation to see if the output line is too long and
+        * should not be counted (we can't do precise calculation
+        * anyway because we don't know if the error explanation part
+        * will be printed in update_local_ref)
+        */
+       if (compact_format) {
+               llen = 0;
+               max = max * 2 / 3;
+       }
+       len = 21 /* flag and summary */ + rlen + 4 /* -> */ + llen;
+       if (len >= max)
+               return;
+
+       /*
+        * Not precise calculation for compact mode because '*' can
+        * appear on the left hand side of '->' and shrink the column
+        * back.
+        */
+       if (refcol_width < rlen)
+               refcol_width = rlen;
+}
+
+static void prepare_format_display(struct ref *ref_map)
+{
+       struct ref *rm;
+       const char *format = "full";
+
+       git_config_get_string_const("fetch.output", &format);
+       if (!strcasecmp(format, "full"))
+               compact_format = 0;
+       else if (!strcasecmp(format, "compact"))
+               compact_format = 1;
+       else
+               die(_("configuration fetch.output contains invalid value %s"),
+                   format);
+
+       for (rm = ref_map; rm; rm = rm->next) {
+               if (rm->status == REF_STATUS_REJECT_SHALLOW ||
+                   !rm->peer_ref ||
+                   !strcmp(rm->name, "HEAD"))
+                       continue;
+
+               adjust_refcol_width(rm);
+       }
+}
+
+static void print_remote_to_local(struct strbuf *display,
+                                 const char *remote, const char *local)
+{
+       strbuf_addf(display, "%-*s -> %s", refcol_width, remote, local);
+}
+
+static int find_and_replace(struct strbuf *haystack,
+                           const char *needle,
+                           const char *placeholder)
+{
+       const char *p = strstr(haystack->buf, needle);
+       int plen, nlen;
+
+       if (!p)
+               return 0;
+
+       if (p > haystack->buf && p[-1] != '/')
+               return 0;
+
+       plen = strlen(p);
+       nlen = strlen(needle);
+       if (plen > nlen && p[nlen] != '/')
+               return 0;
+
+       strbuf_splice(haystack, p - haystack->buf, nlen,
+                     placeholder, strlen(placeholder));
+       return 1;
+}
+
+static void print_compact(struct strbuf *display,
+                         const char *remote, const char *local)
+{
+       struct strbuf r = STRBUF_INIT;
+       struct strbuf l = STRBUF_INIT;
+
+       if (!strcmp(remote, local)) {
+               strbuf_addf(display, "%-*s -> *", refcol_width, remote);
+               return;
+       }
+
+       strbuf_addstr(&r, remote);
+       strbuf_addstr(&l, local);
+
+       if (!find_and_replace(&r, local, "*"))
+               find_and_replace(&l, remote, "*");
+       print_remote_to_local(display, r.buf, l.buf);
+
+       strbuf_release(&r);
+       strbuf_release(&l);
+}
+
+static void format_display(struct strbuf *display, char code,
+                          const char *summary, const char *error,
+                          const char *remote, const char *local)
+{
+       strbuf_addf(display, "%c %-*s ", code, TRANSPORT_SUMMARY(summary));
+       if (!compact_format)
+               print_remote_to_local(display, remote, local);
+       else
+               print_compact(display, remote, local);
+       if (error)
+               strbuf_addf(display, "  (%s)", error);
+}
 
 static int update_local_ref(struct ref *ref,
                            const char *remote,
@@ -467,9 +593,8 @@ static int update_local_ref(struct ref *ref,
 
        if (!oidcmp(&ref->old_oid, &ref->new_oid)) {
                if (verbosity > 0)
-                       strbuf_addf(display, "= %-*s %-*s -> %s",
-                                   TRANSPORT_SUMMARY(_("[up to date]")),
-                                   REFCOL_WIDTH, remote, pretty_ref);
+                       format_display(display, '=', _("[up to date]"), NULL,
+                                      remote, pretty_ref);
                return 0;
        }
 
@@ -481,10 +606,9 @@ static int update_local_ref(struct ref *ref,
                 * If this is the head, and it's not okay to update
                 * the head, and the old value of the head isn't empty...
                 */
-               strbuf_addf(display,
-                           _("! %-*s %-*s -> %s  (can't fetch in current branch)"),
-                           TRANSPORT_SUMMARY(_("[rejected]")),
-                           REFCOL_WIDTH, remote, pretty_ref);
+               format_display(display, '!', _("[rejected]"),
+                              _("can't fetch in current branch"),
+                              remote, pretty_ref);
                return 1;
        }
 
@@ -492,11 +616,9 @@ static int update_local_ref(struct ref *ref,
            starts_with(ref->name, "refs/tags/")) {
                int r;
                r = s_update_ref("updating tag", ref, 0);
-               strbuf_addf(display, "%c %-*s %-*s -> %s%s",
-                           r ? '!' : '-',
-                           TRANSPORT_SUMMARY(_("[tag update]")),
-                           REFCOL_WIDTH, remote, pretty_ref,
-                           r ? _("  (unable to update local ref)") : "");
+               format_display(display, r ? '!' : 't', _("[tag update]"),
+                              r ? _("unable to update local ref") : NULL,
+                              remote, pretty_ref);
                return r;
        }
 
@@ -527,11 +649,9 @@ static int update_local_ref(struct ref *ref,
                    (recurse_submodules != RECURSE_SUBMODULES_ON))
                        check_for_new_submodule_commits(ref->new_oid.hash);
                r = s_update_ref(msg, ref, 0);
-               strbuf_addf(display, "%c %-*s %-*s -> %s%s",
-                           r ? '!' : '*',
-                           TRANSPORT_SUMMARY(what),
-                           REFCOL_WIDTH, remote, pretty_ref,
-                           r ? _("  (unable to update local ref)") : "");
+               format_display(display, r ? '!' : '*', what,
+                              r ? _("unable to update local ref") : NULL,
+                              remote, pretty_ref);
                return r;
        }
 
@@ -545,11 +665,9 @@ static int update_local_ref(struct ref *ref,
                    (recurse_submodules != RECURSE_SUBMODULES_ON))
                        check_for_new_submodule_commits(ref->new_oid.hash);
                r = s_update_ref("fast-forward", ref, 1);
-               strbuf_addf(display, "%c %-*s %-*s -> %s%s",
-                           r ? '!' : ' ',
-                           TRANSPORT_SUMMARY_WIDTH, quickref.buf,
-                           REFCOL_WIDTH, remote, pretty_ref,
-                           r ? _("  (unable to update local ref)") : "");
+               format_display(display, r ? '!' : ' ', quickref.buf,
+                              r ? _("unable to update local ref") : NULL,
+                              remote, pretty_ref);
                strbuf_release(&quickref);
                return r;
        } else if (force || ref->force) {
@@ -562,18 +680,14 @@ static int update_local_ref(struct ref *ref,
                    (recurse_submodules != RECURSE_SUBMODULES_ON))
                        check_for_new_submodule_commits(ref->new_oid.hash);
                r = s_update_ref("forced-update", ref, 1);
-               strbuf_addf(display, "%c %-*s %-*s -> %s  (%s)",
-                           r ? '!' : '+',
-                           TRANSPORT_SUMMARY_WIDTH, quickref.buf,
-                           REFCOL_WIDTH, remote, pretty_ref,
-                           r ? _("unable to update local ref") : _("forced update"));
+               format_display(display, r ? '!' : '+', quickref.buf,
+                              r ? _("unable to update local ref") : _("forced update"),
+                              remote, pretty_ref);
                strbuf_release(&quickref);
                return r;
        } else {
-               strbuf_addf(display, "! %-*s %-*s -> %s  %s",
-                           TRANSPORT_SUMMARY(_("[rejected]")),
-                           REFCOL_WIDTH, remote, pretty_ref,
-                           _("(non-fast-forward)"));
+               format_display(display, '!', _("[rejected]"), _("non-fast-forward"),
+                              remote, pretty_ref);
                return 1;
        }
 }
@@ -620,6 +734,8 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
                goto abort;
        }
 
+       prepare_format_display(ref_map);
+
        /*
         * We do a pass for each fetch_head_status type in their enum order, so
         * merged entries are written before not-for-merge. That lets readers
@@ -714,11 +830,10 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
                                rc |= update_local_ref(ref, what, rm, &note);
                                free(ref);
                        } else
-                               strbuf_addf(&note, "* %-*s %-*s -> FETCH_HEAD",
-                                           TRANSPORT_SUMMARY_WIDTH,
-                                           *kind ? kind : "branch",
-                                           REFCOL_WIDTH,
-                                           *what ? what : "HEAD");
+                               format_display(&note, '*',
+                                              *kind ? kind : "branch", NULL,
+                                              *what ? what : "HEAD",
+                                              "FETCH_HEAD");
                        if (note.len) {
                                if (verbosity >= 0 && !shown_url) {
                                        fprintf(stderr, _("From %.*s\n"),
@@ -806,19 +921,21 @@ static int prune_refs(struct refspec *refs, int ref_count, struct ref *ref_map,
                for (ref = stale_refs; ref; ref = ref->next)
                        string_list_append(&refnames, ref->name);
 
-               result = delete_refs(&refnames);
+               result = delete_refs(&refnames, 0);
                string_list_clear(&refnames, 0);
        }
 
        if (verbosity >= 0) {
                for (ref = stale_refs; ref; ref = ref->next) {
+                       struct strbuf sb = STRBUF_INIT;
                        if (!shown_url) {
                                fprintf(stderr, _("From %.*s\n"), url_len, url);
                                shown_url = 1;
                        }
-                       fprintf(stderr, " x %-*s %-*s -> %s\n",
-                               TRANSPORT_SUMMARY(_("[deleted]")),
-                               REFCOL_WIDTH, _("(none)"), prettify_refname(ref->name));
+                       format_display(&sb, '-', _("[deleted]"), NULL,
+                                      _("(none)"), prettify_refname(ref->name));
+                       fprintf(stderr, " %s\n",sb.buf);
+                       strbuf_release(&sb);
                        warn_dangling_symref(stderr, dangling_msg, ref->name);
                }
        }