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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
diff --git a/src/refdb.c b/src/refdb.c
index 764d2c1..12dfaf1 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 05c0e1c..aeddaf7 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 c5d69c1..e7105c7 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;
}