scalar: implement the `delete` command

Delete an enlistment by first unregistering the repository and then deleting the enlistment directory (usually the directory containing the worktree `src/` directory). On Windows, if the current directory is inside the enlistment's directory, change to the parent of the enlistment directory, to allow us to delete the enlistment (directories used by processes e.g. as current working directories cannot be deleted on Windows). Co-authored-by: Victoria Dye <vdye@github.com> Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Matthew John Cheetham committed Dec 3, 2021 at 13:34 UTC d85ada7cbdc7a1ff6b98891cec87e54ea4a303ae
3 files changed +80
contrib/scalar/scalar.c
+63
@@ -8,6 +8,8 @@
8 #include "config.h"
9 #include "run-command.h"
10 #include "refs.h"
11 +#include "dir.h"
12 +#include "packfile.h"
13
14 /*
15 * Remove the deepest subdirectory in the provided path string. Path must not
@@ -328,6 +330,33 @@ static char *remote_default_branch(const char *url)
330 return NULL;
331 }
332
333 +static int delete_enlistment(struct strbuf *enlistment)
334 +{
335 +#ifdef WIN32
336 + struct strbuf parent = STRBUF_INIT;
337 +#endif
338 +
339 + if (unregister_dir())
340 + die(_("failed to unregister repository"));
341 +
342 +#ifdef WIN32
343 + /*
344 + * Change the current directory to one outside of the enlistment so
345 + * that we may delete everything underneath it.
346 + */
347 + strbuf_addbuf(&parent, enlistment);
348 + strbuf_parent_directory(&parent);
349 + if (chdir(parent.buf) < 0)
350 + die_errno(_("could not switch to '%s'"), parent.buf);
351 + strbuf_release(&parent);
352 +#endif
353 +
354 + if (remove_dir_recursively(enlistment, 0))
355 + die(_("failed to delete enlistment directory"));
356 +
357 + return 0;
358 +}
359 +
360 static int cmd_clone(int argc, const char **argv)
361 {
362 const char *branch = NULL;
@@ -688,6 +717,39 @@ static int cmd_unregister(int argc, const char **argv)
717 return unregister_dir();
718 }
719
720 +static int cmd_delete(int argc, const char **argv)
721 +{
722 + char *cwd = xgetcwd();
723 + struct option options[] = {
724 + OPT_END(),
725 + };
726 + const char * const usage[] = {
727 + N_("scalar delete <enlistment>"),
728 + NULL
729 + };
730 + struct strbuf enlistment = STRBUF_INIT;
731 + int res = 0;
732 +
733 + argc = parse_options(argc, argv, NULL, options,
734 + usage, 0);
735 +
736 + if (argc != 1)
737 + usage_with_options(usage, options);
738 +
739 + setup_enlistment_directory(argc, argv, usage, options, &enlistment);
740 +
741 + if (dir_inside_of(cwd, enlistment.buf) >= 0)
742 + res = error(_("refusing to delete current working directory"));
743 + else {
744 + close_object_store(the_repository->objects);
745 + res = delete_enlistment(&enlistment);
746 + }
747 + strbuf_release(&enlistment);
748 + free(cwd);
749 +
750 + return res;
751 +}
752 +
753 static struct {
754 const char *name;
755 int (*fn)(int, const char **);
@@ -698,6 +760,7 @@ static struct {
760 { "unregister", cmd_unregister },
761 { "run", cmd_run },
762 { "reconfigure", cmd_reconfigure },
763 + { "delete", cmd_delete },
764 { NULL, NULL},
765 };
766
contrib/scalar/scalar.txt
+8
@@ -14,6 +14,7 @@ scalar register [<enlistment>]
14 scalar unregister [<enlistment>]
15 scalar run ( all | config | commit-graph | fetch | loose-objects | pack-files ) [<enlistment>]
16 scalar reconfigure [ --all | <enlistment> ]
17 +scalar delete <enlistment>
18
19 DESCRIPTION
20 -----------
@@ -128,6 +129,13 @@ reconfigure the enlistment.
129 With the `--all` option, all enlistments currently registered with Scalar
130 will be reconfigured. Use this option after each Scalar upgrade.
131
132 +Delete
133 +~~~~~~
134 +
135 +delete <enlistment>::
136 + This subcommand lets you delete an existing Scalar enlistment from your
137 + local file system, unregistering the repository.
138 +
139 SEE ALSO
140 --------
141 linkgit:git-clone[1], linkgit:git-maintenance[1].
contrib/scalar/t/t9099-scalar.sh
+9
@@ -76,4 +76,13 @@ test_expect_success 'scalar reconfigure' '
76 test true = "$(git -C one/src config core.preloadIndex)"
77 '
78
79 +test_expect_success 'scalar delete without enlistment shows a usage' '
80 + test_expect_code 129 scalar delete
81 +'
82 +
83 +test_expect_success 'scalar delete with enlistment' '
84 + scalar delete cloned &&
85 + test_path_is_missing cloned
86 +'
87 +
88 test_done