repository: wire ref extensions to ref backends

The previous change introduced the extensions.refFormat config option.
It is a multi-valued config option that currently understands "files"
and "packed", with both values assumed by default. If any value is
provided explicitly, this default is ignored and the provided settings
are used instead.

The multi-valued nature of this extension presents a way to allow a user
to specify that they never want a packed-refs file (only use "files") or
that they never want loose reference files (only use "packed"). However,
that functionality is not currently connected.

Before actually modifying the files backend to understand these
extension settings, do the basic wiring that connects the
extensions.refFormat parsing to the creation of the ref backend. A
future change will actually change the ref backend initialization based
on these settings, but this communication of the extension is
sufficiently complicated to be worth an isolated change.

For now, also forbid the setting of only "packed". This is done by
redirecting the choice of backend to the packed backend when that
selection is made. A later change will make the "files"-only extension
value ignore the packed backend.

Signed-off-by: Derrick Stolee <derrickstolee@github.com>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
This commit is contained in:
Derrick Stolee 2022-11-07 18:35:39 +00:00 committed by Taylor Blau
parent b62ddf44aa
commit 51d24fadb5
8 changed files with 63 additions and 4 deletions

View file

@ -1155,6 +1155,8 @@ struct repository_format {
int hash_algo;
int sparse_index;
char *work_tree;
int ref_format_count;
enum ref_format_flags ref_format;
struct string_list unknown_extensions;
struct string_list v1_only_extensions;
};

22
refs.c
View file

@ -1982,6 +1982,15 @@ static struct ref_store *lookup_ref_store_map(struct hashmap *map,
return entry ? entry->refs : NULL;
}
static int add_ref_format_flags(enum ref_format_flags flags, int caps) {
if (flags & REF_FORMAT_FILES)
caps |= REF_STORE_FORMAT_FILES;
if (flags & REF_FORMAT_PACKED)
caps |= REF_STORE_FORMAT_PACKED;
return caps;
}
/*
* Create, record, and return a ref_store instance for the specified
* gitdir.
@ -1991,9 +2000,17 @@ static struct ref_store *ref_store_init(struct repository *repo,
unsigned int flags)
{
const char *be_name = "files";
struct ref_storage_be *be = find_ref_storage_backend(be_name);
struct ref_storage_be *be;
struct ref_store *refs;
flags = add_ref_format_flags(repo->ref_format, flags);
if (!(flags & REF_STORE_FORMAT_FILES) &&
(flags & REF_STORE_FORMAT_PACKED))
be_name = "packed";
be = find_ref_storage_backend(be_name);
if (!be)
BUG("reference backend %s is unknown", be_name);
@ -2009,7 +2026,8 @@ struct ref_store *get_main_ref_store(struct repository *r)
if (!r->gitdir)
BUG("attempting to get main_ref_store outside of repository");
r->refs_private = ref_store_init(r, r->gitdir, REF_STORE_ALL_CAPS);
r->refs_private = ref_store_init(r, r->gitdir,
REF_STORE_ALL_CAPS);
r->refs_private = maybe_debug_wrap_ref_store(r->gitdir, r->refs_private);
return r->refs_private;
}

View file

@ -3274,7 +3274,7 @@ static int files_init_db(struct ref_store *ref_store, struct strbuf *err UNUSED)
}
struct ref_storage_be refs_be_files = {
.next = NULL,
.next = &refs_be_packed,
.name = "files",
.init = files_ref_store_create,
.init_db = files_init_db,

View file

@ -521,6 +521,9 @@ struct ref_store;
REF_STORE_ODB | \
REF_STORE_MAIN)
#define REF_STORE_FORMAT_FILES (1 << 8) /* can use loose ref files */
#define REF_STORE_FORMAT_PACKED (1 << 9) /* can use packed-refs file */
/*
* Initialize the ref_store for the specified gitdir. These functions
* should call base_ref_store_init() to initialize the shared part of

View file

@ -182,6 +182,8 @@ int repo_init(struct repository *repo,
repo->repository_format_partial_clone = format.partial_clone;
format.partial_clone = NULL;
repo->ref_format = format.ref_format;
if (worktree)
repo_set_worktree(repo, worktree);

View file

@ -61,6 +61,11 @@ struct repo_path_cache {
char *shallow;
};
enum ref_format_flags {
REF_FORMAT_FILES = (1 << 0),
REF_FORMAT_PACKED = (1 << 1),
};
struct repository {
/* Environment */
/*
@ -95,6 +100,7 @@ struct repository {
* the ref object.
*/
struct ref_store *refs_private;
enum ref_format_flags ref_format;
/*
* Contains path to often used file names.

18
setup.c
View file

@ -578,9 +578,14 @@ static enum extension_result handle_extension(const char *var,
data->hash_algo = format;
return EXTENSION_OK;
} else if (!strcmp(ext, "refformat")) {
if (strcmp(value, "files") && strcmp(value, "packed"))
if (!strcmp(value, "files"))
data->ref_format |= REF_FORMAT_FILES;
else if (!strcmp(value, "packed"))
data->ref_format |= REF_FORMAT_PACKED;
else
return error(_("invalid value for '%s': '%s'"),
"extensions.refFormat", value);
data->ref_format_count++;
return EXTENSION_OK;
}
return EXTENSION_UNKNOWN;
@ -723,6 +728,11 @@ int read_repository_format(struct repository_format *format, const char *path)
git_config_from_file(check_repo_format, path, format);
if (format->version == -1)
clear_repository_format(format);
/* Set default ref_format if no extensions.refFormat exists. */
if (!format->ref_format_count)
format->ref_format = REF_FORMAT_FILES | REF_FORMAT_PACKED;
return format->version;
}
@ -1425,6 +1435,9 @@ int discover_git_directory(struct strbuf *commondir,
candidate.partial_clone;
candidate.partial_clone = NULL;
/* take ownership of candidate.ref_format */
the_repository->ref_format = candidate.ref_format;
clear_repository_format(&candidate);
return 0;
}
@ -1561,6 +1574,8 @@ const char *setup_git_directory_gently(int *nongit_ok)
the_repository->repository_format_partial_clone =
repo_fmt.partial_clone;
repo_fmt.partial_clone = NULL;
the_repository->ref_format = repo_fmt.ref_format;
}
}
/*
@ -1650,6 +1665,7 @@ void check_repository_format(struct repository_format *fmt)
repo_set_hash_algo(the_repository, fmt->hash_algo);
the_repository->repository_format_partial_clone =
xstrdup_or_null(fmt->partial_clone);
the_repository->ref_format = fmt->ref_format;
clear_repository_format(&repo_fmt);
}

View file

@ -24,4 +24,16 @@ test_expect_success 'invalid extensions.refFormat' '
grep "invalid value for '\''extensions.refFormat'\'': '\''bogus'\''" err
'
test_expect_success 'extensions.refFormat=packed only' '
git init only-packed &&
(
cd only-packed &&
git config core.repositoryFormatVersion 1 &&
git config extensions.refFormat packed &&
test_commit A &&
test_path_exists .git/packed-refs &&
test_path_is_missing .git/refs/tags/A
)
'
test_done