e9d16e631585c3795ee628ec33997548a01a01b4
   1#include "cache.h"
   2#include "refs.h"
   3#include "commit.h"
   4
   5#define CHUNK_SIZE (1048576)
   6
   7static char *get_stdin(void)
   8{
   9        char *data = xmalloc(CHUNK_SIZE);
  10        int offset = 0, read = 0;
  11        read = xread(0, data, CHUNK_SIZE);
  12        while (read == CHUNK_SIZE) {
  13                offset += CHUNK_SIZE;
  14                data = xrealloc(data, offset + CHUNK_SIZE);
  15                read = xread(0, data + offset, CHUNK_SIZE);
  16        }
  17        return data;
  18}
  19
  20static void show_new(enum object_type type, unsigned char *sha1_new)
  21{
  22        fprintf(stderr, "  %s: %s\n", typename(type),
  23                find_unique_abbrev(sha1_new, DEFAULT_ABBREV));
  24}
  25
  26static int update_ref(const char *action,
  27                      const char *refname,
  28                      unsigned char *sha1,
  29                      unsigned char *oldval)
  30{
  31        int len;
  32        char msg[1024];
  33        char *rla = getenv("GIT_REFLOG_ACTION");
  34        static struct ref_lock *lock;
  35
  36        if (!rla)
  37                rla = "(reflog update)";
  38        len = snprintf(msg, sizeof(msg), "%s: %s", rla, action);
  39        if (sizeof(msg) <= len)
  40                die("insanely long action");
  41        lock = lock_any_ref_for_update(refname, oldval);
  42        if (!lock)
  43                return 1;
  44        if (write_ref_sha1(lock, sha1, msg) < 0)
  45                return 1;
  46        return 0;
  47}
  48
  49static int update_local_ref(const char *name,
  50                            const char *new_head,
  51                            const char *note,
  52                            int verbose, int force)
  53{
  54        unsigned char sha1_old[20], sha1_new[20];
  55        char oldh[41], newh[41];
  56        struct commit *current, *updated;
  57        enum object_type type;
  58
  59        if (get_sha1_hex(new_head, sha1_new))
  60                die("malformed object name %s", new_head);
  61
  62        type = sha1_object_info(sha1_new, NULL);
  63        if (type < 0)
  64                die("object %s not found", new_head);
  65
  66        if (!*name) {
  67                /* Not storing */
  68                if (verbose) {
  69                        fprintf(stderr, "* fetched %s\n", note);
  70                        show_new(type, sha1_new);
  71                }
  72                return 0;
  73        }
  74
  75        if (get_sha1(name, sha1_old)) {
  76                char *msg;
  77        just_store:
  78                /* new ref */
  79                if (!strncmp(name, "refs/tags/", 10))
  80                        msg = "storing tag";
  81                else
  82                        msg = "storing head";
  83                fprintf(stderr, "* %s: storing %s\n",
  84                        name, note);
  85                show_new(type, sha1_new);
  86                return update_ref(msg, name, sha1_new, NULL);
  87        }
  88
  89        if (!hashcmp(sha1_old, sha1_new)) {
  90                if (verbose) {
  91                        fprintf(stderr, "* %s: same as %s\n", name, note);
  92                        show_new(type, sha1_new);
  93                }
  94                return 0;
  95        }
  96
  97        if (!strncmp(name, "refs/tags/", 10)) {
  98                fprintf(stderr, "* %s: updating with %s\n", name, note);
  99                show_new(type, sha1_new);
 100                return update_ref("updating tag", name, sha1_new, NULL);
 101        }
 102
 103        current = lookup_commit_reference(sha1_old);
 104        updated = lookup_commit_reference(sha1_new);
 105        if (!current || !updated)
 106                goto just_store;
 107
 108        strcpy(oldh, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV));
 109        strcpy(newh, find_unique_abbrev(sha1_new, DEFAULT_ABBREV));
 110
 111        if (in_merge_bases(current, &updated, 1)) {
 112                fprintf(stderr, "* %s: fast forward to %s\n",
 113                        name, note);
 114                fprintf(stderr, "  old..new: %s..%s\n", oldh, newh);
 115                return update_ref("fast forward", name, sha1_new, sha1_old);
 116        }
 117        if (!force) {
 118                fprintf(stderr,
 119                        "* %s: not updating to non-fast forward %s\n",
 120                        name, note);
 121                fprintf(stderr,
 122                        "  old...new: %s...%s\n", oldh, newh);
 123                return 1;
 124        }
 125        fprintf(stderr,
 126                "* %s: forcing update to non-fast forward %s\n",
 127                name, note);
 128        fprintf(stderr, "  old...new: %s...%s\n", oldh, newh);
 129        return update_ref("forced-update", name, sha1_new, sha1_old);
 130}
 131
 132static int append_fetch_head(FILE *fp,
 133                             const char *head, const char *remote,
 134                             const char *remote_name, const char *remote_nick,
 135                             const char *local_name, int not_for_merge,
 136                             int verbose, int force)
 137{
 138        struct commit *commit;
 139        int remote_len, i, note_len;
 140        unsigned char sha1[20];
 141        char note[1024];
 142        const char *what, *kind;
 143
 144        if (get_sha1(head, sha1))
 145                return error("Not a valid object name: %s", head);
 146        commit = lookup_commit_reference(sha1);
 147        if (!commit)
 148                not_for_merge = 1;
 149
 150        if (!strcmp(remote_name, "HEAD")) {
 151                kind = "";
 152                what = "";
 153        }
 154        else if (!strncmp(remote_name, "refs/heads/", 11)) {
 155                kind = "branch";
 156                what = remote_name + 11;
 157        }
 158        else if (!strncmp(remote_name, "refs/tags/", 10)) {
 159                kind = "tag";
 160                what = remote_name + 10;
 161        }
 162        else if (!strncmp(remote_name, "refs/remotes/", 13)) {
 163                kind = "remote branch";
 164                what = remote_name + 13;
 165        }
 166        else {
 167                kind = "";
 168                what = remote_name;
 169        }
 170
 171        remote_len = strlen(remote);
 172        for (i = remote_len - 1; remote[i] == '/' && 0 <= i; i--)
 173                ;
 174        remote_len = i + 1;
 175        if (4 < i && !strncmp(".git", remote + i - 3, 4))
 176                remote_len = i - 3;
 177        note_len = sprintf(note, "%s\t%s\t",
 178                           sha1_to_hex(commit ? commit->object.sha1 : sha1),
 179                           not_for_merge ? "not-for-merge" : "");
 180        if (*what) {
 181                if (*kind)
 182                        note_len += sprintf(note + note_len, "%s ", kind);
 183                note_len += sprintf(note + note_len, "'%s' of ", what);
 184        }
 185        note_len += sprintf(note + note_len, "%.*s", remote_len, remote);
 186        fprintf(fp, "%s\n", note);
 187        return update_local_ref(local_name, head, note, verbose, force);
 188}
 189
 190static char *keep;
 191static void remove_keep(void)
 192{
 193        if (keep && *keep)
 194                unlink(keep);
 195}
 196
 197static void remove_keep_on_signal(int signo)
 198{
 199        remove_keep();
 200        signal(SIGINT, SIG_DFL);
 201        raise(signo);
 202}
 203
 204static char *find_local_name(const char *remote_name, const char *refs,
 205                             int *force_p, int *not_for_merge_p)
 206{
 207        const char *ref = refs;
 208        int len = strlen(remote_name);
 209
 210        while (ref) {
 211                const char *next;
 212                int single_force, not_for_merge;
 213
 214                while (*ref == '\n')
 215                        ref++;
 216                if (!*ref)
 217                        break;
 218                next = strchr(ref, '\n');
 219
 220                single_force = not_for_merge = 0;
 221                if (*ref == '+') {
 222                        single_force = 1;
 223                        ref++;
 224                }
 225                if (*ref == '.') {
 226                        not_for_merge = 1;
 227                        ref++;
 228                        if (*ref == '+') {
 229                                single_force = 1;
 230                                ref++;
 231                        }
 232                }
 233                if (!strncmp(remote_name, ref, len) && ref[len] == ':') {
 234                        const char *local_part = ref + len + 1;
 235                        char *ret;
 236                        int retlen;
 237
 238                        if (!next)
 239                                retlen = strlen(local_part);
 240                        else
 241                                retlen = next - local_part;
 242                        ret = xmalloc(retlen + 1);
 243                        memcpy(ret, local_part, retlen);
 244                        ret[retlen] = 0;
 245                        *force_p = single_force;
 246                        *not_for_merge_p = not_for_merge;
 247                        return ret;
 248                }
 249                ref = next;
 250        }
 251        return NULL;
 252}
 253
 254static int fetch_native_store(FILE *fp,
 255                              const char *remote,
 256                              const char *remote_nick,
 257                              const char *refs,
 258                              int verbose, int force)
 259{
 260        char buffer[1024];
 261        int err = 0;
 262
 263        signal(SIGINT, remove_keep_on_signal);
 264        atexit(remove_keep);
 265
 266        while (fgets(buffer, sizeof(buffer), stdin)) {
 267                int len;
 268                char *cp;
 269                char *local_name;
 270                int single_force, not_for_merge;
 271
 272                for (cp = buffer; *cp && !isspace(*cp); cp++)
 273                        ;
 274                if (*cp)
 275                        *cp++ = 0;
 276                len = strlen(cp);
 277                if (len && cp[len-1] == '\n')
 278                        cp[--len] = 0;
 279                if (!strcmp(buffer, "failed"))
 280                        die("Fetch failure: %s", remote);
 281                if (!strcmp(buffer, "pack"))
 282                        continue;
 283                if (!strcmp(buffer, "keep")) {
 284                        char *od = get_object_directory();
 285                        int len = strlen(od) + strlen(cp) + 50;
 286                        keep = xmalloc(len);
 287                        sprintf(keep, "%s/pack/pack-%s.keep", od, cp);
 288                        continue;
 289                }
 290
 291                local_name = find_local_name(cp, refs,
 292                                             &single_force, &not_for_merge);
 293                if (!local_name)
 294                        continue;
 295                err |= append_fetch_head(fp,
 296                                         buffer, remote, cp, remote_nick,
 297                                         local_name, not_for_merge,
 298                                         verbose, force || single_force);
 299        }
 300        return err;
 301}
 302
 303static int parse_reflist(const char *reflist)
 304{
 305        const char *ref;
 306
 307        printf("refs='");
 308        for (ref = reflist; ref; ) {
 309                const char *next;
 310                while (*ref && isspace(*ref))
 311                        ref++;
 312                if (!*ref)
 313                        break;
 314                for (next = ref; *next && !isspace(*next); next++)
 315                        ;
 316                printf("\n%.*s", (int)(next - ref), ref);
 317                ref = next;
 318        }
 319        printf("'\n");
 320
 321        printf("rref='");
 322        for (ref = reflist; ref; ) {
 323                const char *next, *colon;
 324                while (*ref && isspace(*ref))
 325                        ref++;
 326                if (!*ref)
 327                        break;
 328                for (next = ref; *next && !isspace(*next); next++)
 329                        ;
 330                if (*ref == '.')
 331                        ref++;
 332                if (*ref == '+')
 333                        ref++;
 334                colon = strchr(ref, ':');
 335                putchar('\n');
 336                printf("%.*s", (int)((colon ? colon : next) - ref), ref);
 337                ref = next;
 338        }
 339        printf("'\n");
 340        return 0;
 341}
 342
 343static int expand_refs_wildcard(const char *ls_remote_result, int numrefs,
 344                                const char **refs)
 345{
 346        int i, matchlen, replacelen;
 347        int found_one = 0;
 348        const char *remote = *refs++;
 349        numrefs--;
 350
 351        if (numrefs == 0) {
 352                fprintf(stderr, "Nothing specified for fetching with remote.%s.fetch\n",
 353                        remote);
 354                printf("empty\n");
 355        }
 356
 357        for (i = 0; i < numrefs; i++) {
 358                const char *ref = refs[i];
 359                const char *lref = ref;
 360                const char *colon;
 361                const char *tail;
 362                const char *ls;
 363                const char *next;
 364
 365                if (*lref == '+')
 366                        lref++;
 367                colon = strchr(lref, ':');
 368                tail = lref + strlen(lref);
 369                if (!(colon &&
 370                      2 < colon - lref &&
 371                      colon[-1] == '*' &&
 372                      colon[-2] == '/' &&
 373                      2 < tail - (colon + 1) &&
 374                      tail[-1] == '*' &&
 375                      tail[-2] == '/')) {
 376                        /* not a glob */
 377                        if (!found_one++)
 378                                printf("explicit\n");
 379                        printf("%s\n", ref);
 380                        continue;
 381                }
 382
 383                /* glob */
 384                if (!found_one++)
 385                        printf("glob\n");
 386
 387                /* lref to colon-2 is remote hierarchy name;
 388                 * colon+1 to tail-2 is local.
 389                 */
 390                matchlen = (colon-1) - lref;
 391                replacelen = (tail-1) - (colon+1);
 392                for (ls = ls_remote_result; ls; ls = next) {
 393                        const char *eol;
 394                        unsigned char sha1[20];
 395                        int namelen;
 396
 397                        while (*ls && isspace(*ls))
 398                                ls++;
 399                        next = strchr(ls, '\n');
 400                        eol = !next ? (ls + strlen(ls)) : next;
 401                        if (!memcmp("^{}", eol-3, 3))
 402                                continue;
 403                        if (get_sha1_hex(ls, sha1))
 404                                continue;
 405                        ls += 40;
 406                        while (ls < eol && isspace(*ls))
 407                                ls++;
 408                        /* ls to next (or eol) is the name.
 409                         * is it identical to lref to colon-2?
 410                         */
 411                        if ((eol - ls) <= matchlen ||
 412                            strncmp(ls, lref, matchlen))
 413                                continue;
 414
 415                        /* Yes, it is a match */
 416                        namelen = eol - ls;
 417                        if (lref != ref)
 418                                putchar('+');
 419                        printf("%.*s:%.*s%.*s\n",
 420                               namelen, ls,
 421                               replacelen, colon + 1,
 422                               namelen - matchlen, ls + matchlen);
 423                }
 424        }
 425        return 0;
 426}
 427
 428int cmd_fetch__tool(int argc, const char **argv, const char *prefix)
 429{
 430        int verbose = 0;
 431        int force = 0;
 432
 433        while (1 < argc) {
 434                const char *arg = argv[1];
 435                if (!strcmp("-v", arg))
 436                        verbose = 1;
 437                else if (!strcmp("-f", arg))
 438                        force = 1;
 439                else
 440                        break;
 441                argc--;
 442                argv++;
 443        }
 444
 445        if (argc <= 1)
 446                return error("Missing subcommand");
 447
 448        if (!strcmp("append-fetch-head", argv[1])) {
 449                int result;
 450                FILE *fp;
 451
 452                if (argc != 8)
 453                        return error("append-fetch-head takes 6 args");
 454                fp = fopen(git_path("FETCH_HEAD"), "a");
 455                result = append_fetch_head(fp, argv[2], argv[3],
 456                                           argv[4], argv[5],
 457                                           argv[6], !!argv[7][0],
 458                                           verbose, force);
 459                fclose(fp);
 460                return result;
 461        }
 462        if (!strcmp("update-local-ref", argv[1])) {
 463                if (argc != 5)
 464                        return error("update-local-ref takes 3 args");
 465                return update_local_ref(argv[2], argv[3], argv[4],
 466                                        verbose, force);
 467        }
 468        if (!strcmp("native-store", argv[1])) {
 469                int result;
 470                FILE *fp;
 471
 472                if (argc != 5)
 473                        return error("fetch-native-store takes 3 args");
 474                fp = fopen(git_path("FETCH_HEAD"), "a");
 475                result = fetch_native_store(fp, argv[2], argv[3], argv[4],
 476                                            verbose, force);
 477                fclose(fp);
 478                return result;
 479        }
 480        if (!strcmp("parse-reflist", argv[1])) {
 481                const char *reflist;
 482                if (argc != 3)
 483                        return error("parse-reflist takes 1 arg");
 484                reflist = argv[2];
 485                if (!strcmp(reflist, "-"))
 486                        reflist = get_stdin();
 487                return parse_reflist(reflist);
 488        }
 489        if (!strcmp("expand-refs-wildcard", argv[1])) {
 490                const char *reflist;
 491                if (argc < 4)
 492                        return error("expand-refs-wildcard takes at least 2 args");
 493                reflist = argv[2];
 494                if (!strcmp(reflist, "-"))
 495                        reflist = get_stdin();
 496                return expand_refs_wildcard(reflist, argc - 3, argv + 3);
 497        }
 498
 499        return error("Unknown subcommand: %s", argv[1]);
 500}