builtin/apply: make parse_ignorewhitespace_option() return -1 instead of die()ing
[gitweb.git] / builtin / fetch.c
index 8177f90d418f5b3d27ececad4e74fb529faff1de..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,14 +450,129 @@ 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));
-       strbuf_addf(display, "%-*s -> %s", REFCOL_WIDTH, remote, local);
+       if (!compact_format)
+               print_remote_to_local(display, remote, local);
+       else
+               print_compact(display, remote, local);
        if (error)
                strbuf_addf(display, "  (%s)", error);
 }
@@ -618,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
@@ -803,7 +921,7 @@ 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);
        }
 
@@ -1004,7 +1122,7 @@ static int get_remote_group(const char *key, const char *value, void *priv)
                        size_t wordlen = strcspn(value, " \t\n");
 
                        if (wordlen >= 1)
-                               string_list_append(g->list,
+                               string_list_append_nodup(g->list,
                                                   xstrndup(value, wordlen));
                        value += wordlen + (value[wordlen] != '\0');
                }
@@ -1142,7 +1260,7 @@ static int fetch_one(struct remote *remote, int argc, const char **argv)
 int cmd_fetch(int argc, const char **argv, const char *prefix)
 {
        int i;
-       struct string_list list = STRING_LIST_INIT_NODUP;
+       struct string_list list = STRING_LIST_INIT_DUP;
        struct remote *remote;
        int result = 0;
        struct argv_array argv_gc_auto = ARGV_ARRAY_INIT;
@@ -1225,8 +1343,6 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
                argv_array_clear(&options);
        }
 
-       /* All names were strdup()ed or strndup()ed */
-       list.strdup_strings = 1;
        string_list_clear(&list, 0);
 
        close_all_packs();