From: Tracey Emery Subject: Re: got add recursion To: Stefan Sperling Cc: gameoftrees@openbsd.org Date: Fri, 22 Nov 2019 08:30:02 -0700 Ok, I think I addressed everything. New diff below to reflect your changes, added the directory test, and cleaned up a couple of errant tabs in the revert test. Anything else I missed? Ok? Thanks, T -- Tracey Emery diff refs/heads/master refs/heads/recurse blob - 9320a0971ee4f04fb9c3ff5cda31e6ceae91d2ea blob + 9c0c3772a7c0a876c6e1fc5ae868fe928503cb90 --- got/got.1 +++ got/got.1 @@ -619,9 +619,22 @@ If a tag must be deleted, the command may be used to delete a tag's reference. This should only be done if the tag has not already been copied to another repository. -.It Cm add Ar file-path ... +.It Cm add Oo Fl R Oc Ar path ... Schedule unversioned files in a work tree for addition to the repository in the next commit. +.Pp +The options for +.Cm got add +are as follows: +.Bl -tag -width Ds +.It Fl R +Permit recursion into directories. +If this option is not specified, +.Cm got add +will refuse to run if a specified +.Ar path +is a directory. +.El .It Cm remove Ar file-path ... Remove versioned files from a work tree and schedule them for deletion from the repository in the next commit. blob - 3b8935895b310dbf4148cef5f6f4b5722e0369ba blob + 776fb4c2ed06b1f5eaa6573a02ff26a086f3701b --- got/got.c +++ got/got.c @@ -4086,6 +4086,15 @@ usage_add(void) } static const struct got_error * +add_progress(void *arg, unsigned char status, const char *path) +{ + while (path[0] == '/') + path++; + printf("%c %s\n", status, path); + return NULL; +} + +static const struct got_error * cmd_add(int argc, char *argv[]) { const struct got_error *error = NULL; @@ -4094,12 +4103,15 @@ cmd_add(int argc, char *argv[]) char *cwd = NULL; struct got_pathlist_head paths; struct got_pathlist_entry *pe; - int ch; + int ch, can_recurse = 0; TAILQ_INIT(&paths); - while ((ch = getopt(argc, argv, "")) != -1) { + while ((ch = getopt(argc, argv, "R")) != -1) { switch (ch) { + case 'R': + can_recurse = 1; + break; default: usage_add(); /* NOTREACHED */ @@ -4141,7 +4153,35 @@ cmd_add(int argc, char *argv[]) if (error) goto done; - error = got_worktree_schedule_add(worktree, &paths, print_status, + if (!can_recurse) { + char *ondisk_path; + struct stat sb; + TAILQ_FOREACH(pe, &paths, entry) { + if (asprintf(&ondisk_path, "%s/%s", + got_worktree_get_root_path(worktree), + pe->path) == -1) { + error = got_error_from_errno("asprintf"); + goto done; + } + if (lstat(ondisk_path, &sb) == -1) { + if (errno == ENOENT) { + free(ondisk_path); + continue; + } + error = got_error_from_errno2("lstat", + ondisk_path); + free(ondisk_path); + goto done; + } + free(ondisk_path); + if (S_ISDIR(sb.st_mode)) { + error = got_error_msg(GOT_ERR_BAD_PATH, + "adding directories requires -R option"); + goto done; + } + } + } + error = got_worktree_schedule_add(worktree, &paths, add_progress, NULL, repo); done: if (repo) blob - 336553780903efcf81551b9db8c4a76a0ab2f148 blob + a18fc5a59d6c2c165d6f449c5accb262eb450485 --- include/got_worktree.h +++ include/got_worktree.h @@ -158,7 +158,7 @@ const struct got_error *got_worktree_resolve_path(char /* Schedule files at on-disk paths for addition in the next commit. */ const struct got_error *got_worktree_schedule_add(struct got_worktree *, - struct got_pathlist_head *, got_worktree_status_cb, void *, + struct got_pathlist_head *, got_worktree_checkout_cb, void *, struct got_repository *); /* blob - e841520c6fbc877de575ee04d69018206ea0391f blob + 69f0ca5bcbdcdd0f823c7d47d32883b26350c9ad --- lib/worktree.c +++ lib/worktree.c @@ -2563,7 +2563,7 @@ add_ignores(struct got_pathlist_head *ignores, const c err = read_ignores(ignores, path, ignoresfile); if (ignoresfile && fclose(ignoresfile) == EOF && err == NULL) - err = got_error_from_errno2("flose", path); + err = got_error_from_errno2("fclose", path); free(ignorespath); return err; } @@ -2771,19 +2771,30 @@ done: return err; } +struct schedule_addition_args { + struct got_worktree *worktree; + struct got_fileindex *fileindex; + const char *ondisk_path; + got_worktree_checkout_cb progress_cb; + void *progress_arg; + struct got_repository *repo; +}; + static const struct got_error * -schedule_addition(const char *ondisk_path, struct got_fileindex *fileindex, - const char *relpath, got_worktree_status_cb status_cb, void *status_arg, - struct got_repository *repo) +schedule_addition(void *arg, unsigned char status, unsigned char staged_status, + const char *relpath, struct got_object_id *blob_id, + struct got_object_id *staged_blob_id, struct got_object_id *commit_id) { + struct schedule_addition_args *a = arg; const struct got_error *err = NULL; struct got_fileindex_entry *ie; - unsigned char status; struct stat sb; + char *path = NULL; - ie = got_fileindex_entry_get(fileindex, relpath, strlen(relpath)); + ie = got_fileindex_entry_get(a->fileindex, relpath, strlen(relpath)); if (ie) { - err = get_file_status(&status, &sb, ie, ondisk_path, repo); + err = get_file_status(&status, &sb, ie, a->ondisk_path, + a->repo); if (err) return err; /* Re-adding an existing entry is a no-op. */ @@ -2792,29 +2803,51 @@ schedule_addition(const char *ondisk_path, struct got_ return got_error_path(relpath, GOT_ERR_FILE_STATUS); } - err = got_fileindex_entry_alloc(&ie, ondisk_path, relpath, NULL, NULL); + if (status == GOT_STATUS_UNVERSIONED) { + if (lstat(a->ondisk_path, &sb) != 0) { + err = got_error_from_errno2("lstat", a->ondisk_path); + return err; + } + if (S_ISDIR(sb.st_mode)) { + if (asprintf(&path, "%s/%s", + got_worktree_get_root_path(a->worktree), + relpath) == -1) { + err = got_error_from_errno("asprintf"); + return err; + } + } else + path = strdup(a->ondisk_path); + } + + err = got_fileindex_entry_alloc(&ie, path, relpath, NULL, NULL); if (err) - return err; + goto done; - err = got_fileindex_entry_add(fileindex, ie); + err = got_fileindex_entry_add(a->fileindex, ie); if (err) { got_fileindex_entry_free(ie); - return err; + goto done; } - return report_file_status(ie, ondisk_path, status_cb, status_arg, repo); + free(path); + return (*a->progress_cb)(a->progress_arg, + GOT_STATUS_ADD, relpath); +done: + free(path); + return err; } const struct got_error * got_worktree_schedule_add(struct got_worktree *worktree, struct got_pathlist_head *paths, - got_worktree_status_cb status_cb, void *status_arg, + got_worktree_checkout_cb progress_cb, void *progress_arg, struct got_repository *repo) { struct got_fileindex *fileindex = NULL; char *fileindex_path = NULL; const struct got_error *err = NULL, *sync_err, *unlockerr; struct got_pathlist_entry *pe; + struct schedule_addition_args saa; err = lock_worktree(worktree, LOCK_EX); if (err) @@ -2824,13 +2857,20 @@ got_worktree_schedule_add(struct got_worktree *worktre if (err) goto done; + saa.worktree = worktree; + saa.fileindex = fileindex; + saa.progress_cb = progress_cb; + saa.progress_arg = progress_arg; + saa.repo = repo; + TAILQ_FOREACH(pe, paths, entry) { char *ondisk_path; if (asprintf(&ondisk_path, "%s/%s", worktree->root_path, pe->path) == -1) return got_error_from_errno("asprintf"); - err = schedule_addition(ondisk_path, fileindex, pe->path, - status_cb, status_arg, repo); + saa.ondisk_path = ondisk_path; + err = worktree_status(worktree, pe->path, fileindex, repo, + schedule_addition, &saa, NULL, NULL); free(ondisk_path); if (err) break; blob - 0634eee1bd0a59644a8f17047cc75df2160d3023 (mode 755) blob + 9260016060fa594ef14a31a90e815737bb487ca1 (mode 744) --- regress/cmdline/add.sh +++ regress/cmdline/add.sh @@ -151,8 +151,71 @@ function test_add_deleted { test_done "$testroot" "$ret" } +function test_add_directory { + local testroot=`test_init add_directory` + + got checkout $testroot/repo $testroot/wt > /dev/null + ret="$?" + if [ "$ret" != "0" ]; then + test_done "$testroot" "$ret" + return 1 + fi + + (cd $testroot/wt && got add . > $testroot/stdout 2> $testroot/stderr) + ret="$?" + if [ "$ret" == "0" ]; then + echo "got add command succeeded unexpectedly" >&2 + test_done "$testroot" "1" + return 1 + fi + echo "got: adding directories requires -R option" \ + > $testroot/stderr.expected + cmp -s $testroot/stderr.expected $testroot/stderr + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stderr.expected $testroot/stderr + test_done "$testroot" "$ret" + return 1 + fi + + echo -n > $testroot/stdout.expected + cmp -s $testroot/stdout.expected $testroot/stdout + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stdout.expected $testroot/stdout + test_done "$testroot" "$ret" + return 1 + fi + + (touch $testroot/wt/epsilon/zeta1 && touch $testroot/wt/epsilon/zeta2) + + (cd $testroot/wt && got add -R . > $testroot/stdout) + + echo 'A epsilon/zeta1' > $testroot/stdout.expected + echo 'A epsilon/zeta2' >> $testroot/stdout.expected + + cmp -s $testroot/stdout.expected $testroot/stdout + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stdout.expected $testroot/stdout + test_done "$testroot" "$ret" + return 1 + fi + + echo "zeta" > $testroot/content.expected + cat $testroot/wt/epsilon/zeta > $testroot/content + + cmp -s $testroot/content.expected $testroot/content + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/content.expected $testroot/content + fi + test_done "$testroot" "$ret" +} + run_test test_add_basic run_test test_double_add run_test test_add_multiple run_test test_add_file_in_new_subdir run_test test_add_deleted +run_test test_add_directory blob - 03dde3689850691152912cff6e55604338fb960b (mode 755) blob + 6e6d96b664048db5f46c4c4ac8afba5899c30910 (mode 744) --- regress/cmdline/revert.sh +++ regress/cmdline/revert.sh @@ -332,7 +332,7 @@ function test_revert_directory_unknown { echo "modified alpha" > $testroot/wt/alpha echo "new untracked file" > $testroot/wt/epsilon/new_file - echo "modified epsilon/zeta" > $testroot/wt/epsilon/zeta + echo "modified epsilon/zeta" > $testroot/wt/epsilon/zeta (cd $testroot/wt && got revert -R . > $testroot/stdout) @@ -357,7 +357,7 @@ function test_revert_directory_unknown { test_done "$testroot" "$ret" return 1 fi - + echo "zeta" > $testroot/content.expected cat $testroot/wt/epsilon/zeta > $testroot/content