submodule-config.con commit convert.c: mark more strings for translation (d26a328)
   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 .gitmodules 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               oidcmp(&a->config->gitmodules_oid, &b->config->gitmodules_oid);
  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               oidcmp(&a->config->gitmodules_oid, &b->config->gitmodules_oid);
  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 .gitmodules 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_oid_string(const struct object_id *oid,
 113                                    const char *string)
 114{
 115        return memhash(oid->hash, the_hash_algo->rawsz) + strhash(string);
 116}
 117
 118static void cache_put_path(struct submodule_cache *cache,
 119                           struct submodule *submodule)
 120{
 121        unsigned int hash = hash_oid_string(&submodule->gitmodules_oid,
 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_oid_string(&submodule->gitmodules_oid,
 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_oid_string(&submodule->gitmodules_oid,
 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 struct object_id *gitmodules_oid, const char *path)
 155{
 156        struct submodule_entry *entry;
 157        unsigned int hash = hash_oid_string(gitmodules_oid, path);
 158        struct submodule_entry key;
 159        struct submodule key_config;
 160
 161        oidcpy(&key_config.gitmodules_oid, gitmodules_oid);
 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 struct object_id *gitmodules_oid, const char *name)
 175{
 176        struct submodule_entry *entry;
 177        unsigned int hash = hash_oid_string(gitmodules_oid, name);
 178        struct submodule_entry key;
 179        struct submodule key_config;
 180
 181        oidcpy(&key_config.gitmodules_oid, gitmodules_oid);
 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
 193int check_submodule_name(const char *name)
 194{
 195        /* Disallow empty names */
 196        if (!*name)
 197                return -1;
 198
 199        /*
 200         * Look for '..' as a path component. Check both '/' and '\\' as
 201         * separators rather than is_dir_sep(), because we want the name rules
 202         * to be consistent across platforms.
 203         */
 204        goto in_component; /* always start inside component */
 205        while (*name) {
 206                char c = *name++;
 207                if (c == '/' || c == '\\') {
 208in_component:
 209                        if (name[0] == '.' && name[1] == '.' &&
 210                            (!name[2] || name[2] == '/' || name[2] == '\\'))
 211                                return -1;
 212                }
 213        }
 214
 215        return 0;
 216}
 217
 218static int name_and_item_from_var(const char *var, struct strbuf *name,
 219                                  struct strbuf *item)
 220{
 221        const char *subsection, *key;
 222        int subsection_len, parse;
 223        parse = parse_config_key(var, "submodule", &subsection,
 224                        &subsection_len, &key);
 225        if (parse < 0 || !subsection)
 226                return 0;
 227
 228        strbuf_add(name, subsection, subsection_len);
 229        if (check_submodule_name(name->buf) < 0) {
 230                warning(_("ignoring suspicious submodule name: %s"), name->buf);
 231                strbuf_release(name);
 232                return 0;
 233        }
 234
 235        strbuf_addstr(item, key);
 236
 237        return 1;
 238}
 239
 240static struct submodule *lookup_or_create_by_name(struct submodule_cache *cache,
 241                const struct object_id *gitmodules_oid, const char *name)
 242{
 243        struct submodule *submodule;
 244        struct strbuf name_buf = STRBUF_INIT;
 245
 246        submodule = cache_lookup_name(cache, gitmodules_oid, name);
 247        if (submodule)
 248                return submodule;
 249
 250        submodule = xmalloc(sizeof(*submodule));
 251
 252        strbuf_addstr(&name_buf, name);
 253        submodule->name = strbuf_detach(&name_buf, NULL);
 254
 255        submodule->path = NULL;
 256        submodule->url = NULL;
 257        submodule->update_strategy.type = SM_UPDATE_UNSPECIFIED;
 258        submodule->update_strategy.command = NULL;
 259        submodule->fetch_recurse = RECURSE_SUBMODULES_NONE;
 260        submodule->ignore = NULL;
 261        submodule->branch = NULL;
 262        submodule->recommend_shallow = -1;
 263
 264        oidcpy(&submodule->gitmodules_oid, gitmodules_oid);
 265
 266        cache_add(cache, submodule);
 267
 268        return submodule;
 269}
 270
 271static int parse_fetch_recurse(const char *opt, const char *arg,
 272                               int die_on_error)
 273{
 274        switch (git_parse_maybe_bool(arg)) {
 275        case 1:
 276                return RECURSE_SUBMODULES_ON;
 277        case 0:
 278                return RECURSE_SUBMODULES_OFF;
 279        default:
 280                if (!strcmp(arg, "on-demand"))
 281                        return RECURSE_SUBMODULES_ON_DEMAND;
 282
 283                if (die_on_error)
 284                        die("bad %s argument: %s", opt, arg);
 285                else
 286                        return RECURSE_SUBMODULES_ERROR;
 287        }
 288}
 289
 290int parse_submodule_fetchjobs(const char *var, const char *value)
 291{
 292        int fetchjobs = git_config_int(var, value);
 293        if (fetchjobs < 0)
 294                die(_("negative values not allowed for submodule.fetchjobs"));
 295        return fetchjobs;
 296}
 297
 298int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg)
 299{
 300        return parse_fetch_recurse(opt, arg, 1);
 301}
 302
 303int option_fetch_parse_recurse_submodules(const struct option *opt,
 304                                          const char *arg, int unset)
 305{
 306        int *v;
 307
 308        if (!opt->value)
 309                return -1;
 310
 311        v = opt->value;
 312
 313        if (unset) {
 314                *v = RECURSE_SUBMODULES_OFF;
 315        } else {
 316                if (arg)
 317                        *v = parse_fetch_recurse_submodules_arg(opt->long_name, arg);
 318                else
 319                        *v = RECURSE_SUBMODULES_ON;
 320        }
 321        return 0;
 322}
 323
 324static int parse_update_recurse(const char *opt, const char *arg,
 325                                int die_on_error)
 326{
 327        switch (git_parse_maybe_bool(arg)) {
 328        case 1:
 329                return RECURSE_SUBMODULES_ON;
 330        case 0:
 331                return RECURSE_SUBMODULES_OFF;
 332        default:
 333                if (die_on_error)
 334                        die("bad %s argument: %s", opt, arg);
 335                return RECURSE_SUBMODULES_ERROR;
 336        }
 337}
 338
 339int parse_update_recurse_submodules_arg(const char *opt, const char *arg)
 340{
 341        return parse_update_recurse(opt, arg, 1);
 342}
 343
 344static int parse_push_recurse(const char *opt, const char *arg,
 345                               int die_on_error)
 346{
 347        switch (git_parse_maybe_bool(arg)) {
 348        case 1:
 349                /* There's no simple "on" value when pushing */
 350                if (die_on_error)
 351                        die("bad %s argument: %s", opt, arg);
 352                else
 353                        return RECURSE_SUBMODULES_ERROR;
 354        case 0:
 355                return RECURSE_SUBMODULES_OFF;
 356        default:
 357                if (!strcmp(arg, "on-demand"))
 358                        return RECURSE_SUBMODULES_ON_DEMAND;
 359                else if (!strcmp(arg, "check"))
 360                        return RECURSE_SUBMODULES_CHECK;
 361                else if (!strcmp(arg, "only"))
 362                        return RECURSE_SUBMODULES_ONLY;
 363                else if (die_on_error)
 364                        die("bad %s argument: %s", opt, arg);
 365                else
 366                        return RECURSE_SUBMODULES_ERROR;
 367        }
 368}
 369
 370int parse_push_recurse_submodules_arg(const char *opt, const char *arg)
 371{
 372        return parse_push_recurse(opt, arg, 1);
 373}
 374
 375static void warn_multiple_config(const struct object_id *treeish_name,
 376                                 const char *name, const char *option)
 377{
 378        const char *commit_string = "WORKTREE";
 379        if (treeish_name)
 380                commit_string = oid_to_hex(treeish_name);
 381        warning("%s:.gitmodules, multiple configurations found for "
 382                        "'submodule.%s.%s'. Skipping second one!",
 383                        commit_string, name, option);
 384}
 385
 386struct parse_config_parameter {
 387        struct submodule_cache *cache;
 388        const struct object_id *treeish_name;
 389        const struct object_id *gitmodules_oid;
 390        int overwrite;
 391};
 392
 393static int parse_config(const char *var, const char *value, void *data)
 394{
 395        struct parse_config_parameter *me = data;
 396        struct submodule *submodule;
 397        struct strbuf name = STRBUF_INIT, item = STRBUF_INIT;
 398        int ret = 0;
 399
 400        /* this also ensures that we only parse submodule entries */
 401        if (!name_and_item_from_var(var, &name, &item))
 402                return 0;
 403
 404        submodule = lookup_or_create_by_name(me->cache,
 405                                             me->gitmodules_oid,
 406                                             name.buf);
 407
 408        if (!strcmp(item.buf, "path")) {
 409                if (!value)
 410                        ret = config_error_nonbool(var);
 411                else if (!me->overwrite && submodule->path)
 412                        warn_multiple_config(me->treeish_name, submodule->name,
 413                                        "path");
 414                else {
 415                        if (submodule->path)
 416                                cache_remove_path(me->cache, submodule);
 417                        free((void *) submodule->path);
 418                        submodule->path = xstrdup(value);
 419                        cache_put_path(me->cache, submodule);
 420                }
 421        } else if (!strcmp(item.buf, "fetchrecursesubmodules")) {
 422                /* when parsing worktree configurations we can die early */
 423                int die_on_error = is_null_oid(me->gitmodules_oid);
 424                if (!me->overwrite &&
 425                    submodule->fetch_recurse != RECURSE_SUBMODULES_NONE)
 426                        warn_multiple_config(me->treeish_name, submodule->name,
 427                                        "fetchrecursesubmodules");
 428                else
 429                        submodule->fetch_recurse = parse_fetch_recurse(
 430                                                                var, value,
 431                                                                die_on_error);
 432        } else if (!strcmp(item.buf, "ignore")) {
 433                if (!value)
 434                        ret = config_error_nonbool(var);
 435                else if (!me->overwrite && submodule->ignore)
 436                        warn_multiple_config(me->treeish_name, submodule->name,
 437                                        "ignore");
 438                else if (strcmp(value, "untracked") &&
 439                         strcmp(value, "dirty") &&
 440                         strcmp(value, "all") &&
 441                         strcmp(value, "none"))
 442                        warning("Invalid parameter '%s' for config option "
 443                                        "'submodule.%s.ignore'", value, name.buf);
 444                else {
 445                        free((void *) submodule->ignore);
 446                        submodule->ignore = xstrdup(value);
 447                }
 448        } else if (!strcmp(item.buf, "url")) {
 449                if (!value) {
 450                        ret = config_error_nonbool(var);
 451                } else if (!me->overwrite && submodule->url) {
 452                        warn_multiple_config(me->treeish_name, submodule->name,
 453                                        "url");
 454                } else {
 455                        free((void *) submodule->url);
 456                        submodule->url = xstrdup(value);
 457                }
 458        } else if (!strcmp(item.buf, "update")) {
 459                if (!value)
 460                        ret = config_error_nonbool(var);
 461                else if (!me->overwrite &&
 462                         submodule->update_strategy.type != SM_UPDATE_UNSPECIFIED)
 463                        warn_multiple_config(me->treeish_name, submodule->name,
 464                                             "update");
 465                else if (parse_submodule_update_strategy(value,
 466                         &submodule->update_strategy) < 0)
 467                                die(_("invalid value for %s"), var);
 468        } else if (!strcmp(item.buf, "shallow")) {
 469                if (!me->overwrite && submodule->recommend_shallow != -1)
 470                        warn_multiple_config(me->treeish_name, submodule->name,
 471                                             "shallow");
 472                else
 473                        submodule->recommend_shallow =
 474                                git_config_bool(var, value);
 475        } else if (!strcmp(item.buf, "branch")) {
 476                if (!me->overwrite && submodule->branch)
 477                        warn_multiple_config(me->treeish_name, submodule->name,
 478                                             "branch");
 479                else {
 480                        free((void *)submodule->branch);
 481                        submodule->branch = xstrdup(value);
 482                }
 483        }
 484
 485        strbuf_release(&name);
 486        strbuf_release(&item);
 487
 488        return ret;
 489}
 490
 491static int gitmodule_oid_from_commit(const struct object_id *treeish_name,
 492                                     struct object_id *gitmodules_oid,
 493                                     struct strbuf *rev)
 494{
 495        int ret = 0;
 496
 497        if (is_null_oid(treeish_name)) {
 498                oidclr(gitmodules_oid);
 499                return 1;
 500        }
 501
 502        strbuf_addf(rev, "%s:.gitmodules", oid_to_hex(treeish_name));
 503        if (get_oid(rev->buf, gitmodules_oid) >= 0)
 504                ret = 1;
 505
 506        return ret;
 507}
 508
 509/* This does a lookup of a submodule configuration by name or by path
 510 * (key) with on-demand reading of the appropriate .gitmodules from
 511 * revisions.
 512 */
 513static const struct submodule *config_from(struct submodule_cache *cache,
 514                const struct object_id *treeish_name, const char *key,
 515                enum lookup_type lookup_type)
 516{
 517        struct strbuf rev = STRBUF_INIT;
 518        unsigned long config_size;
 519        char *config = NULL;
 520        struct object_id oid;
 521        enum object_type type;
 522        const struct submodule *submodule = NULL;
 523        struct parse_config_parameter parameter;
 524
 525        /*
 526         * If any parameter except the cache is a NULL pointer just
 527         * return the first submodule. Can be used to check whether
 528         * there are any submodules parsed.
 529         */
 530        if (!treeish_name || !key) {
 531                struct hashmap_iter iter;
 532                struct submodule_entry *entry;
 533
 534                entry = hashmap_iter_first(&cache->for_name, &iter);
 535                if (!entry)
 536                        return NULL;
 537                return entry->config;
 538        }
 539
 540        if (!gitmodule_oid_from_commit(treeish_name, &oid, &rev))
 541                goto out;
 542
 543        switch (lookup_type) {
 544        case lookup_name:
 545                submodule = cache_lookup_name(cache, &oid, key);
 546                break;
 547        case lookup_path:
 548                submodule = cache_lookup_path(cache, &oid, key);
 549                break;
 550        }
 551        if (submodule)
 552                goto out;
 553
 554        config = read_object_file(&oid, &type, &config_size);
 555        if (!config || type != OBJ_BLOB)
 556                goto out;
 557
 558        /* fill the submodule config into the cache */
 559        parameter.cache = cache;
 560        parameter.treeish_name = treeish_name;
 561        parameter.gitmodules_oid = &oid;
 562        parameter.overwrite = 0;
 563        git_config_from_mem(parse_config, CONFIG_ORIGIN_SUBMODULE_BLOB, rev.buf,
 564                        config, config_size, &parameter);
 565        strbuf_release(&rev);
 566        free(config);
 567
 568        switch (lookup_type) {
 569        case lookup_name:
 570                return cache_lookup_name(cache, &oid, key);
 571        case lookup_path:
 572                return cache_lookup_path(cache, &oid, key);
 573        default:
 574                return NULL;
 575        }
 576
 577out:
 578        strbuf_release(&rev);
 579        free(config);
 580        return submodule;
 581}
 582
 583static void submodule_cache_check_init(struct repository *repo)
 584{
 585        if (repo->submodule_cache && repo->submodule_cache->initialized)
 586                return;
 587
 588        if (!repo->submodule_cache)
 589                repo->submodule_cache = submodule_cache_alloc();
 590
 591        submodule_cache_init(repo->submodule_cache);
 592}
 593
 594static int gitmodules_cb(const char *var, const char *value, void *data)
 595{
 596        struct repository *repo = data;
 597        struct parse_config_parameter parameter;
 598
 599        parameter.cache = repo->submodule_cache;
 600        parameter.treeish_name = NULL;
 601        parameter.gitmodules_oid = &null_oid;
 602        parameter.overwrite = 1;
 603
 604        return parse_config(var, value, &parameter);
 605}
 606
 607void repo_read_gitmodules(struct repository *repo)
 608{
 609        submodule_cache_check_init(repo);
 610
 611        if (repo->worktree) {
 612                char *gitmodules;
 613
 614                if (repo_read_index(repo) < 0)
 615                        return;
 616
 617                gitmodules = repo_worktree_path(repo, GITMODULES_FILE);
 618
 619                if (!is_gitmodules_unmerged(repo->index))
 620                        git_config_from_file(gitmodules_cb, gitmodules, repo);
 621
 622                free(gitmodules);
 623        }
 624
 625        repo->submodule_cache->gitmodules_read = 1;
 626}
 627
 628void gitmodules_config_oid(const struct object_id *commit_oid)
 629{
 630        struct strbuf rev = STRBUF_INIT;
 631        struct object_id oid;
 632
 633        submodule_cache_check_init(the_repository);
 634
 635        if (gitmodule_oid_from_commit(commit_oid, &oid, &rev)) {
 636                git_config_from_blob_oid(gitmodules_cb, rev.buf,
 637                                         &oid, the_repository);
 638        }
 639        strbuf_release(&rev);
 640
 641        the_repository->submodule_cache->gitmodules_read = 1;
 642}
 643
 644static void gitmodules_read_check(struct repository *repo)
 645{
 646        submodule_cache_check_init(repo);
 647
 648        /* read the repo's .gitmodules file if it hasn't been already */
 649        if (!repo->submodule_cache->gitmodules_read)
 650                repo_read_gitmodules(repo);
 651}
 652
 653const struct submodule *submodule_from_name(struct repository *r,
 654                                            const struct object_id *treeish_name,
 655                const char *name)
 656{
 657        gitmodules_read_check(r);
 658        return config_from(r->submodule_cache, treeish_name, name, lookup_name);
 659}
 660
 661const struct submodule *submodule_from_path(struct repository *r,
 662                                            const struct object_id *treeish_name,
 663                const char *path)
 664{
 665        gitmodules_read_check(r);
 666        return config_from(r->submodule_cache, treeish_name, path, lookup_path);
 667}
 668
 669void submodule_free(struct repository *r)
 670{
 671        if (r->submodule_cache)
 672                submodule_cache_clear(r->submodule_cache);
 673}