commit 11995603330208ca0b2abf919ffc862d461bfc60 from: Stefan Sperling date: Sun Nov 05 16:26:31 2017 UTC resolve symbolic refs commit - bbfe163a911251028ccdcd91b7af7d9fb71919eb commit + 11995603330208ca0b2abf919ffc862d461bfc60 blob - 3be1c839cfa699e335c8b75c57ba02b9b159a78a blob + eeca74e22721ef756289ffa1d8fa2578b8bb99c4 --- include/got_object.h +++ include/got_object.h @@ -14,6 +14,6 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -struct got_object { +struct got_object_id { u_int8_t sha1[SHA1_DIGEST_LENGTH]; }; blob - 874712f177a4a427bd773e1ed642c3c96a8c85cf blob + 4c5b34a12566dc8a3a51e81f070f896ba32184e5 --- include/got_refs.h +++ include/got_refs.h @@ -43,8 +43,12 @@ struct got_reference { #define GOT_REF_MERGE_HEAD "MERGE_HEAD" #define GOT_REF_FETCH_HEAD "FETCH_HEAD" -const struct got_error * -got_ref_open(struct got_reference **, const char *, const char *); +struct got_repository; +struct got_object_id; +const struct got_error * got_ref_open(struct got_reference **, + struct got_repository *, const char *); void got_ref_close(struct got_reference *); - +struct got_reference *got_ref_dup(struct got_reference *); +const struct got_error *got_ref_resolve(struct got_object_id **, + struct got_repository *, struct got_reference *); blob - 89c33530b2b3ba77bc2946816c911d6b4cd636e0 blob + 7d9c9c23fc76ace9f171b147f75245d418254d7c --- include/got_repository.h +++ include/got_repository.h @@ -25,6 +25,12 @@ void got_repo_close(struct got_repository*); /* Get the absolute path to the top-level directory of a repository. */ const char *got_repo_get_path(struct got_repository *); +char *got_repo_get_path_git_dir(struct got_repository *); +char *got_repo_get_path_objects(struct got_repository *); +char *got_repo_get_path_refs(struct got_repository *); + +struct got_reference; + /* Get a reference, by name, from a repository. */ const struct got_error *got_repo_get_reference(struct got_reference **, struct got_repository *, const char *); blob - c520fc26b393adf1b5feed2c3bce6189be8297a3 blob + a51fefdc0e2f99ba8911531fa5ba38c3d664a020 --- lib/refs.c +++ lib/refs.c @@ -20,12 +20,17 @@ #include #include #include +#include +#include #include "got_error.h" +#include "got_object.h" +#include "got_repository.h" #include "got_refs.h" #include "path.h" + static const struct got_error * parse_symref(struct got_reference **ref, const char *name, const char *line) { @@ -54,18 +59,39 @@ parse_symref(struct got_reference **ref, const char *n } static int +parse_xdigit(uint8_t *val, const char *hex) +{ + char *ep; + long lval; + + errno = 0; + lval = strtol(hex, &ep, 16); + if (hex[0] == '\0' || *ep != '\0') + return 0; + if (errno == ERANGE && (lval == LONG_MAX || lval == LONG_MIN)) + return 0; + + *val = (uint8_t)lval; + return 1; +} + +static int parse_sha1_digest(uint8_t *digest, const char *line) { - uint8_t b; - int i, n; + uint8_t b = 0; + char hex[3] = {'\0', '\0', '\0'}; + int i, j; - memset(digest, 0, SHA1_DIGEST_LENGTH); for (i = 0; i < SHA1_DIGEST_LENGTH; i++) { - n = sscanf(line, "%hhx", &b); - if (n == 1) - digest[i] = b; - else + if (line[0] == '\0' || line[1] == '\0') return 0; + for (j = 0; j < 2; j++) { + hex[j] = *line; + line++; + } + if (!parse_xdigit(&b, hex)) + return 0; + digest[i] = b; } return 1; @@ -121,14 +147,37 @@ done: return err; } +static char * +get_refs_dir_path(struct got_repository *repo, const char *refname) +{ + /* Some refs live in the .git directory. */ + if (strcmp(refname, GOT_REF_HEAD) == 0 || + strcmp(refname, GOT_REF_ORIG_HEAD) == 0 || + strcmp(refname, GOT_REF_MERGE_HEAD) == 0 || + strcmp(refname, GOT_REF_FETCH_HEAD) == 0) + return got_repo_get_path_git_dir(repo); + + /* Is the ref name relative to the .git directory? */ + if (strncmp(refname, "refs/", 5) == 0) + return got_repo_get_path_git_dir(repo); + + return got_repo_get_path_refs(repo); +} + const struct got_error * -got_ref_open(struct got_reference **ref, const char *path_refs, +got_ref_open(struct got_reference **ref, struct got_repository *repo, const char *refname) { const struct got_error *err = NULL; char *path_ref = NULL; char *normpath = NULL; const char *parent_dir; + char *path_refs = get_refs_dir_path(repo, refname); + + if (path_refs == NULL) { + err = got_error(GOT_ERR_NO_MEM); + goto done; + } /* XXX For now, this assumes that refs exist in the filesystem. */ @@ -143,10 +192,11 @@ got_ref_open(struct got_reference **ref, const char *p goto done; } - err = parse_ref_file(ref, refname, normpath ? normpath : path_refs); + err = parse_ref_file(ref, refname, normpath); done: free(normpath); free(path_ref); + free(path_refs); return err; } @@ -159,3 +209,81 @@ got_ref_close(struct got_reference *ref) free(ref->ref.ref.name); free(ref); } + +struct got_reference * +got_ref_dup(struct got_reference *ref) +{ + struct got_reference *ret = calloc(1, sizeof(*ret)); + char *name = NULL; + char *symref = NULL; + + if (ret == NULL) + return NULL; + + ret->flags = ref->flags; + if (ref->flags & GOT_REF_IS_SYMBOLIC) { + ret->ref.symref.name = strdup(ref->ref.symref.name); + if (ret->ref.symref.name == NULL) { + free(ret); + return NULL; + } + ret->ref.symref.ref = strdup(ref->ref.symref.ref); + if (ret->ref.symref.ref == NULL) { + free(ret->ref.symref.name); + free(ret); + return NULL; + } + } else { + ref->ref.ref.name = strdup(ref->ref.ref.name); + if (ref->ref.ref.name == NULL) { + free(ret); + return NULL; + } + memcpy(ret->ref.ref.sha1, ref->ref.ref.sha1, + SHA1_DIGEST_LENGTH); + } + + return ret; +} + +static const struct got_error * +resolve_symbolic_ref(struct got_reference **resolved, + struct got_repository *repo, struct got_reference *ref) +{ + struct got_reference *nextref; + const struct got_error *err; + + err = got_ref_open(&nextref, repo, ref->ref.symref.ref); + if (err) + return err; + + if (nextref->flags & GOT_REF_IS_SYMBOLIC) + err = resolve_symbolic_ref(resolved, repo, nextref); + else + *resolved = got_ref_dup(nextref); + + got_ref_close(nextref); + return err; +} + +const struct got_error * +got_ref_resolve(struct got_object_id **id, struct got_repository *repo, + struct got_reference *ref) +{ + const struct got_error *err; + + if (ref->flags & GOT_REF_IS_SYMBOLIC) { + struct got_reference *resolved = NULL; + err = resolve_symbolic_ref(&resolved, repo, ref); + if (err == NULL) + err = got_ref_resolve(id, repo, resolved); + free(resolved); + return err; + } + + *id = calloc(1, sizeof(**id)); + if (*id == NULL) + return got_error(GOT_ERR_NO_MEM); + memcpy((*id)->sha1, ref->ref.ref.sha1, SHA1_DIGEST_LENGTH); + return NULL; +} blob - 6d7b5ecf1b90ffd234386b4628cee19748d53983 blob + 9e794a4d7f4135d316e402f7d6740e6612b55756 --- lib/repository.c +++ lib/repository.c @@ -37,8 +37,8 @@ #define GOT_FETCH_HEAD_FILE "FETCH_HEAD" #define GOT_ORIG_HEAD_FILE "ORIG_HEAD" -static char * -get_path_git_dir(struct got_repository *repo) +char * +got_repo_get_path_git_dir(struct got_repository *repo) { char *path_git; @@ -60,14 +60,14 @@ get_path_git_child(struct got_repository *repo, const return path_child; } -static char * -get_path_objects(struct got_repository *repo) +char * +got_repo_get_path_objects(struct got_repository *repo) { return get_path_git_child(repo, GOT_OBJECTS_DIR); } -static char * -get_path_refs(struct got_repository *repo) +char * +got_repo_get_path_refs(struct got_repository *repo) { return get_path_git_child(repo, GOT_REFS_DIR); } @@ -81,9 +81,9 @@ get_path_head(struct got_repository *repo) static int is_git_repo(struct got_repository *repo) { - char *path_git = get_path_git_dir(repo); - char *path_objects = get_path_objects(repo); - char *path_refs = get_path_refs(repo); + char *path_git = got_repo_get_path_git_dir(repo); + char *path_objects = got_repo_get_path_objects(repo); + char *path_refs = got_repo_get_path_refs(repo); char *path_head = get_path_head(repo); int ret; @@ -145,24 +145,3 @@ got_repo_get_path(struct got_repository *repo) { return repo->path; } - -const struct got_error * -got_repo_get_reference(struct got_reference **ref, - struct got_repository *repo, const char *refname) -{ - const struct got_error *err = NULL; - char *path_refs; - - /* Some refs live in the .git directory. */ - if (strcmp(refname, GOT_REF_HEAD) == 0 || - strcmp(refname, GOT_REF_ORIG_HEAD) == 0 || - strcmp(refname, GOT_REF_MERGE_HEAD) == 0 || - strcmp(refname, GOT_REF_FETCH_HEAD) == 0) - path_refs = get_path_git_dir(repo); - else - path_refs = get_path_refs(repo); - - err = got_ref_open(ref, path_refs, refname); - free(path_refs); - return err; -} blob - f70ab8cdc937290abf9b2d0afd92733f30acc517 blob + 1973fa4e78449a49c05220759400edfa491d4c4b --- regress/repository/repository_test.c +++ regress/repository/repository_test.c @@ -19,6 +19,7 @@ #include #include "got_error.h" +#include "got_object.h" #include "got_refs.h" #include "got_repository.h" @@ -52,7 +53,7 @@ repo_get_head_ref(const char *repo_path) err = got_repo_open(&repo, repo_path); if (err != NULL || repo == NULL) return 0; - err = got_repo_get_reference(&head_ref, repo, GOT_REF_HEAD); + err = got_ref_open(&head_ref, repo, GOT_REF_HEAD); if (err != NULL || head_ref == NULL) return 0; got_ref_close(head_ref); @@ -60,6 +61,30 @@ repo_get_head_ref(const char *repo_path) return 1; } +static int +repo_resolve_head_ref(const char *repo_path) +{ + const struct got_error *err; + struct got_repository *repo; + struct got_reference *head_ref; + struct got_object_id *id; + int ret; + + err = got_repo_open(&repo, repo_path); + if (err != NULL || repo == NULL) + return 0; + err = got_ref_open(&head_ref, repo, GOT_REF_HEAD); + if (err != NULL || head_ref == NULL) + return 0; + err = got_ref_resolve(&id, repo, head_ref); + if (err != NULL || head_ref == NULL) + return 0; + free(id); + got_ref_close(head_ref); + got_repo_close(repo); + return 1; +} + int main(int argc, const char *argv[]) { @@ -77,6 +102,7 @@ main(int argc, const char *argv[]) RUN_TEST(repo_open_test(repo_path), "repo_open"); RUN_TEST(repo_get_head_ref(repo_path), "get_head_ref"); + RUN_TEST(repo_resolve_head_ref(repo_path), "resolve_head_ref"); return failure ? 1 : 0; }