diff options
author | Patrick Steinhardt <ps@pks.im> | 2020-06-30 09:28:12 +0200 |
---|---|---|
committer | Patrick Steinhardt <ps@pks.im> | 2020-07-12 16:01:16 +0200 |
commit | c54f40e47193af508b81eeec3ac7002649101360 (patch) | |
tree | f689fd0b2dfa98f888813f121b0bff4910f29cef | |
parent | 9703d26fc4d080863ce58166fae77ce12dcd4840 (diff) | |
download | libgit2-c54f40e47193af508b81eeec3ac7002649101360.tar.gz |
refs: move resolving of references into the refdb
Resolving of symbolic references is currently implemented inside the
"refs" layer. As a result, it's hard to call this function from
low-level parts that only have a refdb available, but no repository, as
the "refs" layer always operates on the repository-level. So let's move
the function into the generic "refdb" implementation to lift this
restriction.
-rw-r--r-- | src/refdb.c | 48 | ||||
-rw-r--r-- | src/refdb.h | 6 | ||||
-rw-r--r-- | src/refs.c | 45 |
3 files changed, 59 insertions, 40 deletions
diff --git a/src/refdb.c b/src/refdb.c index 764d2c1f7..12dfaf1e2 100644 --- a/src/refdb.c +++ b/src/refdb.c @@ -17,6 +17,9 @@ #include "reflog.h" #include "posix.h" +#define DEFAULT_NESTING_LEVEL 5 +#define MAX_NESTING_LEVEL 10 + int git_refdb_new(git_refdb **out, git_repository *repo) { git_refdb *db; @@ -134,6 +137,51 @@ int git_refdb_lookup(git_reference **out, git_refdb *db, const char *ref_name) return 0; } +int git_refdb_resolve( + git_reference **out, + git_refdb *db, + const char *ref_name, + int max_nesting) +{ + git_reference *ref = NULL; + int error = 0, nesting; + + *out = NULL; + + if (max_nesting > MAX_NESTING_LEVEL) + max_nesting = MAX_NESTING_LEVEL; + else if (max_nesting < 0) + max_nesting = DEFAULT_NESTING_LEVEL; + + if ((error = git_refdb_lookup(&ref, db, ref_name)) < 0) + goto out; + + for (nesting = 0; nesting < max_nesting; nesting++) { + git_reference *resolved; + + if (ref->type == GIT_REFERENCE_DIRECT) + break; + if ((error = git_refdb_lookup(&resolved, db, git_reference_symbolic_target(ref))) < 0) + goto out; + + git_reference_free(ref); + ref = resolved; + } + + if (ref->type != GIT_REFERENCE_DIRECT && max_nesting != 0) { + git_error_set(GIT_ERROR_REFERENCE, + "cannot resolve reference (>%u levels deep)", max_nesting); + error = -1; + goto out; + } + + *out = ref; + ref = NULL; +out: + git_reference_free(ref); + return error; +} + int git_refdb_iterator(git_reference_iterator **out, git_refdb *db, const char *glob) { int error; diff --git a/src/refdb.h b/src/refdb.h index 05c0e1c67..aeddaf7da 100644 --- a/src/refdb.h +++ b/src/refdb.h @@ -30,6 +30,12 @@ int git_refdb_lookup( git_refdb *refdb, const char *ref_name); +int git_refdb_resolve( + git_reference **out, + git_refdb *db, + const char *ref_name, + int max_nesting); + int git_refdb_rename( git_reference **out, git_refdb *db, diff --git a/src/refs.c b/src/refs.c index c5d69c18c..e7105c7ae 100644 --- a/src/refs.c +++ b/src/refs.c @@ -214,52 +214,17 @@ int git_reference_lookup_resolved( const char *name, int max_nesting) { - git_refname_t scan_name; - git_reference_t scan_type; - int error = 0, nesting; - git_reference *ref = NULL; + git_refname_t normalized; git_refdb *refdb; + int error = 0; assert(ref_out && repo && name); - *ref_out = NULL; - - if (max_nesting > MAX_NESTING_LEVEL) - max_nesting = MAX_NESTING_LEVEL; - else if (max_nesting < 0) - max_nesting = DEFAULT_NESTING_LEVEL; - - scan_type = GIT_REFERENCE_SYMBOLIC; - - if ((error = reference_normalize_for_repo(scan_name, repo, name, true)) < 0) + if ((error = reference_normalize_for_repo(normalized, repo, name, true)) < 0 || + (error = git_repository_refdb__weakptr(&refdb, repo)) < 0 || + (error = git_refdb_resolve(ref_out, refdb, normalized, max_nesting)) < 0) return error; - if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0) - return error; - - for (nesting = max_nesting; - nesting >= 0 && scan_type == GIT_REFERENCE_SYMBOLIC; - nesting--) - { - if (nesting != max_nesting) { - strncpy(scan_name, ref->target.symbolic, sizeof(scan_name)); - git_reference_free(ref); - } - - if ((error = git_refdb_lookup(&ref, refdb, scan_name)) < 0) - return error; - - scan_type = ref->type; - } - - if (scan_type != GIT_REFERENCE_DIRECT && max_nesting != 0) { - git_error_set(GIT_ERROR_REFERENCE, - "cannot resolve reference (>%u levels deep)", max_nesting); - git_reference_free(ref); - return -1; - } - - *ref_out = ref; return 0; } |