submodule-config.con commit git-p4: don't groom exclude path list on every commit (ff8c50e)
   1#include "cache.h"
   2#include "dir.h"
   3#include "repository.h"
   4#include "config.h"
   5#include "submodule-config.h"
   6#include "submodule.h"
   7#include "strbuf.h"
   8#include "object-store.h"
   9#include "parse-options.h"
  10
  11/*
  12 * submodule cache lookup structure
  13 * There is one shared set of 'struct submodule' entries which can be
  14 * looked up by their sha1 blob id of the .gitmodules file and either
  15 * using path or name as key.
  16 * for_path stores submodule entries with path as key
  17 * for_name stores submodule entries with name as key
  18 */
  19struct submodule_cache {
  20        struct hashmap for_path;
  21        struct hashmap for_name;
  22        unsigned initialized:1;
  23        unsigned gitmodules_read:1;
  24};
  25
  26/*
  27 * thin wrapper struct needed to insert 'struct submodule' entries to
  28 * the hashmap
  29 */
  30struct submodule_entry {
  31        struct hashmap_entry ent;
  32        struct submodule *config;
  33};
  34
  35enum lookup_type {
  36        lookup_name,
  37        lookup_path
  38};
  39
  40static int config_path_cmp(const void *unused_cmp_data,
  41                           const void *entry,
  42                           const void *entry_or_key,
  43                           const void *unused_keydata)
  44{
  45        const struct submodule_entry *a = entry;
  46        const struct submodule_entry *b = entry_or_key;
  47
  48        return strcmp(a->config->path, b->config->path) ||
  49               !oideq(&a->config->gitmodules_oid, &b->config->gitmodules_oid);
  50}
  51
  52static int config_name_cmp(const void *unused_cmp_data,
  53                           const void *entry,
  54                           const void *entry_or_key,
  55                           const void *unused_keydata)
  56{
  57        const struct submodule_entry *a = entry;
  58        const struct submodule_entry *b = entry_or_key;
  59
  60        return strcmp(a->config->name, b->config->name) ||
  61               !oideq(&a->config->gitmodules_oid, &b->config->gitmodules_oid);
  62}
  63
  64static struct submodule_cache *submodule_cache_alloc(void)
  65{
  66        return xcalloc(1, sizeof(struct submodule_cache));
  67}
  68
  69static void submodule_cache_init(struct submodule_cache *cache)
  70{
  71        hashmap_init(&cache->for_path, config_path_cmp, NULL, 0);
  72        hashmap_init(&cache->for_name, config_name_cmp, NULL, 0);
  73        cache->initialized = 1;
  74}
  75
  76static void free_one_config(struct submodule_entry *entry)
  77{
  78        free((void *) entry->config->path);
  79        free((void *) entry->config->name);
  80        free((void *) entry->config->branch);
  81        free((void *) entry->config->update_strategy.command);
  82        free(entry->config);
  83}
  84
  85static void submodule_cache_clear(struct submodule_cache *cache)
  86{
  87        struct hashmap_iter iter;
  88        struct submodule_entry *entry;
  89
  90        if (!cache->initialized)
  91                return;
  92
  93        /*
  94         * We iterate over the name hash here to be symmetric with the
  95         * allocation of struct submodule entries. Each is allocated by
  96         * their .gitmodules blob sha1 and submodule name.
  97         */
  98        hashmap_iter_init(&cache->for_name, &iter);
  99        while ((entry = hashmap_iter_next(&iter)))
 100                free_one_config(entry);
 101
 102        hashmap_free(&cache->for_path, 1);
 103        hashmap_free(&cache->for_name, 1);
 104        cache->initialized = 0;
 105        cache->gitmodules_read = 0;
 106}
 107
 108void submodule_cache_free(struct submodule_cache *cache)
 109{
 110        submodule_cache_clear(cache);
 111        free(cache);
 112}
 113
 114static unsigned int hash_oid_string(const struct object_id *oid,
 115                                    const char *string)
 116{
 117        return memhash(oid->hash, the_hash_algo->rawsz) + strhash(string);
 118}
 119
 120static void cache_put_path(struct submodule_cache *cache,
 121                           struct submodule *submodule)
 122{
 123        unsigned int hash = hash_oid_string(&submodule->gitmodules_oid,
 124                                            submodule->path);
 125        struct submodule_entry *e = xmalloc(sizeof(*e));
 126        hashmap_entry_init(e, hash);
 127        e->config = submodule;
 128        hashmap_put(&cache->for_path, e);
 129}
 130
 131static void cache_remove_path(struct submodule_cache *cache,
 132                              struct submodule *submodule)
 133{
 134        unsigned int hash = hash_oid_string(&submodule->gitmodules_oid,
 135                                            submodule->path);
 136        struct submodule_entry e;
 137        struct submodule_entry *removed;
 138        hashmap_entry_init(&e, hash);
 139        e.config = submodule;
 140        removed = hashmap_remove(&cache->for_path, &e, NULL);
 141        free(removed);
 142}
 143
 144static void cache_add(struct submodule_cache *cache,
 145                      struct submodule *submodule)
 146{
 147        unsigned int hash = hash_oid_string(&submodule->gitmodules_oid,
 148                                            submodule->name);
 149        struct submodule_entry *e = xmalloc(sizeof(*e));
 150        hashmap_entry_init(e, hash);
 151        e->config = submodule;
 152        hashmap_add(&cache->for_name, e);
 153}
 154
 155static const struct submodule *cache_lookup_path(struct submodule_cache *cache,
 156                const struct object_id *gitmodules_oid, const char *path)
 157{
 158        struct submodule_entry *entry;
 159        unsigned int hash = hash_oid_string(gitmodules_oid, path);
 160        struct submodule_entry key;
 161        struct submodule key_config;
 162
 163        oidcpy(&key_config.gitmodules_oid, gitmodules_oid);
 164        key_config.path = path;
 165
 166        hashmap_entry_init(&key, hash);
 167        key.config = &key_config;
 168
 169        entry = hashmap_get(&cache->for_path, &key, NULL);
 170        if (entry)
 171                return entry->config;
 172        return NULL;
 173}
 174
 175static struct submodule *cache_lookup_name(struct submodule_cache *cache,
 176                const struct object_id *gitmodules_oid, const char *name)
 177{
 178        struct submodule_entry *entry;
 179        unsigned int hash = hash_oid_string(gitmodules_oid, name);
 180        struct submodule_entry key;
 181        struct submodule key_config;
 182
 183        oidcpy(&key_config.gitmodules_oid, gitmodules_oid);
 184        key_config.name = name;
 185
 186        hashmap_entry_init(&key, hash);
 187        key.config = &key_config;
 188
 189        entry = hashmap_get(&cache->for_name, &key, NULL);
 190        if (entry)
 191                return entry->config;
 192        return NULL;
 193}
 194
 195int check_submodule_name(const char *name)
 196{
 197        /* Disallow empty names */
 198        if (!*name)
 199                return -1;
 200
 201        /*
 202         * Look for '..' as a path component. Check both '/' and '\\' as
 203         * separators rather than is_dir_sep(), because we want the name rules
 204         * to be consistent across platforms.
 205         */
 206        goto in_component; /* always start inside component */
 207        while (*name) {
 208                char c = *name++;
 209                if (c == '/' || c == '\\') {
 210in_component:
 211                        if (name[0] == '.' && name[1] == '.' &&
 212                            (!name[2] || name[2] == '/' || name[2] == '\\'))
 213                                return -1;
 214                }
 215        }
 216
 217        return 0;
 218}
 219
 220static int name_and_item_from_var(const char *var, struct strbuf *name,
 221                                  struct strbuf *item)
 222{
 223        const char *subsection, *key;
 224        int subsection_len, parse;
 225        parse = parse_config_key(var, "submodule", &subsection,
 226                        &subsection_len, &key);
 227        if (parse < 0 || !subsection)
 228                return 0;
 229
 230        strbuf_add(name, subsection, subsection_len);
 231        if (check_submodule_name(name->buf) < 0) {
 232                warning(_("ignoring suspicious submodule name: %s"), name->buf);
 233                strbuf_release(name);
 234                return 0;
 235        }
 236
 237        strbuf_addstr(item, key);
 238
 239        return 1;
 240}
 241
 242static struct submodule *lookup_or_create_by_name(struct submodule_cache *cache,
 243                const struct object_id *gitmodules_oid, const char *name)
 244{
 245        struct submodule *submodule;
 246        struct strbuf name_buf = STRBUF_INIT;
 247
 248        submodule = cache_lookup_name(cache, gitmodules_oid, name);
 249        if (submodule)
 250                return submodule;
 251
 252        submodule = xmalloc(sizeof(*submodule));
 253
 254        strbuf_addstr(&name_buf, name);
 255        submodule->name = strbuf_detach(&name_buf, NULL);
 256
 257        submodule->path = NULL;
 258        submodule->url = NULL;
 259        submodule->update_strategy.type = SM_UPDATE_UNSPECIFIED;
 260        submodule->update_strategy.command = NULL;
 261        submodule->fetch_recurse = RECURSE_SUBMODULES_NONE;
 262        submodule->ignore = NULL;
 263        submodule->branch = NULL;
 264        submodule->recommend_shallow = -1;
 265
 266        oidcpy(&submodule->gitmodules_oid, gitmodules_oid);
 267
 268        cache_add(cache, submodule);
 269
 270        return submodule;
 271}
 272
 273static int parse_fetch_recurse(const char *opt, const char *arg,
 274                               int die_on_error)
 275{
 276        switch (git_parse_maybe_bool(arg)) {
 277        case 1:
 278                return RECURSE_SUBMODULES_ON;
 279        case 0:
 280                return RECURSE_SUBMODULES_OFF;
 281        default:
 282                if (!strcmp(arg, "on-demand"))
 283                        return RECURSE_SUBMODULES_ON_DEMAND;
 284                /*
 285                 * Please update $__git_fetch_recurse_submodules in
 286                 * git-completion.bash when you add new options.
 287                 */
 288                if (die_on_error)
 289                        die("bad %s argument: %s", opt, arg);
 290                else
 291                        return RECURSE_SUBMODULES_ERROR;
 292        }
 293}
 294
 295int parse_submodule_fetchjobs(const char *var, const char *value)
 296{
 297        int fetchjobs = git_config_int(var, value);
 298        if (fetchjobs < 0)
 299                die(_("negative values not allowed for submodule.fetchjobs"));
 300        return fetchjobs;
 301}
 302
 303int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg)
 304{
 305        return parse_fetch_recurse(opt, arg, 1);
 306}
 307
 308int option_fetch_parse_recurse_submodules(const struct option *opt,
 309                                          const char *arg, int unset)
 310{
 311        int *v;
 312
 313        if (!opt->value)
 314                return -1;
 315
 316        v = opt->value;
 317
 318        if (unset) {
 319                *v = RECURSE_SUBMODULES_OFF;
 320        } else {
 321                if (arg)
 322                        *v = parse_fetch_recurse_submodules_arg(opt->long_name, arg);
 323                else
 324                        *v = RECURSE_SUBMODULES_ON;
 325        }
 326        return 0;
 327}
 328
 329static int parse_update_recurse(const char *opt, const char *arg,
 330                                int die_on_error)
 331{
 332        switch (git_parse_maybe_bool(arg)) {
 333        case 1:
 334                return RECURSE_SUBMODULES_ON;
 335        case 0:
 336                return RECURSE_SUBMODULES_OFF;
 337        default:
 338                if (die_on_error)
 339                        die("bad %s argument: %s", opt, arg);
 340                return RECURSE_SUBMODULES_ERROR;
 341        }
 342}
 343
 344int parse_update_recurse_submodules_arg(const char *opt, const char *arg)
 345{
 346        return parse_update_recurse(opt, arg, 1);
 347}
 348
 349static int parse_push_recurse(const char *opt, const char *arg,
 350                               int die_on_error)
 351{
 352        switch (git_parse_maybe_bool(arg)) {
 353        case 1:
 354                /* There's no simple "on" value when pushing */
 355                if (die_on_error)
 356                        die("bad %s argument: %s", opt, arg);
 357                else
 358                        return RECURSE_SUBMODULES_ERROR;
 359        case 0:
 360                return RECURSE_SUBMODULES_OFF;
 361        default:
 362                if (!strcmp(arg, "on-demand"))
 363                        return RECURSE_SUBMODULES_ON_DEMAND;
 364                else if (!strcmp(arg, "check"))
 365                        return RECURSE_SUBMODULES_CHECK;
 366                else if (!strcmp(arg, "only"))
 367                        return RECURSE_SUBMODULES_ONLY;
 368                /*
 369                 * Please update $__git_push_recurse_submodules in
 370                 * git-completion.bash when you add new modes.
 371                 */
 372                else if (die_on_error)
 373                        die("bad %s argument: %s", opt, arg);
 374                else
 375                        return RECURSE_SUBMODULES_ERROR;
 376        }
 377}
 378
 379int parse_push_recurse_submodules_arg(const char *opt, const char *arg)
 380{
 381        return parse_push_recurse(opt, arg, 1);
 382}
 383
 384static void warn_multiple_config(const struct object_id *treeish_name,
 385                                 const char *name, const char *option)
 386{
 387        const char *commit_string = "WORKTREE";
 388        if (treeish_name)
 389                commit_string = oid_to_hex(treeish_name);
 390        warning("%s:.gitmodules, multiple configurations found for "
 391                        "'submodule.%s.%s'. Skipping second one!",
 392                        commit_string, name, option);
 393}
 394
 395static void warn_command_line_option(const char *var, const char *value)
 396{
 397        warning(_("ignoring '%s' which may be interpreted as"
 398                  " a command-line option: %s"), var, value);
 399}
 400
 401struct parse_config_parameter {
 402        struct submodule_cache *cache;
 403        const struct object_id *treeish_name;
 404        const struct object_id *gitmodules_oid;
 405        int overwrite;
 406};
 407
 408static int parse_config(const char *var, const char *value, void *data)
 409{
 410        struct parse_config_parameter *me = data;
 411        struct submodule *submodule;
 412        struct strbuf name = STRBUF_INIT, item = STRBUF_INIT;
 413        int ret = 0;
 414
 415        /* this also ensures that we only parse submodule entries */
 416        if (!name_and_item_from_var(var, &name, &item))
 417                return 0;
 418
 419        submodule = lookup_or_create_by_name(me->cache,
 420                                             me->gitmodules_oid,
 421                                             name.buf);
 422
 423        if (!strcmp(item.buf, "path")) {
 424                if (!value)
 425                        ret = config_error_nonbool(var);
 426                else if (looks_like_command_line_option(value))
 427                        warn_command_line_option(var, value);
 428                else if (!me->overwrite && submodule->path)
 429                        warn_multiple_config(me->treeish_name, submodule->name,
 430                                        "path");
 431                else {
 432                        if (submodule->path)
 433                                cache_remove_path(me->cache, submodule);
 434                        free((void *) submodule->path);
 435                        submodule->path = xstrdup(value);
 436                        cache_put_path(me->cache, submodule);
 437                }
 438        } else if (!strcmp(item.buf, "fetchrecursesubmodules")) {
 439                /* when parsing worktree configurations we can die early */
 440                int die_on_error = is_null_oid(me->gitmodules_oid);
 441                if (!me->overwrite &&
 442                    submodule->fetch_recurse != RECURSE_SUBMODULES_NONE)
 443                        warn_multiple_config(me->treeish_name, submodule->name,
 444                                        "fetchrecursesubmodules");
 445                else
 446                        submodule->fetch_recurse = parse_fetch_recurse(
 447                                                                var, value,
 448                                                                die_on_error);
 449        } else if (!strcmp(item.buf, "ignore")) {
 450                if (!value)
 451                        ret = config_error_nonbool(var);
 452                else if (!me->overwrite && submodule->ignore)
 453                        warn_multiple_config(me->treeish_name, submodule->name,
 454                                        "ignore");
 455                else if (strcmp(value, "untracked") &&
 456                         strcmp(value, "dirty") &&
 457                         strcmp(value, "all") &&
 458                         strcmp(value, "none"))
 459                        warning("Invalid parameter '%s' for config option "
 460                                        "'submodule.%s.ignore'", value, name.buf);
 461                else {
 462                        free((void *) submodule->ignore);
 463                        submodule->ignore = xstrdup(value);
 464                }
 465        } else if (!strcmp(item.buf, "url")) {
 466                if (!value) {
 467                        ret = config_error_nonbool(var);
 468                } else if (looks_like_command_line_option(value)) {
 469                        warn_command_line_option(var, value);
 470                } else if (!me->overwrite && submodule->url) {
 471                        warn_multiple_config(me->treeish_name, submodule->name,
 472                                        "url");
 473                } else {
 474                        free((void *) submodule->url);
 475                        submodule->url = xstrdup(value);
 476                }
 477        } else if (!strcmp(item.buf, "update")) {
 478                if (!value)
 479                        ret = config_error_nonbool(var);
 480                else if (!me->overwrite &&
 481                         submodule->update_strategy.type != SM_UPDATE_UNSPECIFIED)
 482                        warn_multiple_config(me->treeish_name, submodule->name,
 483                                             "update");
 484                else if (parse_submodule_update_strategy(value,
 485                         &submodule->update_strategy) < 0)
 486                                die(_("invalid value for %s"), var);
 487        } else if (!strcmp(item.buf, "shallow")) {
 488                if (!me->overwrite && submodule->recommend_shallow != -1)
 489                        warn_multiple_config(me->treeish_name, submodule->name,
 490                                             "shallow");
 491                else
 492                        submodule->recommend_shallow =
 493                                git_config_bool(var, value);
 494        } else if (!strcmp(item.buf, "branch")) {
 495                if (!me->overwrite && submodule->branch)
 496                        warn_multiple_config(me->treeish_name, submodule->name,
 497                                             "branch");
 498                else {
 499                        free((void *)submodule->branch);
 500                        submodule->branch = xstrdup(value);
 501                }
 502        }
 503
 504        strbuf_release(&name);
 505        strbuf_release(&item);
 506
 507        return ret;
 508}
 509
 510static int gitmodule_oid_from_commit(const struct object_id *treeish_name,
 511                                     struct object_id *gitmodules_oid,
 512                                     struct strbuf *rev)
 513{
 514        int ret = 0;
 515
 516        if (is_null_oid(treeish_name)) {
 517                oidclr(gitmodules_oid);
 518                return 1;
 519        }
 520
 521        strbuf_addf(rev, "%s:.gitmodules", oid_to_hex(treeish_name));
 522        if (get_oid(rev->buf, gitmodules_oid) >= 0)
 523                ret = 1;
 524
 525        return ret;
 526}
 527
 528/* This does a lookup of a submodule configuration by name or by path
 529 * (key) with on-demand reading of the appropriate .gitmodules from
 530 * revisions.
 531 */
 532static const struct submodule *config_from(struct submodule_cache *cache,
 533                const struct object_id *treeish_name, const char *key,
 534                enum lookup_type lookup_type)
 535{
 536        struct strbuf rev = STRBUF_INIT;
 537        unsigned long config_size;
 538        char *config = NULL;
 539        struct object_id oid;
 540        enum object_type type;
 541        const struct submodule *submodule = NULL;
 542        struct parse_config_parameter parameter;
 543
 544        /*
 545         * If any parameter except the cache is a NULL pointer just
 546         * return the first submodule. Can be used to check whether
 547         * there are any submodules parsed.
 548         */
 549        if (!treeish_name || !key) {
 550                struct hashmap_iter iter;
 551                struct submodule_entry *entry;
 552
 553                entry = hashmap_iter_first(&cache->for_name, &iter);
 554                if (!entry)
 555                        return NULL;
 556                return entry->config;
 557        }
 558
 559        if (!gitmodule_oid_from_commit(treeish_name, &oid, &rev))
 560                goto out;
 561
 562        switch (lookup_type) {
 563        case lookup_name:
 564                submodule = cache_lookup_name(cache, &oid, key);
 565                break;
 566        case lookup_path:
 567                submodule = cache_lookup_path(cache, &oid, key);
 568                break;
 569        }
 570        if (submodule)
 571                goto out;
 572
 573        config = read_object_file(&oid, &type, &config_size);
 574        if (!config || type != OBJ_BLOB)
 575                goto out;
 576
 577        /* fill the submodule config into the cache */
 578        parameter.cache = cache;
 579        parameter.treeish_name = treeish_name;
 580        parameter.gitmodules_oid = &oid;
 581        parameter.overwrite = 0;
 582        git_config_from_mem(parse_config, CONFIG_ORIGIN_SUBMODULE_BLOB, rev.buf,
 583                        config, config_size, &parameter, NULL);
 584        strbuf_release(&rev);
 585        free(config);
 586
 587        switch (lookup_type) {
 588        case lookup_name:
 589                return cache_lookup_name(cache, &oid, key);
 590        case lookup_path:
 591                return cache_lookup_path(cache, &oid, key);
 592        default:
 593                return NULL;
 594        }
 595
 596out:
 597        strbuf_release(&rev);
 598        free(config);
 599        return submodule;
 600}
 601
 602static void submodule_cache_check_init(struct repository *repo)
 603{
 604        if (repo->submodule_cache && repo->submodule_cache->initialized)
 605                return;
 606
 607        if (!repo->submodule_cache)
 608                repo->submodule_cache = submodule_cache_alloc();
 609
 610        submodule_cache_init(repo->submodule_cache);
 611}
 612
 613/*
 614 * Note: This function is private for a reason, the '.gitmodules' file should
 615 * not be used as as a mechanism to retrieve arbitrary configuration stored in
 616 * the repository.
 617 *
 618 * Runs the provided config function on the '.gitmodules' file found in the
 619 * working directory.
 620 */
 621static void config_from_gitmodules(config_fn_t fn, struct repository *repo, void *data)
 622{
 623        if (repo->worktree) {
 624                struct git_config_source config_source = { 0 };
 625                const struct config_options opts = { 0 };
 626                struct object_id oid;
 627                char *file;
 628
 629                file = repo_worktree_path(repo, GITMODULES_FILE);
 630                if (file_exists(file)) {
 631                        config_source.file = file;
 632                } else if (repo->submodule_prefix) {
 633                        /*
 634                         * When get_oid and config_with_options, used below,
 635                         * become able to work on a specific repository, this
 636                         * warning branch can be removed.
 637                         */
 638                        warning("nested submodules without %s in the working tree are not supported yet",
 639                                GITMODULES_FILE);
 640                        goto out;
 641                } else if (get_oid(GITMODULES_INDEX, &oid) >= 0) {
 642                        config_source.blob = GITMODULES_INDEX;
 643                } else if (get_oid(GITMODULES_HEAD, &oid) >= 0) {
 644                        config_source.blob = GITMODULES_HEAD;
 645                } else {
 646                        goto out;
 647                }
 648
 649                config_with_options(fn, data, &config_source, &opts);
 650
 651out:
 652                free(file);
 653        }
 654}
 655
 656static int gitmodules_cb(const char *var, const char *value, void *data)
 657{
 658        struct repository *repo = data;
 659        struct parse_config_parameter parameter;
 660
 661        parameter.cache = repo->submodule_cache;
 662        parameter.treeish_name = NULL;
 663        parameter.gitmodules_oid = &null_oid;
 664        parameter.overwrite = 1;
 665
 666        return parse_config(var, value, &parameter);
 667}
 668
 669void repo_read_gitmodules(struct repository *repo)
 670{
 671        submodule_cache_check_init(repo);
 672
 673        if (repo_read_index(repo) < 0)
 674                return;
 675
 676        if (!is_gitmodules_unmerged(repo->index))
 677                config_from_gitmodules(gitmodules_cb, repo, repo);
 678
 679        repo->submodule_cache->gitmodules_read = 1;
 680}
 681
 682void gitmodules_config_oid(const struct object_id *commit_oid)
 683{
 684        struct strbuf rev = STRBUF_INIT;
 685        struct object_id oid;
 686
 687        submodule_cache_check_init(the_repository);
 688
 689        if (gitmodule_oid_from_commit(commit_oid, &oid, &rev)) {
 690                git_config_from_blob_oid(gitmodules_cb, rev.buf,
 691                                         &oid, the_repository);
 692        }
 693        strbuf_release(&rev);
 694
 695        the_repository->submodule_cache->gitmodules_read = 1;
 696}
 697
 698static void gitmodules_read_check(struct repository *repo)
 699{
 700        submodule_cache_check_init(repo);
 701
 702        /* read the repo's .gitmodules file if it hasn't been already */
 703        if (!repo->submodule_cache->gitmodules_read)
 704                repo_read_gitmodules(repo);
 705}
 706
 707const struct submodule *submodule_from_name(struct repository *r,
 708                                            const struct object_id *treeish_name,
 709                const char *name)
 710{
 711        gitmodules_read_check(r);
 712        return config_from(r->submodule_cache, treeish_name, name, lookup_name);
 713}
 714
 715const struct submodule *submodule_from_path(struct repository *r,
 716                                            const struct object_id *treeish_name,
 717                const char *path)
 718{
 719        gitmodules_read_check(r);
 720        return config_from(r->submodule_cache, treeish_name, path, lookup_path);
 721}
 722
 723void submodule_free(struct repository *r)
 724{
 725        if (r->submodule_cache)
 726                submodule_cache_clear(r->submodule_cache);
 727}
 728
 729static int config_print_callback(const char *var, const char *value, void *cb_data)
 730{
 731        char *wanted_key = cb_data;
 732
 733        if (!strcmp(wanted_key, var))
 734                printf("%s\n", value);
 735
 736        return 0;
 737}
 738
 739int print_config_from_gitmodules(struct repository *repo, const char *key)
 740{
 741        int ret;
 742        char *store_key;
 743
 744        ret = git_config_parse_key(key, &store_key, NULL);
 745        if (ret < 0)
 746                return CONFIG_INVALID_KEY;
 747
 748        config_from_gitmodules(config_print_callback, repo, store_key);
 749
 750        free(store_key);
 751        return 0;
 752}
 753
 754int config_set_in_gitmodules_file_gently(const char *key, const char *value)
 755{
 756        int ret;
 757
 758        ret = git_config_set_in_file_gently(GITMODULES_FILE, key, value);
 759        if (ret < 0)
 760                /* Maybe the user already did that, don't error out here */
 761                warning(_("Could not update .gitmodules entry %s"), key);
 762
 763        return ret;
 764}
 765
 766struct fetch_config {
 767        int *max_children;
 768        int *recurse_submodules;
 769};
 770
 771static int gitmodules_fetch_config(const char *var, const char *value, void *cb)
 772{
 773        struct fetch_config *config = cb;
 774        if (!strcmp(var, "submodule.fetchjobs")) {
 775                *(config->max_children) = parse_submodule_fetchjobs(var, value);
 776                return 0;
 777        } else if (!strcmp(var, "fetch.recursesubmodules")) {
 778                *(config->recurse_submodules) = parse_fetch_recurse_submodules_arg(var, value);
 779                return 0;
 780        }
 781
 782        return 0;
 783}
 784
 785void fetch_config_from_gitmodules(int *max_children, int *recurse_submodules)
 786{
 787        struct fetch_config config = {
 788                .max_children = max_children,
 789                .recurse_submodules = recurse_submodules
 790        };
 791        config_from_gitmodules(gitmodules_fetch_config, the_repository, &config);
 792}
 793
 794static int gitmodules_update_clone_config(const char *var, const char *value,
 795                                          void *cb)
 796{
 797        int *max_jobs = cb;
 798        if (!strcmp(var, "submodule.fetchjobs"))
 799                *max_jobs = parse_submodule_fetchjobs(var, value);
 800        return 0;
 801}
 802
 803void update_clone_config_from_gitmodules(int *max_jobs)
 804{
 805        config_from_gitmodules(gitmodules_update_clone_config, the_repository, &max_jobs);
 806}