diff options
Diffstat (limited to 'setup.c')
-rw-r--r-- | setup.c | 137 |
1 files changed, 121 insertions, 16 deletions
@@ -447,6 +447,63 @@ static int read_worktree_config(const char *var, const char *value, void *vdata) return 0; } +enum extension_result { + EXTENSION_ERROR = -1, /* compatible with error(), etc */ + EXTENSION_UNKNOWN = 0, + EXTENSION_OK = 1 +}; + +/* + * Do not add new extensions to this function. It handles extensions which are + * respected even in v0-format repositories for historical compatibility. + */ +static enum extension_result handle_extension_v0(const char *var, + const char *value, + const char *ext, + struct repository_format *data) +{ + if (!strcmp(ext, "noop")) { + return EXTENSION_OK; + } else if (!strcmp(ext, "preciousobjects")) { + data->precious_objects = git_config_bool(var, value); + return EXTENSION_OK; + } else if (!strcmp(ext, "partialclone")) { + if (!value) + return config_error_nonbool(var); + data->partial_clone = xstrdup(value); + return EXTENSION_OK; + } else if (!strcmp(ext, "worktreeconfig")) { + data->worktree_config = git_config_bool(var, value); + return EXTENSION_OK; + } + + return EXTENSION_UNKNOWN; +} + +/* + * Record any new extensions in this function. + */ +static enum extension_result handle_extension(const char *var, + const char *value, + const char *ext, + struct repository_format *data) +{ + if (!strcmp(ext, "noop-v1")) { + return EXTENSION_OK; + } else if (!strcmp(ext, "objectformat")) { + int format; + + if (!value) + return config_error_nonbool(var); + format = hash_algo_by_name(value); + if (format == GIT_HASH_UNKNOWN) + return error("invalid value for 'extensions.objectformat'"); + data->hash_algo = format; + return EXTENSION_OK; + } + return EXTENSION_UNKNOWN; +} + static int check_repo_format(const char *var, const char *value, void *vdata) { struct repository_format *data = vdata; @@ -455,23 +512,25 @@ static int check_repo_format(const char *var, const char *value, void *vdata) if (strcmp(var, "core.repositoryformatversion") == 0) data->version = git_config_int(var, value); else if (skip_prefix(var, "extensions.", &ext)) { - /* - * record any known extensions here; otherwise, - * we fall through to recording it as unknown, and - * check_repository_format will complain - */ - if (!strcmp(ext, "noop")) - ; - else if (!strcmp(ext, "preciousobjects")) - data->precious_objects = git_config_bool(var, value); - else if (!strcmp(ext, "partialclone")) { - if (!value) - return config_error_nonbool(var); - data->partial_clone = xstrdup(value); - } else if (!strcmp(ext, "worktreeconfig")) - data->worktree_config = git_config_bool(var, value); - else + switch (handle_extension_v0(var, value, ext, data)) { + case EXTENSION_ERROR: + return -1; + case EXTENSION_OK: + return 0; + case EXTENSION_UNKNOWN: + break; + } + + switch (handle_extension(var, value, ext, data)) { + case EXTENSION_ERROR: + return -1; + case EXTENSION_OK: + string_list_append(&data->v1_only_extensions, ext); + return 0; + case EXTENSION_UNKNOWN: string_list_append(&data->unknown_extensions, ext); + return 0; + } } return read_worktree_config(var, value, vdata); @@ -510,6 +569,7 @@ static int check_repository_format_gently(const char *gitdir, struct repository_ set_repository_format_partial_clone(candidate->partial_clone); repository_format_worktree_config = candidate->worktree_config; string_list_clear(&candidate->unknown_extensions, 0); + string_list_clear(&candidate->v1_only_extensions, 0); if (repository_format_worktree_config) { /* @@ -538,6 +598,37 @@ static int check_repository_format_gently(const char *gitdir, struct repository_ return 0; } +int upgrade_repository_format(int target_version) +{ + struct strbuf sb = STRBUF_INIT; + struct strbuf err = STRBUF_INIT; + struct strbuf repo_version = STRBUF_INIT; + struct repository_format repo_fmt = REPOSITORY_FORMAT_INIT; + + strbuf_git_common_path(&sb, the_repository, "config"); + read_repository_format(&repo_fmt, sb.buf); + strbuf_release(&sb); + + if (repo_fmt.version >= target_version) + return 0; + + if (verify_repository_format(&repo_fmt, &err) < 0) { + error("cannot upgrade repository format from %d to %d: %s", + repo_fmt.version, target_version, err.buf); + strbuf_release(&err); + return -1; + } + if (!repo_fmt.version && repo_fmt.unknown_extensions.nr) + return error("cannot upgrade repository format: " + "unknown extension %s", + repo_fmt.unknown_extensions.items[0].string); + + strbuf_addf(&repo_version, "%d", target_version); + git_config_set("core.repositoryformatversion", repo_version.buf); + strbuf_release(&repo_version); + return 1; +} + static void init_repository_format(struct repository_format *format) { const struct repository_format fresh = REPOSITORY_FORMAT_INIT; @@ -557,6 +648,7 @@ int read_repository_format(struct repository_format *format, const char *path) void clear_repository_format(struct repository_format *format) { string_list_clear(&format->unknown_extensions, 0); + string_list_clear(&format->v1_only_extensions, 0); free(format->work_tree); free(format->partial_clone); init_repository_format(format); @@ -582,6 +674,18 @@ int verify_repository_format(const struct repository_format *format, return -1; } + if (format->version == 0 && format->v1_only_extensions.nr) { + int i; + + strbuf_addstr(err, + _("repo version is 0, but v1-only extensions found:")); + + for (i = 0; i < format->v1_only_extensions.nr; i++) + strbuf_addf(err, "\n\t%s", + format->v1_only_extensions.items[i].string); + return -1; + } + return 0; } @@ -1273,6 +1377,7 @@ void check_repository_format(struct repository_format *fmt) fmt = &repo_fmt; check_repository_format_gently(get_git_dir(), fmt, NULL); startup_info->have_repository = 1; + repo_set_hash_algo(the_repository, fmt->hash_algo); clear_repository_format(&repo_fmt); } |