submodule-config.con commit object-store: move object access functions to object-store.h (cbd53a2)
   1#include "cache.h"
   2#include "repository.h"
   3#include "config.h"
   4#include "submodule-config.h"
   5#include "submodule.h"
   6#include "strbuf.h"
   7#include "object-store.h"
   8#include "parse-options.h"
   9
  10/*
  11 * submodule cache lookup structure
  12 * There is one shared set of 'struct submodule' entries which can be
  13 * looked up by their sha1 blob id of the .gitmodules file and either
  14 * using path or name as key.
  15 * for_path stores submodule entries with path as key
  16 * for_name stores submodule entries with name as key
  17 */
  18struct submodule_cache {
  19        struct hashmap for_path;
  20        struct hashmap for_name;
  21        unsigned initialized:1;
  22        unsigned gitmodules_read:1;
  23};
  24
  25/*
  26 * thin wrapper struct needed to insert 'struct submodule' entries to
  27 * the hashmap
  28 */
  29struct submodule_entry {
  30        struct hashmap_entry ent;
  31        struct submodule *config;
  32};
  33
  34enum lookup_type {
  35        lookup_name,
  36        lookup_path
  37};
  38
  39static int config_path_cmp(const void *unused_cmp_data,
  40                           const void *entry,
  41                           const void *entry_or_key,
  42                           const void *unused_keydata)
  43{
  44        const struct submodule_entry *a = entry;
  45        const struct submodule_entry *b = entry_or_key;
  46
  47        return strcmp(a->config->path, b->config->path) ||
  48               hashcmp(a->config->gitmodules_sha1, b->config->gitmodules_sha1);
  49}
  50
  51static int config_name_cmp(const void *unused_cmp_data,
  52                           const void *entry,
  53                           const void *entry_or_key,
  54                           const void *unused_keydata)
  55{
  56        const struct submodule_entry *a = entry;
  57        const struct submodule_entry *b = entry_or_key;
  58
  59        return strcmp(a->config->name, b->config->name) ||
  60               hashcmp(a->config->gitmodules_sha1, b->config->gitmodules_sha1);
  61}
  62
  63static struct submodule_cache *submodule_cache_alloc(void)
  64{
  65        return xcalloc(1, sizeof(struct submodule_cache));
  66}
  67
  68static void submodule_cache_init(struct submodule_cache *cache)
  69{
  70        hashmap_init(&cache->for_path, config_path_cmp, NULL, 0);
  71        hashmap_init(&cache->for_name, config_name_cmp, NULL, 0);
  72        cache->initialized = 1;
  73}
  74
  75static void free_one_config(struct submodule_entry *entry)
  76{
  77        free((void *) entry->config->path);
  78        free((void *) entry->config->name);
  79        free((void *) entry->config->branch);
  80        free((void *) entry->config->update_strategy.command);
  81        free(entry->config);
  82}
  83
  84static void submodule_cache_clear(struct submodule_cache *cache)
  85{
  86        struct hashmap_iter iter;
  87        struct submodule_entry *entry;
  88
  89        if (!cache->initialized)
  90                return;
  91
  92        /*
  93         * We iterate over the name hash here to be symmetric with the
  94         * allocation of struct submodule entries. Each is allocated by
  95         * their .gitmodules blob sha1 and submodule name.
  96         */
  97        hashmap_iter_init(&cache->for_name, &iter);
  98        while ((entry = hashmap_iter_next(&iter)))
  99                free_one_config(entry);
 100
 101        hashmap_free(&cache->for_path, 1);
 102        hashmap_free(&cache->for_name, 1);
 103        cache->initialized = 0;
 104        cache->gitmodules_read = 0;
 105}
 106
 107void submodule_cache_free(struct submodule_cache *cache)
 108{
 109        submodule_cache_clear(cache);
 110        free(cache);
 111}
 112
 113static unsigned int hash_sha1_string(const unsigned char *sha1,
 114                                     const char *string)
 115{
 116        return memhash(sha1, 20) + strhash(string);
 117}
 118
 119static void cache_put_path(struct submodule_cache *cache,
 120                           struct submodule *submodule)
 121{
 122        unsigned int hash = hash_sha1_string(submodule->gitmodules_sha1,
 123                                             submodule->path);
 124        struct submodule_entry *e = xmalloc(sizeof(*e));
 125        hashmap_entry_init(e, hash);
 126        e->config = submodule;
 127        hashmap_put(&cache->for_path, e);
 128}
 129
 130static void cache_remove_path(struct submodule_cache *cache,
 131                              struct submodule *submodule)
 132{
 133        unsigned int hash = hash_sha1_string(submodule->gitmodules_sha1,
 134                                             submodule->path);
 135        struct submodule_entry e;
 136        struct submodule_entry *removed;
 137        hashmap_entry_init(&e, hash);
 138        e.config = submodule;
 139        removed = hashmap_remove(&cache->for_path, &e, NULL);
 140        free(removed);
 141}
 142
 143static void cache_add(struct submodule_cache *cache,
 144                      struct submodule *submodule)
 145{
 146        unsigned int hash = hash_sha1_string(submodule->gitmodules_sha1,
 147                                             submodule->name);
 148        struct submodule_entry *e = xmalloc(sizeof(*e));
 149        hashmap_entry_init(e, hash);
 150        e->config = submodule;
 151        hashmap_add(&cache->for_name, e);
 152}
 153
 154static const struct submodule *cache_lookup_path(struct submodule_cache *cache,
 155                const unsigned char *gitmodules_sha1, const char *path)
 156{
 157        struct submodule_entry *entry;
 158        unsigned int hash = hash_sha1_string(gitmodules_sha1, path);
 159        struct submodule_entry key;
 160        struct submodule key_config;
 161
 162        hashcpy(key_config.gitmodules_sha1, gitmodules_sha1);
 163        key_config.path = path;
 164
 165        hashmap_entry_init(&key, hash);
 166        key.config = &key_config;
 167
 168        entry = hashmap_get(&cache->for_path, &key, NULL);
 169        if (entry)
 170                return entry->config;
 171        return NULL;
 172}
 173
 174static struct submodule *cache_lookup_name(struct submodule_cache *cache,
 175                const unsigned char *gitmodules_sha1, const char *name)
 176{
 177        struct submodule_entry *entry;
 178        unsigned int hash = hash_sha1_string(gitmodules_sha1, name);
 179        struct submodule_entry key;
 180        struct submodule key_config;
 181
 182        hashcpy(key_config.gitmodules_sha1, gitmodules_sha1);
 183        key_config.name = name;
 184
 185        hashmap_entry_init(&key, hash);
 186        key.config = &key_config;
 187
 188        entry = hashmap_get(&cache->for_name, &key, NULL);
 189        if (entry)
 190                return entry->config;
 191        return NULL;
 192}
 193
 194static int name_and_item_from_var(const char *var, struct strbuf *name,
 195                                  struct strbuf *item)
 196{
 197        const char *subsection, *key;
 198        int subsection_len, parse;
 199        parse = parse_config_key(var, "submodule", &subsection,
 200                        &subsection_len, &key);
 201        if (parse < 0 || !subsection)
 202                return 0;
 203
 204        strbuf_add(name, subsection, subsection_len);
 205        strbuf_addstr(item, key);
 206
 207        return 1;
 208}
 209
 210static struct submodule *lookup_or_create_by_name(struct submodule_cache *cache,
 211                const unsigned char *gitmodules_sha1, const char *name)
 212{
 213        struct submodule *submodule;
 214        struct strbuf name_buf = STRBUF_INIT;
 215
 216        submodule = cache_lookup_name(cache, gitmodules_sha1, name);
 217        if (submodule)
 218                return submodule;
 219
 220        submodule = xmalloc(sizeof(*submodule));
 221
 222        strbuf_addstr(&name_buf, name);
 223        submodule->name = strbuf_detach(&name_buf, NULL);
 224
 225        submodule->path = NULL;
 226        submodule->url = NULL;
 227        submodule->update_strategy.type = SM_UPDATE_UNSPECIFIED;
 228        submodule->update_strategy.command = NULL;
 229        submodule->fetch_recurse = RECURSE_SUBMODULES_NONE;
 230        submodule->ignore = NULL;
 231        submodule->branch = NULL;
 232        submodule->recommend_shallow = -1;
 233
 234        hashcpy(submodule->gitmodules_sha1, gitmodules_sha1);
 235
 236        cache_add(cache, submodule);
 237
 238        return submodule;
 239}
 240
 241static int parse_fetch_recurse(const char *opt, const char *arg,
 242                               int die_on_error)
 243{
 244        switch (git_parse_maybe_bool(arg)) {
 245        case 1:
 246                return RECURSE_SUBMODULES_ON;
 247        case 0:
 248                return RECURSE_SUBMODULES_OFF;
 249        default:
 250                if (!strcmp(arg, "on-demand"))
 251                        return RECURSE_SUBMODULES_ON_DEMAND;
 252
 253                if (die_on_error)
 254                        die("bad %s argument: %s", opt, arg);
 255                else
 256                        return RECURSE_SUBMODULES_ERROR;
 257        }
 258}
 259
 260int parse_submodule_fetchjobs(const char *var, const char *value)
 261{
 262        int fetchjobs = git_config_int(var, value);
 263        if (fetchjobs < 0)
 264                die(_("negative values not allowed for submodule.fetchjobs"));
 265        return fetchjobs;
 266}
 267
 268int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg)
 269{
 270        return parse_fetch_recurse(opt, arg, 1);
 271}
 272
 273int option_fetch_parse_recurse_submodules(const struct option *opt,
 274                                          const char *arg, int unset)
 275{
 276        int *v;
 277
 278        if (!opt->value)
 279                return -1;
 280
 281        v = opt->value;
 282
 283        if (unset) {
 284                *v = RECURSE_SUBMODULES_OFF;
 285        } else {
 286                if (arg)
 287                        *v = parse_fetch_recurse_submodules_arg(opt->long_name, arg);
 288                else
 289                        *v = RECURSE_SUBMODULES_ON;
 290        }
 291        return 0;
 292}
 293
 294static int parse_update_recurse(const char *opt, const char *arg,
 295                                int die_on_error)
 296{
 297        switch (git_parse_maybe_bool(arg)) {
 298        case 1:
 299                return RECURSE_SUBMODULES_ON;
 300        case 0:
 301                return RECURSE_SUBMODULES_OFF;
 302        default:
 303                if (die_on_error)
 304                        die("bad %s argument: %s", opt, arg);
 305                return RECURSE_SUBMODULES_ERROR;
 306        }
 307}
 308
 309int parse_update_recurse_submodules_arg(const char *opt, const char *arg)
 310{
 311        return parse_update_recurse(opt, arg, 1);
 312}
 313
 314static int parse_push_recurse(const char *opt, const char *arg,
 315                               int die_on_error)
 316{
 317        switch (git_parse_maybe_bool(arg)) {
 318        case 1:
 319                /* There's no simple "on" value when pushing */
 320                if (die_on_error)
 321                        die("bad %s argument: %s", opt, arg);
 322                else
 323                        return RECURSE_SUBMODULES_ERROR;
 324        case 0:
 325                return RECURSE_SUBMODULES_OFF;
 326        default:
 327                if (!strcmp(arg, "on-demand"))
 328                        return RECURSE_SUBMODULES_ON_DEMAND;
 329                else if (!strcmp(arg, "check"))
 330                        return RECURSE_SUBMODULES_CHECK;
 331                else if (!strcmp(arg, "only"))
 332                        return RECURSE_SUBMODULES_ONLY;
 333                else if (die_on_error)
 334                        die("bad %s argument: %s", opt, arg);
 335                else
 336                        return RECURSE_SUBMODULES_ERROR;
 337        }
 338}
 339
 340int parse_push_recurse_submodules_arg(const char *opt, const char *arg)
 341{
 342        return parse_push_recurse(opt, arg, 1);
 343}
 344
 345static void warn_multiple_config(const unsigned char *treeish_name,
 346                                 const char *name, const char *option)
 347{
 348        const char *commit_string = "WORKTREE";
 349        if (treeish_name)
 350                commit_string = sha1_to_hex(treeish_name);
 351        warning("%s:.gitmodules, multiple configurations found for "
 352                        "'submodule.%s.%s'. Skipping second one!",
 353                        commit_string, name, option);
 354}
 355
 356struct parse_config_parameter {
 357        struct submodule_cache *cache;
 358        const unsigned char *treeish_name;
 359        const unsigned char *gitmodules_sha1;
 360        int overwrite;
 361};
 362
 363static int parse_config(const char *var, const char *value, void *data)
 364{
 365        struct parse_config_parameter *me = data;
 366        struct submodule *submodule;
 367        struct strbuf name = STRBUF_INIT, item = STRBUF_INIT;
 368        int ret = 0;
 369
 370        /* this also ensures that we only parse submodule entries */
 371        if (!name_and_item_from_var(var, &name, &item))
 372                return 0;
 373
 374        submodule = lookup_or_create_by_name(me->cache,
 375                                             me->gitmodules_sha1,
 376                                             name.buf);
 377
 378        if (!strcmp(item.buf, "path")) {
 379                if (!value)
 380                        ret = config_error_nonbool(var);
 381                else if (!me->overwrite && submodule->path)
 382                        warn_multiple_config(me->treeish_name, submodule->name,
 383                                        "path");
 384                else {
 385                        if (submodule->path)
 386                                cache_remove_path(me->cache, submodule);
 387                        free((void *) submodule->path);
 388                        submodule->path = xstrdup(value);
 389                        cache_put_path(me->cache, submodule);
 390                }
 391        } else if (!strcmp(item.buf, "fetchrecursesubmodules")) {
 392                /* when parsing worktree configurations we can die early */
 393                int die_on_error = is_null_sha1(me->gitmodules_sha1);
 394                if (!me->overwrite &&
 395                    submodule->fetch_recurse != RECURSE_SUBMODULES_NONE)
 396                        warn_multiple_config(me->treeish_name, submodule->name,
 397                                        "fetchrecursesubmodules");
 398                else
 399                        submodule->fetch_recurse = parse_fetch_recurse(
 400                                                                var, value,
 401                                                                die_on_error);
 402        } else if (!strcmp(item.buf, "ignore")) {
 403                if (!value)
 404                        ret = config_error_nonbool(var);
 405                else if (!me->overwrite && submodule->ignore)
 406                        warn_multiple_config(me->treeish_name, submodule->name,
 407                                        "ignore");
 408                else if (strcmp(value, "untracked") &&
 409                         strcmp(value, "dirty") &&
 410                         strcmp(value, "all") &&
 411                         strcmp(value, "none"))
 412                        warning("Invalid parameter '%s' for config option "
 413                                        "'submodule.%s.ignore'", value, name.buf);
 414                else {
 415                        free((void *) submodule->ignore);
 416                        submodule->ignore = xstrdup(value);
 417                }
 418        } else if (!strcmp(item.buf, "url")) {
 419                if (!value) {
 420                        ret = config_error_nonbool(var);
 421                } else if (!me->overwrite && submodule->url) {
 422                        warn_multiple_config(me->treeish_name, submodule->name,
 423                                        "url");
 424                } else {
 425                        free((void *) submodule->url);
 426                        submodule->url = xstrdup(value);
 427                }
 428        } else if (!strcmp(item.buf, "update")) {
 429                if (!value)
 430                        ret = config_error_nonbool(var);
 431                else if (!me->overwrite &&
 432                         submodule->update_strategy.type != SM_UPDATE_UNSPECIFIED)
 433                        warn_multiple_config(me->treeish_name, submodule->name,
 434                                             "update");
 435                else if (parse_submodule_update_strategy(value,
 436                         &submodule->update_strategy) < 0)
 437                                die(_("invalid value for %s"), var);
 438        } else if (!strcmp(item.buf, "shallow")) {
 439                if (!me->overwrite && submodule->recommend_shallow != -1)
 440                        warn_multiple_config(me->treeish_name, submodule->name,
 441                                             "shallow");
 442                else
 443                        submodule->recommend_shallow =
 444                                git_config_bool(var, value);
 445        } else if (!strcmp(item.buf, "branch")) {
 446                if (!me->overwrite && submodule->branch)
 447                        warn_multiple_config(me->treeish_name, submodule->name,
 448                                             "branch");
 449                else {
 450                        free((void *)submodule->branch);
 451                        submodule->branch = xstrdup(value);
 452                }
 453        }
 454
 455        strbuf_release(&name);
 456        strbuf_release(&item);
 457
 458        return ret;
 459}
 460
 461static int gitmodule_oid_from_commit(const struct object_id *treeish_name,
 462                                     struct object_id *gitmodules_oid,
 463                                     struct strbuf *rev)
 464{
 465        int ret = 0;
 466
 467        if (is_null_oid(treeish_name)) {
 468                oidclr(gitmodules_oid);
 469                return 1;
 470        }
 471
 472        strbuf_addf(rev, "%s:.gitmodules", oid_to_hex(treeish_name));
 473        if (get_oid(rev->buf, gitmodules_oid) >= 0)
 474                ret = 1;
 475
 476        return ret;
 477}
 478
 479/* This does a lookup of a submodule configuration by name or by path
 480 * (key) with on-demand reading of the appropriate .gitmodules from
 481 * revisions.
 482 */
 483static const struct submodule *config_from(struct submodule_cache *cache,
 484                const struct object_id *treeish_name, const char *key,
 485                enum lookup_type lookup_type)
 486{
 487        struct strbuf rev = STRBUF_INIT;
 488        unsigned long config_size;
 489        char *config = NULL;
 490        struct object_id oid;
 491        enum object_type type;
 492        const struct submodule *submodule = NULL;
 493        struct parse_config_parameter parameter;
 494
 495        /*
 496         * If any parameter except the cache is a NULL pointer just
 497         * return the first submodule. Can be used to check whether
 498         * there are any submodules parsed.
 499         */
 500        if (!treeish_name || !key) {
 501                struct hashmap_iter iter;
 502                struct submodule_entry *entry;
 503
 504                entry = hashmap_iter_first(&cache->for_name, &iter);
 505                if (!entry)
 506                        return NULL;
 507                return entry->config;
 508        }
 509
 510        if (!gitmodule_oid_from_commit(treeish_name, &oid, &rev))
 511                goto out;
 512
 513        switch (lookup_type) {
 514        case lookup_name:
 515                submodule = cache_lookup_name(cache, oid.hash, key);
 516                break;
 517        case lookup_path:
 518                submodule = cache_lookup_path(cache, oid.hash, key);
 519                break;
 520        }
 521        if (submodule)
 522                goto out;
 523
 524        config = read_object_file(&oid, &type, &config_size);
 525        if (!config || type != OBJ_BLOB)
 526                goto out;
 527
 528        /* fill the submodule config into the cache */
 529        parameter.cache = cache;
 530        parameter.treeish_name = treeish_name->hash;
 531        parameter.gitmodules_sha1 = oid.hash;
 532        parameter.overwrite = 0;
 533        git_config_from_mem(parse_config, CONFIG_ORIGIN_SUBMODULE_BLOB, rev.buf,
 534                        config, config_size, &parameter);
 535        strbuf_release(&rev);
 536        free(config);
 537
 538        switch (lookup_type) {
 539        case lookup_name:
 540                return cache_lookup_name(cache, oid.hash, key);
 541        case lookup_path:
 542                return cache_lookup_path(cache, oid.hash, key);
 543        default:
 544                return NULL;
 545        }
 546
 547out:
 548        strbuf_release(&rev);
 549        free(config);
 550        return submodule;
 551}
 552
 553static void submodule_cache_check_init(struct repository *repo)
 554{
 555        if (repo->submodule_cache && repo->submodule_cache->initialized)
 556                return;
 557
 558        if (!repo->submodule_cache)
 559                repo->submodule_cache = submodule_cache_alloc();
 560
 561        submodule_cache_init(repo->submodule_cache);
 562}
 563
 564static int gitmodules_cb(const char *var, const char *value, void *data)
 565{
 566        struct repository *repo = data;
 567        struct parse_config_parameter parameter;
 568
 569        parameter.cache = repo->submodule_cache;
 570        parameter.treeish_name = NULL;
 571        parameter.gitmodules_sha1 = null_sha1;
 572        parameter.overwrite = 1;
 573
 574        return parse_config(var, value, &parameter);
 575}
 576
 577void repo_read_gitmodules(struct repository *repo)
 578{
 579        submodule_cache_check_init(repo);
 580
 581        if (repo->worktree) {
 582                char *gitmodules;
 583
 584                if (repo_read_index(repo) < 0)
 585                        return;
 586
 587                gitmodules = repo_worktree_path(repo, GITMODULES_FILE);
 588
 589                if (!is_gitmodules_unmerged(repo->index))
 590                        git_config_from_file(gitmodules_cb, gitmodules, repo);
 591
 592                free(gitmodules);
 593        }
 594
 595        repo->submodule_cache->gitmodules_read = 1;
 596}
 597
 598void gitmodules_config_oid(const struct object_id *commit_oid)
 599{
 600        struct strbuf rev = STRBUF_INIT;
 601        struct object_id oid;
 602
 603        submodule_cache_check_init(the_repository);
 604
 605        if (gitmodule_oid_from_commit(commit_oid, &oid, &rev)) {
 606                git_config_from_blob_oid(gitmodules_cb, rev.buf,
 607                                         &oid, the_repository);
 608        }
 609        strbuf_release(&rev);
 610
 611        the_repository->submodule_cache->gitmodules_read = 1;
 612}
 613
 614static void gitmodules_read_check(struct repository *repo)
 615{
 616        submodule_cache_check_init(repo);
 617
 618        /* read the repo's .gitmodules file if it hasn't been already */
 619        if (!repo->submodule_cache->gitmodules_read)
 620                repo_read_gitmodules(repo);
 621}
 622
 623const struct submodule *submodule_from_name(const struct object_id *treeish_name,
 624                const char *name)
 625{
 626        gitmodules_read_check(the_repository);
 627        return config_from(the_repository->submodule_cache, treeish_name, name, lookup_name);
 628}
 629
 630const struct submodule *submodule_from_path(const struct object_id *treeish_name,
 631                const char *path)
 632{
 633        gitmodules_read_check(the_repository);
 634        return config_from(the_repository->submodule_cache, treeish_name, path, lookup_path);
 635}
 636
 637const struct submodule *submodule_from_cache(struct repository *repo,
 638                                             const struct object_id *treeish_name,
 639                                             const char *key)
 640{
 641        gitmodules_read_check(repo);
 642        return config_from(repo->submodule_cache, treeish_name,
 643                           key, lookup_path);
 644}
 645
 646void submodule_free(void)
 647{
 648        if (the_repository->submodule_cache)
 649                submodule_cache_clear(the_repository->submodule_cache);
 650}