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