commit e09a504cc5b72ff4eca5d539b6fb50c8d01d0036 from: Stefan Sperling date: Fri Jun 28 20:05:17 2019 UTC introduce support for abbreviated object IDs commit - d69bcdf7cbe646a8ad22a81f8665f3bd2e39e189 commit + e09a504cc5b72ff4eca5d539b6fb50c8d01d0036 blob - a4975d670ed06aa6ed6696642cd7e23b2e0a0ee9 blob + 63ce30e7bcc45b4859409015ccaceab0666be898 --- got/got.c +++ got/got.c @@ -560,8 +560,8 @@ cmd_checkout(int argc, char *argv[]) if (commit_id_str) { struct got_object_id *commit_id; - error = got_object_resolve_id_str(&commit_id, repo, - commit_id_str); + error = got_repo_match_object_id_prefix(&commit_id, + commit_id_str, repo); if (error != NULL) goto done; error = check_linear_ancestry(commit_id, @@ -741,8 +741,8 @@ cmd_update(int argc, char *argv[]) if (error != NULL) goto done; } else { - error = got_object_resolve_id_str(&commit_id, repo, - commit_id_str); + error = got_repo_match_object_id_prefix(&commit_id, + commit_id_str, repo); if (error != NULL) goto done; } @@ -1190,8 +1190,8 @@ cmd_log(int argc, char *argv[]) goto done; } if (commit == NULL) { - error = got_object_resolve_id_str(&id, repo, - start_commit); + error = got_repo_match_object_id_prefix(&id, + start_commit, repo); if (error != NULL) return error; } @@ -1429,7 +1429,7 @@ cmd_diff(int argc, char *argv[]) goto done; } - error = got_object_resolve_id_str(&id1, repo, id_str1); + error = got_repo_match_object_id_prefix(&id1, id_str1, repo); if (error) { struct got_reference *ref; if (error->code != GOT_ERR_BAD_OBJ_ID_STR) @@ -1454,7 +1454,7 @@ cmd_diff(int argc, char *argv[]) } } - error = got_object_resolve_id_str(&id2, repo, id_str2); + error = got_repo_match_object_id_prefix(&id2, id_str2, repo); if (error) { struct got_reference *ref; if (error->code != GOT_ERR_BAD_OBJ_ID_STR) @@ -1642,8 +1642,8 @@ cmd_blame(int argc, char *argv[]) if (error != NULL) goto done; } else { - error = got_object_resolve_id_str(&commit_id, repo, - commit_id_str); + error = got_repo_match_object_id_prefix(&commit_id, + commit_id_str, repo); if (error != NULL) goto done; } @@ -1874,8 +1874,8 @@ cmd_tree(int argc, char *argv[]) if (error != NULL) goto done; } else { - error = got_object_resolve_id_str(&commit_id, repo, - commit_id_str); + error = got_repo_match_object_id_prefix(&commit_id, + commit_id_str, repo); if (error != NULL) goto done; } @@ -2034,7 +2034,7 @@ add_ref(struct got_repository *repo, const char *refna struct got_object_id *id; struct got_reference *ref = NULL; - err = got_object_resolve_id_str(&id, repo, target); + err = got_repo_match_object_id_prefix(&id, target, repo); if (err) { struct got_reference *target_ref; @@ -2996,7 +2996,7 @@ cmd_cherrypick(int argc, char *argv[]) if (error) goto done; - error = got_object_resolve_id_str(&commit_id, repo, argv[0]); + error = got_repo_match_object_id_prefix(&commit_id, argv[0], repo); if (error != NULL) { struct got_reference *ref; if (error->code != GOT_ERR_BAD_OBJ_ID_STR) @@ -3105,7 +3105,7 @@ cmd_backout(int argc, char *argv[]) if (error) goto done; - error = got_object_resolve_id_str(&commit_id, repo, argv[0]); + error = got_repo_match_object_id_prefix(&commit_id, argv[0], repo); if (error != NULL) { struct got_reference *ref; if (error->code != GOT_ERR_BAD_OBJ_ID_STR) blob - c05ac929d21262fe260f6843312f25459fc4a06d blob + 83b7c99d663d7a35621aa740a8b3f4da13281612 --- include/got_error.h +++ include/got_error.h @@ -28,7 +28,7 @@ #define GOT_ERR_BAD_OBJ_HDR 10 #define GOT_ERR_OBJ_TYPE 11 #define GOT_ERR_BAD_OBJ_DATA 12 -/* 13 is currently free for re-use */ +#define GOT_ERR_AMBIGUOUS_ID 13 #define GOT_ERR_BAD_PACKIDX 14 #define GOT_ERR_PACKIDX_CSUM 15 #define GOT_ERR_BAD_PACKFILE 16 @@ -115,7 +115,7 @@ static const struct got_error { { GOT_ERR_BAD_OBJ_HDR, "bad object header" }, { GOT_ERR_OBJ_TYPE, "wrong type of object" }, { GOT_ERR_BAD_OBJ_DATA, "bad object data" }, - { 13, "unused error code" }, + { GOT_ERR_AMBIGUOUS_ID, "ambiguous object ID" }, { GOT_ERR_BAD_PACKIDX, "bad pack index file" }, { GOT_ERR_PACKIDX_CSUM, "pack index file checksum error" }, { GOT_ERR_BAD_PACKFILE, "bad pack file" }, blob - 0b61b49e3ed0680170a01636840b554aac156059 blob + 69c2e095c3af4282d19b75475fcff80fe12aeef5 --- include/got_repository.h +++ include/got_repository.h @@ -57,3 +57,7 @@ const struct got_error *got_repo_map_path(char **, str /* Create a new repository in an empty directory at a specified path. */ const struct got_error *got_repo_init(const char *); + +/* Attempt to find a unique object ID for a given ID string prefix. */ +const struct got_error *got_repo_match_object_id_prefix(struct got_object_id **, + const char *, struct got_repository *); blob - 449f4a66c5e45ada327bc786016b0b7788668394 blob + 241a9411ba3a191b9ceafd49e0fec3cd038b2049 --- lib/diff.c +++ lib/diff.c @@ -24,8 +24,8 @@ #include #include -#include "got_repository.h" #include "got_object.h" +#include "got_repository.h" #include "got_error.h" #include "got_diff.h" #include "got_opentemp.h" blob - 34beeb2b7345dac2a513a297aab77a4a94811563 blob + 7af741d237c7cd84aca6789c32dc4cdf3bb5237a --- lib/got_lib_pack.h +++ lib/got_lib_pack.h @@ -161,6 +161,10 @@ const struct got_error *got_packidx_open(struct got_pa const char *, int); const struct got_error* got_packidx_close(struct got_packidx *); int got_packidx_get_object_idx(struct got_packidx *, struct got_object_id *); +typedef const struct got_error *(*got_packidx_for_each_id_cb)(void *, + struct got_object_id *); +const struct got_error *got_packidx_for_each_id(struct got_packidx *, + got_packidx_for_each_id_cb cb, void *); const struct got_error *got_packfile_open_object(struct got_object **, struct got_pack *, struct got_packidx *, int, struct got_object_id *); blob - 691ab915f783045757051241faacca38bd22898f blob + 60a273ea713af45d42943ac3274ba6081c775576 --- lib/object.c +++ lib/object.c @@ -1596,4 +1596,3 @@ done: } return err; } - blob - 9f38ab305851d89c4ee68b2ae45ad8935d7a6d87 blob + 269e6fa733cf1a2955a5e341a8d46504352492c9 --- lib/pack.c +++ lib/pack.c @@ -444,6 +444,27 @@ got_packidx_get_object_idx(struct got_packidx *packidx } const struct got_error * +got_packidx_for_each_id(struct got_packidx *packidx, + got_packidx_for_each_id_cb cb, void *cb_arg) +{ + const struct got_error *err = NULL; + uint32_t nobj = betoh32(packidx->hdr.fanout_table[0xff]); + struct got_packidx_object_id *oid; + struct got_object_id id; + int i; + + for (i = 0; i < nobj; i++) { + oid = &packidx->hdr.sorted_ids[i]; + memcpy(&id, oid->sha1, SHA1_DIGEST_LENGTH); + err = cb(cb_arg, &id); + if (err) + break; + } + + return err; +} + +const struct got_error * got_pack_stop_privsep_child(struct got_pack *pack) { const struct got_error *err = NULL; blob - 34d0da428d84d9053008e21e8223ac41ed646d33 blob + f4cf79809502ced018e0ec153ae2240982059eb5 --- lib/repository.c +++ lib/repository.c @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -48,6 +49,7 @@ #include "got_lib_pack.h" #include "got_lib_privsep.h" #include "got_lib_worktree.h" +#include "got_lib_sha1.h" #include "got_lib_object_cache.h" #include "got_lib_repository.h" @@ -874,4 +876,220 @@ got_repo_init(const char *repo_path) return err; return NULL; +} + +struct match_packidx_id_args { + const char *id_str_prefix; + struct got_object_id *unique_id; +}; + +static const struct got_error * +match_packidx_id(void *arg, struct got_object_id *id) +{ + const struct got_error *err; + struct match_packidx_id_args *a = arg; + char *id_str; + + err = got_object_id_str(&id_str, id); + if (err) + return err; + + if (strncmp(a->id_str_prefix, id_str, strlen(a->id_str_prefix)) == 0) { + if (a->unique_id == NULL) { + a->unique_id = got_object_id_dup(id); + if (a->unique_id == NULL) + err = got_error_from_errno("got_object_id_dup"); + } + } + + free(id_str); + return err; +} + +static const struct got_error * +match_packed_object_id_prefix(struct got_object_id **unique_id, + struct got_repository *repo, const char *id_str_prefix) +{ + const struct got_error *err = NULL; + struct match_packidx_id_args args; + char *path_packdir; + DIR *packdir; + struct dirent *dent; + char *path_packidx; + + *unique_id = NULL; + + path_packdir = got_repo_get_path_objects_pack(repo); + if (path_packdir == NULL) + return got_error_from_errno("got_repo_get_path_objects_pack"); + + packdir = opendir(path_packdir); + if (packdir == NULL) { + err = got_error_from_errno2("opendir", path_packdir); + goto done; + } + + while ((dent = readdir(packdir)) != NULL) { + struct got_packidx *packidx; + const struct got_error *cb_err; + + if (!is_packidx_filename(dent->d_name, dent->d_namlen)) + continue; + + if (asprintf(&path_packidx, "%s/%s", path_packdir, + dent->d_name) == -1) { + err = got_error_from_errno("asprintf"); + goto done; + } + + err = got_packidx_open(&packidx, path_packidx, 0); + free(path_packidx); + if (err) + goto done; + + args.id_str_prefix = id_str_prefix; + args.unique_id = NULL; + cb_err = got_packidx_for_each_id(packidx, match_packidx_id, + &args); + err = got_packidx_close(packidx); + if (err) + break; + if (cb_err) { + err = cb_err; + break; + } + + if (args.unique_id) { + if (*unique_id == NULL) + *unique_id = args.unique_id; + else { + err = got_error(GOT_ERR_AMBIGUOUS_ID); + break; + } + } + } +done: + free(path_packdir); + if (packdir && closedir(packdir) != 0 && err == NULL) + err = got_error_from_errno("closedir"); + if (err) { + free(*unique_id); + *unique_id = NULL; + } + return err; +} + +static const struct got_error * +match_object_id(struct got_object_id **unique_id, const char *path_objects, + const char *object_dir, const char *id_str_prefix, + struct got_repository *repo) +{ + const struct got_error *err = NULL; + char *path; + DIR *dir = NULL; + struct dirent *dent; + struct got_object_id id; + int i; + + for (i = 0; i < strlen(id_str_prefix); i++) { + if (isxdigit((unsigned char)id_str_prefix[i])) + continue; + return got_error(GOT_ERR_BAD_OBJ_ID_STR); + } + + /* Search pack index. */ + err = match_packed_object_id_prefix(unique_id, repo, id_str_prefix); + if (err) + return err; + + /* Search on-disk directories. */ + if (asprintf(&path, "%s/%s", path_objects, object_dir) == -1) { + err = got_error_from_errno("asprintf"); + goto done; + } + + dir = opendir(path); + if (dir == NULL) { + err = got_error_from_errno2("opendir", path); + goto done; + } + while ((dent = readdir(dir)) != NULL) { + char *id_str; + if (strcmp(dent->d_name, ".") == 0 || + strcmp(dent->d_name, "..") == 0) + continue; + + if (asprintf(&id_str, "%s%s", object_dir, dent->d_name) == -1) { + err = got_error_from_errno("asprintf"); + goto done; + } + + if (!got_parse_sha1_digest(id.sha1, id_str)) + continue; + + if (strncmp(id_str_prefix, id_str, + strlen(id_str_prefix)) != 0) { + free(id_str); + continue; + } + + if (*unique_id == NULL) { + *unique_id = got_object_id_dup(&id); + if (*unique_id == NULL) { + err = got_error_from_errno("got_object_id_dup"); + free(id_str); + goto done; + } + } else { + err = got_error(GOT_ERR_AMBIGUOUS_ID); + free(id_str); + goto done; + } + } + + if (err == NULL && *unique_id == NULL) + err = got_error(GOT_ERR_NO_OBJ); +done: + if (err) { + free(*unique_id); + *unique_id = NULL; + } + if (dir && closedir(dir) != 0 && err == NULL) + err = got_error_from_errno("closedir"); + free(path); + return err; } + +const struct got_error * +got_repo_match_object_id_prefix(struct got_object_id **id, const char *id_str_prefix, + struct got_repository *repo) +{ + const struct got_error *err = NULL; + char *path_objects = got_repo_get_path_objects(repo); + char *object_dir = NULL; + size_t len; + + len = strlen(id_str_prefix); + if (len >= 2) { + object_dir = strndup(id_str_prefix, 2); + if (object_dir == NULL) + return got_error_from_errno("strdup"); + err = match_object_id(id, path_objects, object_dir, + id_str_prefix, repo); + } else if (len == 1) { + int i; + for (i = 0; i < 0xf; i++) { + if (asprintf(&object_dir, "%s%.1x", id_str_prefix, i) + == -1) + return got_error_from_errno("asprintf"); + err = match_object_id(id, path_objects, object_dir, + id_str_prefix, repo); + if (err) + break; + } + } else + return got_error(GOT_ERR_BAD_OBJ_ID_STR); + + free(object_dir); + return err; +} blob - fc0bb7562d2d4c401739ecf6172c5813f1448b59 blob + 79ae802838b0dee98d1c9dcf060003faa4c58629 --- tog/tog.c +++ tog/tog.c @@ -2221,8 +2221,8 @@ cmd_log(int argc, char *argv[]) got_worktree_get_head_ref_name(worktree) : GOT_REF_HEAD, repo); else - error = got_object_resolve_id_str(&start_id, repo, - start_commit); + error = got_repo_match_object_id_prefix(&start_id, + start_commit, repo); if (error != NULL) goto done; @@ -2830,11 +2830,11 @@ cmd_diff(int argc, char *argv[]) if (error) goto done; - error = got_object_resolve_id_str(&id1, repo, id_str1); + error = got_repo_match_object_id_prefix(&id1, id_str1, repo); if (error) goto done; - error = got_object_resolve_id_str(&id2, repo, id_str2); + error = got_repo_match_object_id_prefix(&id2, id_str2, repo); if (error) goto done; @@ -3684,8 +3684,8 @@ cmd_blame(int argc, char *argv[]) error = got_ref_resolve(&commit_id, repo, head_ref); got_ref_close(head_ref); } else { - error = got_object_resolve_id_str(&commit_id, repo, - commit_id_str); + error = got_repo_match_object_id_prefix(&commit_id, + commit_id_str, repo); } if (error != NULL) goto done; @@ -4411,8 +4411,8 @@ cmd_tree(int argc, char *argv[]) if (commit_id_arg == NULL) error = get_head_commit_id(&commit_id, GOT_REF_HEAD, repo); else - error = got_object_resolve_id_str(&commit_id, repo, - commit_id_arg); + error = got_repo_match_object_id_prefix(&commit_id, + commit_id_arg, repo); if (error != NULL) goto done;