commit 6ced41767b1ce3cd525b304d3adf2197b57bfaf6 from: Stefan Sperling date: Fri Jul 12 12:20:33 2019 UTC move a chunk of file checkout code into a separate helper function commit - e642f803bde24b919bd4fe2ba66956b4b8173c32 commit + 6ced41767b1ce3cd525b304d3adf2197b57bfaf6 blob - 323bf4a0ab4e5880df4f20a77702593068ee18d3 blob + a0eaf352d837f1d8fc1afa69082b04e1a970c2fb --- lib/worktree.c +++ lib/worktree.c @@ -1530,7 +1530,110 @@ done: free(new_fileindex_path); return err; } + +static const struct got_error * +find_tree_entry_for_checkout(int *entry_type, char **tree_relpath, + struct got_object_id **tree_id, const char *wt_relpath, + struct got_worktree *worktree, struct got_repository *repo) +{ + const struct got_error *err = NULL; + struct got_object_id *id = NULL; + char *in_repo_path = NULL; + int is_root_wt = got_path_is_root_dir(worktree->path_prefix); + + *entry_type = GOT_OBJ_TYPE_ANY; + *tree_relpath = NULL; + *tree_id = NULL; + + if (wt_relpath[0] == '\0') { + /* Check out all files within the work tree. */ + *entry_type = GOT_OBJ_TYPE_TREE; + *tree_relpath = strdup(""); + if (*tree_relpath == NULL) { + err = got_error_from_errno("strdup"); + goto done; + } + err = got_object_id_by_path(tree_id, repo, + worktree->base_commit_id, worktree->path_prefix); + if (err) + goto done; + return NULL; + } + + /* Check out a subset of files in the work tree. */ + + if (asprintf(&in_repo_path, "%s%s%s", worktree->path_prefix, + is_root_wt ? "" : "/", wt_relpath) == -1) { + err = got_error_from_errno("asprintf"); + goto done; + } + + err = got_object_id_by_path(&id, repo, worktree->base_commit_id, + in_repo_path); + if (err) + goto done; + + free(in_repo_path); + in_repo_path = NULL; + + err = got_object_get_type(entry_type, repo, id); + if (err) + goto done; + if (*entry_type == GOT_OBJ_TYPE_BLOB) { + /* Check out a single file. */ + if (strchr(wt_relpath, '/') == NULL) { + /* Check out a single file in work tree's root dir. */ + in_repo_path = strdup(worktree->path_prefix); + if (in_repo_path == NULL) { + err = got_error_from_errno("strdup"); + goto done; + } + *tree_relpath = strdup(""); + if (*tree_relpath == NULL) { + err = got_error_from_errno("strdup"); + goto done; + } + } else { + /* Check out a single file in a subdirectory. */ + err = got_path_dirname(tree_relpath, wt_relpath); + if (err) + return err; + if (asprintf(&in_repo_path, "%s%s%s", + worktree->path_prefix, is_root_wt ? "" : "/", + *tree_relpath) == -1) { + err = got_error_from_errno("asprintf"); + goto done; + } + } + err = got_object_id_by_path(tree_id, repo, + worktree->base_commit_id, in_repo_path); + } else { + /* Check out all files within a subdirectory. */ + *tree_id = got_object_id_dup(id); + if (*tree_id == NULL) { + err = got_error_from_errno("got_object_id_dup"); + goto done; + } + *tree_relpath = strdup(wt_relpath); + if (*tree_relpath == NULL) { + err = got_error_from_errno("strdup"); + goto done; + } + } +done: + free(id); + free(in_repo_path); + if (err) { + *entry_type = GOT_OBJ_TYPE_ANY; + free(*tree_relpath); + *tree_relpath = NULL; + free(*tree_id); + *tree_id = NULL; + } + return err; +} + const struct got_error * got_worktree_checkout_files(struct got_worktree *worktree, const char *path, struct got_repository *repo, got_worktree_checkout_cb progress_cb, @@ -1546,11 +1649,25 @@ got_worktree_checkout_files(struct got_worktree *workt struct diff_cb_arg arg; char *relpath = NULL, *entry_name = NULL; struct bump_base_commit_id_arg bbc_arg; + int entry_type; err = lock_worktree(worktree, LOCK_EX); if (err) return err; + err = find_tree_entry_for_checkout(&entry_type, &relpath, &tree_id, + path, worktree, repo); + if (err) + goto done; + + if (entry_type == GOT_OBJ_TYPE_BLOB) { + entry_name = basename(path); + if (entry_name == NULL) { + err = got_error_from_errno2("basename", path); + goto done; + } + } + /* * Read the file index. * Checking out files is supposed to be an idempotent operation. @@ -1568,78 +1685,6 @@ got_worktree_checkout_files(struct got_worktree *workt worktree->base_commit_id); if (err) goto done; - - if (path[0]) { - char *tree_path; - int obj_type; - if (asprintf(&tree_path, "%s%s%s", worktree->path_prefix, - got_path_is_root_dir(worktree->path_prefix) ? "" : "/", - path) == -1) { - err = got_error_from_errno("asprintf"); - goto done; - } - err = got_object_id_by_path(&tree_id, repo, - worktree->base_commit_id, tree_path); - free(tree_path); - if (err) - goto done; - err = got_object_get_type(&obj_type, repo, tree_id); - if (err) - goto done; - if (obj_type == GOT_OBJ_TYPE_BLOB) { - /* Split provided path into parent dir + entry name. */ - if (strchr(path, '/') == NULL) { - relpath = strdup(""); - if (relpath == NULL) { - err = got_error_from_errno("strdup"); - goto done; - } - tree_path = strdup(worktree->path_prefix); - if (tree_path == NULL) { - err = got_error_from_errno("strdup"); - goto done; - } - } else { - err = got_path_dirname(&relpath, path); - if (err) - goto done; - if (asprintf(&tree_path, "%s%s%s", - worktree->path_prefix, - got_path_is_root_dir( - worktree->path_prefix) ? "" : "/", - relpath) == -1) { - err = got_error_from_errno("asprintf"); - goto done; - } - } - err = got_object_id_by_path(&tree_id, repo, - worktree->base_commit_id, tree_path); - free(tree_path); - if (err) - goto done; - entry_name = basename(path); - if (entry_name == NULL) { - err = got_error_from_errno2("basename", path); - goto done; - } - } else { - relpath = strdup(path); - if (relpath == NULL) { - err = got_error_from_errno("strdup"); - goto done; - } - } - } else { - relpath = strdup(""); - if (relpath == NULL) { - err = got_error_from_errno("strdup"); - goto done; - } - err = got_object_id_by_path(&tree_id, repo, - worktree->base_commit_id, worktree->path_prefix); - if (err) - goto done; - } err = got_object_open_as_tree(&tree, repo, tree_id); if (err)