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