Merge branch 'ds/scalar-updates'
Scalar updates. * ds/scalar-updates: scalar reconfigure: help users remove buggy repos setup: add discover_git_directory_reason() scalar: add --[no-]src option
This commit is contained in:
@ -8,7 +8,8 @@ scalar - A tool for managing large Git repositories
|
|||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
[verse]
|
[verse]
|
||||||
scalar clone [--single-branch] [--branch <main-branch>] [--full-clone] <url> [<enlistment>]
|
scalar clone [--single-branch] [--branch <main-branch>] [--full-clone]
|
||||||
|
[--[no-]src] <url> [<enlistment>]
|
||||||
scalar list
|
scalar list
|
||||||
scalar register [<enlistment>]
|
scalar register [<enlistment>]
|
||||||
scalar unregister [<enlistment>]
|
scalar unregister [<enlistment>]
|
||||||
@ -80,6 +81,11 @@ remote-tracking branch for the branch this option was used for the initial
|
|||||||
cloning. If the HEAD at the remote did not point at any branch when
|
cloning. If the HEAD at the remote did not point at any branch when
|
||||||
`--single-branch` clone was made, no remote-tracking branch is created.
|
`--single-branch` clone was made, no remote-tracking branch is created.
|
||||||
|
|
||||||
|
--[no-]src::
|
||||||
|
By default, `scalar clone` places the cloned repository within a
|
||||||
|
`<entlistment>/src` directory. Use `--no-src` to place the cloned
|
||||||
|
repository directly in the `<enlistment>` directory.
|
||||||
|
|
||||||
--[no-]full-clone::
|
--[no-]full-clone::
|
||||||
A sparse-checkout is initialized by default. This behavior can be
|
A sparse-checkout is initialized by default. This behavior can be
|
||||||
turned off via `--full-clone`.
|
turned off via `--full-clone`.
|
||||||
|
72
scalar.c
72
scalar.c
@ -409,6 +409,7 @@ static int cmd_clone(int argc, const char **argv)
|
|||||||
{
|
{
|
||||||
const char *branch = NULL;
|
const char *branch = NULL;
|
||||||
int full_clone = 0, single_branch = 0, show_progress = isatty(2);
|
int full_clone = 0, single_branch = 0, show_progress = isatty(2);
|
||||||
|
int src = 1;
|
||||||
struct option clone_options[] = {
|
struct option clone_options[] = {
|
||||||
OPT_STRING('b', "branch", &branch, N_("<branch>"),
|
OPT_STRING('b', "branch", &branch, N_("<branch>"),
|
||||||
N_("branch to checkout after clone")),
|
N_("branch to checkout after clone")),
|
||||||
@ -417,10 +418,13 @@ static int cmd_clone(int argc, const char **argv)
|
|||||||
OPT_BOOL(0, "single-branch", &single_branch,
|
OPT_BOOL(0, "single-branch", &single_branch,
|
||||||
N_("only download metadata for the branch that will "
|
N_("only download metadata for the branch that will "
|
||||||
"be checked out")),
|
"be checked out")),
|
||||||
|
OPT_BOOL(0, "src", &src,
|
||||||
|
N_("create repository within 'src' directory")),
|
||||||
OPT_END(),
|
OPT_END(),
|
||||||
};
|
};
|
||||||
const char * const clone_usage[] = {
|
const char * const clone_usage[] = {
|
||||||
N_("scalar clone [<options>] [--] <repo> [<dir>]"),
|
N_("scalar clone [--single-branch] [--branch <main-branch>] [--full-clone]\n"
|
||||||
|
"\t[--[no-]src] <url> [<enlistment>]"),
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
const char *url;
|
const char *url;
|
||||||
@ -456,7 +460,10 @@ static int cmd_clone(int argc, const char **argv)
|
|||||||
if (is_directory(enlistment))
|
if (is_directory(enlistment))
|
||||||
die(_("directory '%s' exists already"), enlistment);
|
die(_("directory '%s' exists already"), enlistment);
|
||||||
|
|
||||||
dir = xstrfmt("%s/src", enlistment);
|
if (src)
|
||||||
|
dir = xstrfmt("%s/src", enlistment);
|
||||||
|
else
|
||||||
|
dir = xstrdup(enlistment);
|
||||||
|
|
||||||
strbuf_reset(&buf);
|
strbuf_reset(&buf);
|
||||||
if (branch)
|
if (branch)
|
||||||
@ -657,6 +664,7 @@ static int cmd_reconfigure(int argc, const char **argv)
|
|||||||
git_config(get_scalar_repos, &scalar_repos);
|
git_config(get_scalar_repos, &scalar_repos);
|
||||||
|
|
||||||
for (i = 0; i < scalar_repos.nr; i++) {
|
for (i = 0; i < scalar_repos.nr; i++) {
|
||||||
|
int succeeded = 0;
|
||||||
const char *dir = scalar_repos.items[i].string;
|
const char *dir = scalar_repos.items[i].string;
|
||||||
|
|
||||||
strbuf_reset(&commondir);
|
strbuf_reset(&commondir);
|
||||||
@ -667,30 +675,56 @@ static int cmd_reconfigure(int argc, const char **argv)
|
|||||||
|
|
||||||
if (errno != ENOENT) {
|
if (errno != ENOENT) {
|
||||||
warning_errno(_("could not switch to '%s'"), dir);
|
warning_errno(_("could not switch to '%s'"), dir);
|
||||||
res = -1;
|
goto loop_end;
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
strbuf_addstr(&buf, dir);
|
strbuf_addstr(&buf, dir);
|
||||||
if (remove_deleted_enlistment(&buf))
|
if (remove_deleted_enlistment(&buf))
|
||||||
res = error(_("could not remove stale "
|
error(_("could not remove stale "
|
||||||
"scalar.repo '%s'"), dir);
|
"scalar.repo '%s'"), dir);
|
||||||
else
|
else {
|
||||||
warning(_("removing stale scalar.repo '%s'"),
|
warning(_("removed stale scalar.repo '%s'"),
|
||||||
dir);
|
dir);
|
||||||
|
succeeded = 1;
|
||||||
|
}
|
||||||
strbuf_release(&buf);
|
strbuf_release(&buf);
|
||||||
} else if (discover_git_directory(&commondir, &gitdir) < 0) {
|
goto loop_end;
|
||||||
warning_errno(_("git repository gone in '%s'"), dir);
|
}
|
||||||
|
|
||||||
|
switch (discover_git_directory_reason(&commondir, &gitdir)) {
|
||||||
|
case GIT_DIR_INVALID_OWNERSHIP:
|
||||||
|
warning(_("repository at '%s' has different owner"), dir);
|
||||||
|
goto loop_end;
|
||||||
|
|
||||||
|
case GIT_DIR_INVALID_GITFILE:
|
||||||
|
case GIT_DIR_INVALID_FORMAT:
|
||||||
|
warning(_("repository at '%s' has a format issue"), dir);
|
||||||
|
goto loop_end;
|
||||||
|
|
||||||
|
case GIT_DIR_DISCOVERED:
|
||||||
|
succeeded = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
warning(_("repository not found in '%s'"), dir);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
git_config_clear();
|
||||||
|
|
||||||
|
the_repository = &r;
|
||||||
|
r.commondir = commondir.buf;
|
||||||
|
r.gitdir = gitdir.buf;
|
||||||
|
|
||||||
|
if (set_recommended_config(1) >= 0)
|
||||||
|
succeeded = 1;
|
||||||
|
|
||||||
|
loop_end:
|
||||||
|
if (!succeeded) {
|
||||||
res = -1;
|
res = -1;
|
||||||
} else {
|
warning(_("to unregister this repository from Scalar, run\n"
|
||||||
git_config_clear();
|
"\tgit config --global --unset --fixed-value scalar.repo \"%s\""),
|
||||||
|
dir);
|
||||||
the_repository = &r;
|
|
||||||
r.commondir = commondir.buf;
|
|
||||||
r.gitdir = gitdir.buf;
|
|
||||||
|
|
||||||
if (set_recommended_config(1) < 0)
|
|
||||||
res = -1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
34
setup.c
34
setup.c
@ -1221,19 +1221,6 @@ static const char *allowed_bare_repo_to_string(
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum discovery_result {
|
|
||||||
GIT_DIR_NONE = 0,
|
|
||||||
GIT_DIR_EXPLICIT,
|
|
||||||
GIT_DIR_DISCOVERED,
|
|
||||||
GIT_DIR_BARE,
|
|
||||||
/* these are errors */
|
|
||||||
GIT_DIR_HIT_CEILING = -1,
|
|
||||||
GIT_DIR_HIT_MOUNT_POINT = -2,
|
|
||||||
GIT_DIR_INVALID_GITFILE = -3,
|
|
||||||
GIT_DIR_INVALID_OWNERSHIP = -4,
|
|
||||||
GIT_DIR_DISALLOWED_BARE = -5,
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We cannot decide in this function whether we are in the work tree or
|
* We cannot decide in this function whether we are in the work tree or
|
||||||
* not, since the config can only be read _after_ this function was called.
|
* not, since the config can only be read _after_ this function was called.
|
||||||
@ -1385,21 +1372,23 @@ static enum discovery_result setup_git_directory_gently_1(struct strbuf *dir,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int discover_git_directory(struct strbuf *commondir,
|
enum discovery_result discover_git_directory_reason(struct strbuf *commondir,
|
||||||
struct strbuf *gitdir)
|
struct strbuf *gitdir)
|
||||||
{
|
{
|
||||||
struct strbuf dir = STRBUF_INIT, err = STRBUF_INIT;
|
struct strbuf dir = STRBUF_INIT, err = STRBUF_INIT;
|
||||||
size_t gitdir_offset = gitdir->len, cwd_len;
|
size_t gitdir_offset = gitdir->len, cwd_len;
|
||||||
size_t commondir_offset = commondir->len;
|
size_t commondir_offset = commondir->len;
|
||||||
struct repository_format candidate = REPOSITORY_FORMAT_INIT;
|
struct repository_format candidate = REPOSITORY_FORMAT_INIT;
|
||||||
|
enum discovery_result result;
|
||||||
|
|
||||||
if (strbuf_getcwd(&dir))
|
if (strbuf_getcwd(&dir))
|
||||||
return -1;
|
return GIT_DIR_CWD_FAILURE;
|
||||||
|
|
||||||
cwd_len = dir.len;
|
cwd_len = dir.len;
|
||||||
if (setup_git_directory_gently_1(&dir, gitdir, NULL, 0) <= 0) {
|
result = setup_git_directory_gently_1(&dir, gitdir, NULL, 0);
|
||||||
|
if (result <= 0) {
|
||||||
strbuf_release(&dir);
|
strbuf_release(&dir);
|
||||||
return -1;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1429,11 +1418,11 @@ int discover_git_directory(struct strbuf *commondir,
|
|||||||
strbuf_setlen(commondir, commondir_offset);
|
strbuf_setlen(commondir, commondir_offset);
|
||||||
strbuf_setlen(gitdir, gitdir_offset);
|
strbuf_setlen(gitdir, gitdir_offset);
|
||||||
clear_repository_format(&candidate);
|
clear_repository_format(&candidate);
|
||||||
return -1;
|
return GIT_DIR_INVALID_FORMAT;
|
||||||
}
|
}
|
||||||
|
|
||||||
clear_repository_format(&candidate);
|
clear_repository_format(&candidate);
|
||||||
return 0;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *setup_git_directory_gently(int *nongit_ok)
|
const char *setup_git_directory_gently(int *nongit_ok)
|
||||||
@ -1515,10 +1504,11 @@ const char *setup_git_directory_gently(int *nongit_ok)
|
|||||||
}
|
}
|
||||||
*nongit_ok = 1;
|
*nongit_ok = 1;
|
||||||
break;
|
break;
|
||||||
case GIT_DIR_NONE:
|
case GIT_DIR_CWD_FAILURE:
|
||||||
|
case GIT_DIR_INVALID_FORMAT:
|
||||||
/*
|
/*
|
||||||
* As a safeguard against setup_git_directory_gently_1 returning
|
* As a safeguard against setup_git_directory_gently_1 returning
|
||||||
* this value, fallthrough to BUG. Otherwise it is possible to
|
* these values, fallthrough to BUG. Otherwise it is possible to
|
||||||
* set startup_info->have_repository to 1 when we did nothing to
|
* set startup_info->have_repository to 1 when we did nothing to
|
||||||
* find a repository.
|
* find a repository.
|
||||||
*/
|
*/
|
||||||
|
35
setup.h
35
setup.h
@ -42,16 +42,45 @@ const char *resolve_gitdir_gently(const char *suspect, int *return_error_code);
|
|||||||
#define resolve_gitdir(path) resolve_gitdir_gently((path), NULL)
|
#define resolve_gitdir(path) resolve_gitdir_gently((path), NULL)
|
||||||
|
|
||||||
void setup_work_tree(void);
|
void setup_work_tree(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* discover_git_directory_reason() is similar to discover_git_directory(),
|
||||||
|
* except it returns an enum value instead. It is important to note that
|
||||||
|
* a zero-valued return here is actually GIT_DIR_NONE, which is different
|
||||||
|
* from discover_git_directory.
|
||||||
|
*/
|
||||||
|
enum discovery_result {
|
||||||
|
GIT_DIR_EXPLICIT = 1,
|
||||||
|
GIT_DIR_DISCOVERED = 2,
|
||||||
|
GIT_DIR_BARE = 3,
|
||||||
|
/* these are errors */
|
||||||
|
GIT_DIR_HIT_CEILING = -1,
|
||||||
|
GIT_DIR_HIT_MOUNT_POINT = -2,
|
||||||
|
GIT_DIR_INVALID_GITFILE = -3,
|
||||||
|
GIT_DIR_INVALID_OWNERSHIP = -4,
|
||||||
|
GIT_DIR_DISALLOWED_BARE = -5,
|
||||||
|
GIT_DIR_INVALID_FORMAT = -6,
|
||||||
|
GIT_DIR_CWD_FAILURE = -7,
|
||||||
|
};
|
||||||
|
enum discovery_result discover_git_directory_reason(struct strbuf *commondir,
|
||||||
|
struct strbuf *gitdir);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find the commondir and gitdir of the repository that contains the current
|
* Find the commondir and gitdir of the repository that contains the current
|
||||||
* working directory, without changing the working directory or other global
|
* working directory, without changing the working directory or other global
|
||||||
* state. The result is appended to commondir and gitdir. If the discovered
|
* state. The result is appended to commondir and gitdir. If the discovered
|
||||||
* gitdir does not correspond to a worktree, then 'commondir' and 'gitdir' will
|
* gitdir does not correspond to a worktree, then 'commondir' and 'gitdir' will
|
||||||
* both have the same result appended to the buffer. The return value is
|
* both have the same result appended to the buffer. The return value is
|
||||||
* either 0 upon success and non-zero if no repository was found.
|
* either 0 upon success and -1 if no repository was found.
|
||||||
*/
|
*/
|
||||||
int discover_git_directory(struct strbuf *commondir,
|
static inline int discover_git_directory(struct strbuf *commondir,
|
||||||
struct strbuf *gitdir);
|
struct strbuf *gitdir)
|
||||||
|
{
|
||||||
|
if (discover_git_directory_reason(commondir, gitdir) <= 0)
|
||||||
|
return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
const char *setup_git_directory_gently(int *);
|
const char *setup_git_directory_gently(int *);
|
||||||
const char *setup_git_directory(void);
|
const char *setup_git_directory(void);
|
||||||
char *prefix_path(const char *prefix, int len, const char *path);
|
char *prefix_path(const char *prefix, int len, const char *path);
|
||||||
|
@ -180,4 +180,16 @@ test_expect_success 'scalar clone warns when background maintenance fails' '
|
|||||||
grep "could not turn on maintenance" err
|
grep "could not turn on maintenance" err
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success '`scalar clone --no-src`' '
|
||||||
|
scalar clone --src "file://$(pwd)/to-clone" with-src &&
|
||||||
|
scalar clone --no-src "file://$(pwd)/to-clone" without-src &&
|
||||||
|
|
||||||
|
test_path_is_dir with-src/src &&
|
||||||
|
test_path_is_missing without-src/src &&
|
||||||
|
|
||||||
|
(cd with-src/src && ls ?*) >with &&
|
||||||
|
(cd without-src && ls ?*) >without &&
|
||||||
|
test_cmp with without
|
||||||
|
'
|
||||||
|
|
||||||
test_done
|
test_done
|
||||||
|
Reference in New Issue
Block a user