summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Steinhardt <ps@pks.im>2020-06-30 09:28:12 +0200
committerPatrick Steinhardt <ps@pks.im>2020-07-12 16:01:16 +0200
commitc54f40e47193af508b81eeec3ac7002649101360 (patch)
treef689fd0b2dfa98f888813f121b0bff4910f29cef
parent9703d26fc4d080863ce58166fae77ce12dcd4840 (diff)
downloadlibgit2-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.c48
-rw-r--r--src/refdb.h6
-rw-r--r--src/refs.c45
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;
}