Skip to content

Commit

Permalink
Merge pull request #402 from vdye/bugfix/scalar-register-directory
Browse files Browse the repository at this point in the history
Handle Scalar enlistments without `src` subdirectory
  • Loading branch information
vdye authored and derrickstolee committed Aug 4, 2021
2 parents 77f3f93 + ec9aa83 commit e720ed3
Show file tree
Hide file tree
Showing 2 changed files with 168 additions and 73 deletions.
188 changes: 115 additions & 73 deletions contrib/scalar/scalar.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,55 +19,91 @@ static int is_unattended(void) {
return git_env_bool("Scalar_UNATTENDED", 0);
}

/*
* Remove the deepest subdirectory in the provided path string. Path must not
* include a trailing path separator. Returns 1 if parent directory found,
* otherwise 0.
*/
static int strbuf_parentdir(struct strbuf *buf)
{
size_t len = buf->len;
size_t offset = offset_1st_component(buf->buf);
char *path_sep = find_last_dir_sep(buf->buf + offset);
strbuf_setlen(buf, path_sep ? path_sep - buf->buf : offset);

return buf->len < len;
}

static void setup_enlistment_directory(int argc, const char **argv,
const char * const *usagestr,
const struct option *options)
const struct option *options,
struct strbuf *enlistment_root)
{
struct strbuf path = STRBUF_INIT;
char *root;
int enlistment_found = 0;

if (startup_info->have_repository)
BUG("gitdir already set up?!?");

if (argc > 1)
usage_with_options(usagestr, options);

/* find the worktree, determine its corresponding root */
if (argc == 1) {
char *src = xstrfmt("%s/src", argv[0]);
const char *dir = is_directory(src) ? src : argv[0];
strbuf_add_absolute_path(&path, argv[0]);
} else if (strbuf_getcwd(&path) < 0) {
die(_("need a working directory"));
}

if (chdir(dir) < 0)
die_errno(_("could not switch to '%s'"), dir);
strbuf_trim_trailing_dir_sep(&path);
do {
const size_t len = path.len;

free(src);
} else {
/* find the worktree, and ensure that it is named `src` */
struct strbuf path = STRBUF_INIT;
/* check if currently in enlistment root with src/ workdir */
strbuf_addstr(&path, "/src/.git");
if (is_git_directory(path.buf)) {
strbuf_strip_suffix(&path, "/.git");

if (strbuf_getcwd(&path) < 0)
die(_("need a working directory"));

for (;;) {
size_t len = path.len;

strbuf_addstr(&path, "/src/.git");
if (is_git_directory(path.buf)) {
strbuf_setlen(&path, len);
strbuf_addstr(&path, "/src");
if (chdir(path.buf) < 0)
die_errno(_("could not switch to '%s'"),
path.buf);
strbuf_release(&path);
break;
}
if (enlistment_root)
strbuf_add(enlistment_root, path.buf, len);

while (len > 0 && !is_dir_sep(path.buf[--len]))
; /* keep looking for parent directory */
enlistment_found = 1;
break;
}

if (!len)
die(_("could not find enlistment root"));
/* reset to original path */
strbuf_setlen(&path, len);

/* check if currently in workdir */
strbuf_addstr(&path, "/.git");
if (is_git_directory(path.buf)) {
strbuf_setlen(&path, len);

if (enlistment_root) {
/*
* If the worktree's directory's name is `src`, the enlistment is the
* parent directory, otherwise it is identical to the worktree.
*/
root = strip_path_suffix(path.buf, "src");
strbuf_addstr(enlistment_root, root ? root : path.buf);
free(root);
}

enlistment_found = 1;
break;
}
}

strbuf_setlen(&path, len);
} while (strbuf_parentdir(&path));

if (!enlistment_found)
die(_("could not find enlistment root"));

if (chdir(path.buf) < 0)
die_errno(_("could not switch to '%s'"), path.buf);

strbuf_release(&path);
setup_git_directory();
}

Expand Down Expand Up @@ -789,42 +825,28 @@ static char *remote_default_branch(const char *url)
return NULL;
}

static void strbuf_parentdir(struct strbuf *buf)
static int delete_enlistment(struct strbuf *enlistment)
{
int len = buf->len;
while (len > 0 && !is_dir_sep(buf->buf[--len]))
; /* keep looking for parent directory */
strbuf_setlen(buf, len);
}

static int delete_enlistment(void)
{
struct strbuf enlistment = STRBUF_INIT;
#ifdef WIN32
struct strbuf parent = STRBUF_INIT;
#endif

if (unregister_dir())
die(_("failed to unregister repository"));

/* Compute the enlistment path (parent of the worktree) */
strbuf_addstr(&enlistment, the_repository->worktree);
strbuf_parentdir(&enlistment);

#ifdef WIN32
/* Change current directory to one outside of the enlistment
so that we may delete everything underneath it. */
strbuf_addbuf(&parent, &enlistment);
strbuf_addbuf(&parent, enlistment);
strbuf_parentdir(&parent);
if (chdir(parent.buf) < 0)
die_errno(_("could not switch to '%s'"), parent.buf);
strbuf_release(&parent);
#endif

if (remove_dir_recursively(&enlistment, 0))
if (remove_dir_recursively(enlistment, 0))
die(_("failed to delete enlistment directory"));

strbuf_release(&enlistment);
return 0;
}

Expand Down Expand Up @@ -1185,9 +1207,9 @@ static int cmd_diagnose(int argc, const char **argv)
argc = parse_options(argc, argv, NULL, options,
usage, 0);

setup_enlistment_directory(argc, argv, usage, options);
setup_enlistment_directory(argc, argv, usage, options, &buf);

strbuf_addstr(&buf, "../.scalarDiagnostics/scalar_");
strbuf_addstr(&buf, "/.scalarDiagnostics/scalar_");
strbuf_addftime(&buf, "%Y%m%d_%H%M%S", localtime_r(&now, &tm), 0, 0);
if (run_git("init", "-q", "-b", "dummy", "--bare", buf.buf, NULL)) {
res = error(_("could not initialize temporary repository: %s"),
Expand Down Expand Up @@ -1299,7 +1321,7 @@ static int cmd_register(int argc, const char **argv)
argc = parse_options(argc, argv, NULL, options,
usage, 0);

setup_enlistment_directory(argc, argv, usage, options);
setup_enlistment_directory(argc, argv, usage, options, NULL);

return register_dir();
}
Expand Down Expand Up @@ -1335,7 +1357,7 @@ static int cmd_reconfigure(int argc, const char **argv)
usage, 0);

if (!all) {
setup_enlistment_directory(argc, argv, usage, options);
setup_enlistment_directory(argc, argv, usage, options, NULL);

return set_recommended_config(1);
}
Expand Down Expand Up @@ -1421,7 +1443,7 @@ static int cmd_run(int argc, const char **argv)

argc--;
argv++;
setup_enlistment_directory(argc, argv, usagestr, options);
setup_enlistment_directory(argc, argv, usagestr, options, NULL);
strbuf_release(&buf);

if (i == 0)
Expand All @@ -1440,6 +1462,24 @@ static int cmd_run(int argc, const char **argv)
return 0;
}

static int remove_deleted_enlistment(struct strbuf *path)
{
int res = 0;
strbuf_realpath_forgiving(path, path->buf, 1);

if (run_git("config", "--global",
"--unset", "--fixed-value",
"scalar.repo", path->buf, NULL) < 0)
res = -1;

if (run_git("config", "--global",
"--unset", "--fixed-value",
"maintenance.repo", path->buf, NULL) < 0)
res = -1;

return res;
}

static int cmd_unregister(int argc, const char **argv)
{
struct option options[] = {
Expand All @@ -1459,32 +1499,29 @@ static int cmd_unregister(int argc, const char **argv)
* mistake and _still_ wants to unregister the thing.
*/
if (argc == 1) {
struct strbuf path = STRBUF_INIT;
struct strbuf src_path = STRBUF_INIT, workdir_path = STRBUF_INIT;

strbuf_addf(&path, "%s/src/.git", argv[0]);
if (!is_directory(path.buf)) {
int res = 0;
strbuf_addf(&src_path, "%s/src/.git", argv[0]);
strbuf_addf(&workdir_path, "%s/.git", argv[0]);
if (!is_directory(src_path.buf) && !is_directory(workdir_path.buf)) {
/* remove possible matching registrations */
int res = -1;

strbuf_strip_suffix(&path, "/.git");
strbuf_realpath_forgiving(&path, path.buf, 1);

if (run_git("config", "--global",
"--unset", "--fixed-value",
"scalar.repo", path.buf, NULL) < 0)
res = -1;
strbuf_strip_suffix(&src_path, "/.git");
res = remove_deleted_enlistment(&src_path) && res;

if (run_git("config", "--global",
"--unset", "--fixed-value",
"maintenance.repo", path.buf, NULL) < 0)
res = -1;
strbuf_strip_suffix(&workdir_path, "/.git");
res = remove_deleted_enlistment(&workdir_path) && res;

strbuf_release(&path);
strbuf_release(&src_path);
strbuf_release(&workdir_path);
return res;
}
strbuf_release(&path);
strbuf_release(&src_path);
strbuf_release(&workdir_path);
}

setup_enlistment_directory(argc, argv, usage, options);
setup_enlistment_directory(argc, argv, usage, options, NULL);

return unregister_dir();
}
Expand All @@ -1498,16 +1535,21 @@ static int cmd_delete(int argc, const char **argv)
N_("scalar delete <enlistment>"),
NULL
};
struct strbuf enlistment = STRBUF_INIT;
int res = 0;

argc = parse_options(argc, argv, NULL, options,
usage, 0);

if (argc != 1)
usage_with_options(usage, options);

setup_enlistment_directory(argc, argv, usage, options);
setup_enlistment_directory(argc, argv, usage, options, &enlistment);

return delete_enlistment();
res = delete_enlistment(&enlistment);
strbuf_release(&enlistment);

return res;
}

static int cmd_help(int argc, const char **argv)
Expand Down Expand Up @@ -1586,7 +1628,7 @@ static int cmd_cache_server(int argc, const char **argv)
usage_msg_opt(_("--get/--set/--list are mutually exclusive"),
usage, options);

setup_enlistment_directory(argc, argv, usage, options);
setup_enlistment_directory(argc, argv, usage, options, NULL);

if (list) {
const char *name = list, *url = list;
Expand Down
53 changes: 53 additions & 0 deletions contrib/scalar/t/t9099-scalar.sh
Original file line number Diff line number Diff line change
Expand Up @@ -204,4 +204,57 @@ test_expect_success '`scalar clone` with GVFS-enabled server' '
)
'

test_expect_success '`scalar register` parallel to worktree' '
git init test-repo/src &&
mkdir -p test-repo/out &&
scalar register test-repo/out &&
git config --get --global --fixed-value \
maintenance.repo "$(pwd)/test-repo/src" &&
scalar list >scalar.repos &&
grep -F "$(pwd)/test-repo/src" scalar.repos &&
scalar delete test-repo
'

test_expect_success '`scalar register` & `unregister` with existing repo' '
git init existing &&
scalar register existing &&
git config --get --global --fixed-value \
maintenance.repo "$(pwd)/existing" &&
scalar list >scalar.repos &&
grep -F "$(pwd)/existing" scalar.repos &&
scalar unregister existing &&
test_must_fail git config --get --global --fixed-value \
maintenance.repo "$(pwd)/existing" &&
scalar list >scalar.repos &&
! grep -F "$(pwd)/existing" scalar.repos
'

test_expect_success '`scalar unregister` with existing repo, deleted .git' '
scalar register existing &&
rm -rf existing/.git &&
scalar unregister existing &&
test_must_fail git config --get --global --fixed-value \
maintenance.repo "$(pwd)/existing" &&
scalar list >scalar.repos &&
! grep -F "$(pwd)/existing" scalar.repos
'

test_expect_success '`scalar register` existing repo with `src` folder' '
git init existing &&
mkdir -p existing/src &&
scalar register existing/src &&
scalar list >scalar.repos &&
grep -F "$(pwd)/existing" scalar.repos &&
scalar unregister existing &&
scalar list >scalar.repos &&
! grep -F "$(pwd)/existing" scalar.repos
'

test_expect_success '`scalar delete` with existing repo' '
git init existing &&
scalar register existing &&
scalar delete existing &&
test_path_is_missing existing
'

test_done

0 comments on commit e720ed3

Please sign in to comment.