Merge branch 'ar/submodule-add-more'

More parts of "git submodule add" has been rewritten in C.

* ar/submodule-add-more:
  submodule--helper: rename compute_submodule_clone_url()
  submodule--helper: remove resolve-relative-url subcommand
  submodule--helper: remove add-config subcommand
  submodule--helper: remove add-clone subcommand
  submodule--helper: convert the bulk of cmd_add() to C
  dir: libify and export helper functions from clone.c
  submodule--helper: remove repeated code in sync_submodule()
  submodule--helper: refactor resolve_relative_url() helper
  submodule--helper: add options for compute_submodule_clone_url()
This commit is contained in:
Junio C Hamano
2021-09-20 15:20:43 -07:00
5 changed files with 291 additions and 355 deletions

View File

@ -199,34 +199,28 @@ static char *relative_url(const char *remote_url,
return strbuf_detach(&sb, NULL);
}
static int resolve_relative_url(int argc, const char **argv, const char *prefix)
static char *resolve_relative_url(const char *rel_url, const char *up_path, int quiet)
{
char *remoteurl = NULL;
char *remoteurl, *resolved_url;
char *remote = get_default_remote();
const char *up_path = NULL;
char *res;
const char *url;
struct strbuf sb = STRBUF_INIT;
struct strbuf remotesb = STRBUF_INIT;
if (argc != 2 && argc != 3)
die("resolve-relative-url only accepts one or two arguments");
url = argv[1];
strbuf_addf(&sb, "remote.%s.url", remote);
free(remote);
if (git_config_get_string(sb.buf, &remoteurl))
/* the repository is its own authoritative upstream */
strbuf_addf(&remotesb, "remote.%s.url", remote);
if (git_config_get_string(remotesb.buf, &remoteurl)) {
if (!quiet)
warning(_("could not look up configuration '%s'. "
"Assuming this repository is its own "
"authoritative upstream."),
remotesb.buf);
remoteurl = xgetcwd();
}
resolved_url = relative_url(remoteurl, rel_url, up_path);
if (argc == 3)
up_path = argv[2];
res = relative_url(remoteurl, url, up_path);
puts(res);
free(res);
free(remote);
free(remoteurl);
return 0;
strbuf_release(&remotesb);
return resolved_url;
}
static int resolve_relative_url_test(int argc, const char **argv, const char *prefix)
@ -590,26 +584,6 @@ static int module_foreach(int argc, const char **argv, const char *prefix)
return 0;
}
static char *compute_submodule_clone_url(const char *rel_url)
{
char *remoteurl, *relurl;
char *remote = get_default_remote();
struct strbuf remotesb = STRBUF_INIT;
strbuf_addf(&remotesb, "remote.%s.url", remote);
if (git_config_get_string(remotesb.buf, &remoteurl)) {
warning(_("could not look up configuration '%s'. Assuming this repository is its own authoritative upstream."), remotesb.buf);
remoteurl = xgetcwd();
}
relurl = relative_url(remoteurl, rel_url, NULL);
free(remote);
free(remoteurl);
strbuf_release(&remotesb);
return relurl;
}
struct init_cb {
const char *prefix;
unsigned int flags;
@ -660,7 +634,7 @@ static void init_submodule(const char *path, const char *prefix,
if (starts_with_dot_dot_slash(url) ||
starts_with_dot_slash(url)) {
char *oldurl = url;
url = compute_submodule_clone_url(oldurl);
url = resolve_relative_url(oldurl, NULL, 0);
free(oldurl);
}
@ -1380,20 +1354,10 @@ static void sync_submodule(const char *path, const char *prefix,
if (sub && sub->url) {
if (starts_with_dot_dot_slash(sub->url) ||
starts_with_dot_slash(sub->url)) {
char *remote_url, *up_path;
char *remote = get_default_remote();
strbuf_addf(&sb, "remote.%s.url", remote);
if (git_config_get_string(sb.buf, &remote_url))
remote_url = xgetcwd();
up_path = get_up_path(path);
sub_origin_url = relative_url(remote_url, sub->url, up_path);
super_config_url = relative_url(remote_url, sub->url, NULL);
free(remote);
char *up_path = get_up_path(path);
sub_origin_url = resolve_relative_url(sub->url, up_path, 1);
super_config_url = resolve_relative_url(sub->url, NULL, 1);
free(up_path);
free(remote_url);
} else {
sub_origin_url = xstrdup(sub->url);
super_config_url = xstrdup(sub->url);
@ -2134,7 +2098,7 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
if (repo_config_get_string_tmp(the_repository, sb.buf, &url)) {
if (starts_with_dot_slash(sub->url) ||
starts_with_dot_dot_slash(sub->url)) {
url = compute_submodule_clone_url(sub->url);
url = resolve_relative_url(sub->url, NULL, 0);
need_free_url = 1;
} else
url = sub->url;
@ -2765,7 +2729,7 @@ struct add_data {
const char *prefix;
const char *branch;
const char *reference_path;
const char *sm_path;
char *sm_path;
const char *sm_name;
const char *repo;
const char *realrepo;
@ -2877,65 +2841,6 @@ static int add_submodule(const struct add_data *add_data)
return 0;
}
static int add_clone(int argc, const char **argv, const char *prefix)
{
int force = 0, quiet = 0, dissociate = 0, progress = 0;
struct add_data add_data = ADD_DATA_INIT;
struct option options[] = {
OPT_STRING('b', "branch", &add_data.branch,
N_("branch"),
N_("branch of repository to checkout on cloning")),
OPT_STRING(0, "prefix", &prefix,
N_("path"),
N_("alternative anchor for relative paths")),
OPT_STRING(0, "path", &add_data.sm_path,
N_("path"),
N_("where the new submodule will be cloned to")),
OPT_STRING(0, "name", &add_data.sm_name,
N_("string"),
N_("name of the new submodule")),
OPT_STRING(0, "url", &add_data.realrepo,
N_("string"),
N_("url where to clone the submodule from")),
OPT_STRING(0, "reference", &add_data.reference_path,
N_("repo"),
N_("reference repository")),
OPT_BOOL(0, "dissociate", &dissociate,
N_("use --reference only while cloning")),
OPT_INTEGER(0, "depth", &add_data.depth,
N_("depth for shallow clones")),
OPT_BOOL(0, "progress", &progress,
N_("force cloning progress")),
OPT__FORCE(&force, N_("allow adding an otherwise ignored submodule path"),
PARSE_OPT_NOCOMPLETE),
OPT__QUIET(&quiet, "suppress output for cloning a submodule"),
OPT_END()
};
const char *const usage[] = {
N_("git submodule--helper add-clone [<options>...] "
"--url <url> --path <path> --name <name>"),
NULL
};
argc = parse_options(argc, argv, prefix, options, usage, 0);
if (argc != 0)
usage_with_options(usage, options);
add_data.prefix = prefix;
add_data.progress = !!progress;
add_data.dissociate = !!dissociate;
add_data.force = !!force;
add_data.quiet = !!quiet;
if (add_submodule(&add_data))
return 1;
return 0;
}
static int config_submodule_in_gitmodules(const char *name, const char *var, const char *value)
{
char *key;
@ -3016,50 +2921,164 @@ static void configure_added_submodule(struct add_data *add_data)
}
}
static int add_config(int argc, const char **argv, const char *prefix)
static void die_on_index_match(const char *path, int force)
{
int force = 0;
struct pathspec ps;
const char *args[] = { path, NULL };
parse_pathspec(&ps, 0, PATHSPEC_PREFER_CWD, NULL, args);
if (read_cache_preload(NULL) < 0)
die(_("index file corrupt"));
if (ps.nr) {
int i;
char *ps_matched = xcalloc(ps.nr, 1);
/* TODO: audit for interaction with sparse-index. */
ensure_full_index(&the_index);
/*
* Since there is only one pathspec, we just need
* need to check ps_matched[0] to know if a cache
* entry matched.
*/
for (i = 0; i < active_nr; i++) {
ce_path_match(&the_index, active_cache[i], &ps,
ps_matched);
if (ps_matched[0]) {
if (!force)
die(_("'%s' already exists in the index"),
path);
if (!S_ISGITLINK(active_cache[i]->ce_mode))
die(_("'%s' already exists in the index "
"and is not a submodule"), path);
break;
}
}
free(ps_matched);
}
}
static void die_on_repo_without_commits(const char *path)
{
struct strbuf sb = STRBUF_INIT;
strbuf_addstr(&sb, path);
if (is_nonbare_repository_dir(&sb)) {
struct object_id oid;
if (resolve_gitlink_ref(path, "HEAD", &oid) < 0)
die(_("'%s' does not have a commit checked out"), path);
}
}
static int module_add(int argc, const char **argv, const char *prefix)
{
int force = 0, quiet = 0, progress = 0, dissociate = 0;
struct add_data add_data = ADD_DATA_INIT;
struct option options[] = {
OPT_STRING('b', "branch", &add_data.branch,
N_("branch"),
N_("branch of repository to store in "
"the submodule configuration")),
OPT_STRING(0, "url", &add_data.repo,
N_("string"),
N_("url to clone submodule from")),
OPT_STRING(0, "resolved-url", &add_data.realrepo,
N_("string"),
N_("url to clone the submodule from, after it has "
"been dereferenced relative to parent's url, "
"in the case where <url> is a relative url")),
OPT_STRING(0, "path", &add_data.sm_path,
N_("path"),
N_("where the new submodule will be cloned to")),
OPT_STRING(0, "name", &add_data.sm_name,
N_("string"),
N_("name of the new submodule")),
OPT_STRING('b', "branch", &add_data.branch, N_("branch"),
N_("branch of repository to add as submodule")),
OPT__FORCE(&force, N_("allow adding an otherwise ignored submodule path"),
PARSE_OPT_NOCOMPLETE),
OPT__QUIET(&quiet, N_("print only error messages")),
OPT_BOOL(0, "progress", &progress, N_("force cloning progress")),
OPT_STRING(0, "reference", &add_data.reference_path, N_("repository"),
N_("reference repository")),
OPT_BOOL(0, "dissociate", &dissociate, N_("borrow the objects from reference repositories")),
OPT_STRING(0, "name", &add_data.sm_name, N_("name"),
N_("sets the submodules name to the given string "
"instead of defaulting to its path")),
OPT_INTEGER(0, "depth", &add_data.depth, N_("depth for shallow clones")),
OPT_END()
};
const char *const usage[] = {
N_("git submodule--helper add-config "
"[--force|-f] [--branch|-b <branch>] "
"--url <url> --resolved-url <resolved-url> "
"--path <path> --name <name>"),
N_("git submodule--helper add [<options>] [--] <repository> [<path>]"),
NULL
};
argc = parse_options(argc, argv, prefix, options, usage, 0);
if (argc)
if (!is_writing_gitmodules_ok())
die(_("please make sure that the .gitmodules file is in the working tree"));
if (prefix && *prefix &&
add_data.reference_path && !is_absolute_path(add_data.reference_path))
add_data.reference_path = xstrfmt("%s%s", prefix, add_data.reference_path);
if (argc == 0 || argc > 2)
usage_with_options(usage, options);
add_data.repo = argv[0];
if (argc == 1)
add_data.sm_path = git_url_basename(add_data.repo, 0, 0);
else
add_data.sm_path = xstrdup(argv[1]);
if (prefix && *prefix && !is_absolute_path(add_data.sm_path))
add_data.sm_path = xstrfmt("%s%s", prefix, add_data.sm_path);
if (starts_with_dot_dot_slash(add_data.repo) ||
starts_with_dot_slash(add_data.repo)) {
if (prefix)
die(_("Relative path can only be used from the toplevel "
"of the working tree"));
/* dereference source url relative to parent's url */
add_data.realrepo = resolve_relative_url(add_data.repo, NULL, 1);
} else if (is_dir_sep(add_data.repo[0]) || strchr(add_data.repo, ':')) {
add_data.realrepo = add_data.repo;
} else {
die(_("repo URL: '%s' must be absolute or begin with ./|../"),
add_data.repo);
}
/*
* normalize path:
* multiple //; leading ./; /./; /../;
*/
normalize_path_copy(add_data.sm_path, add_data.sm_path);
strip_dir_trailing_slashes(add_data.sm_path);
die_on_index_match(add_data.sm_path, force);
die_on_repo_without_commits(add_data.sm_path);
if (!force) {
int exit_code = -1;
struct strbuf sb = STRBUF_INIT;
struct child_process cp = CHILD_PROCESS_INIT;
cp.git_cmd = 1;
cp.no_stdout = 1;
strvec_pushl(&cp.args, "add", "--dry-run", "--ignore-missing",
"--no-warn-embedded-repo", add_data.sm_path, NULL);
if ((exit_code = pipe_command(&cp, NULL, 0, NULL, 0, &sb, 0))) {
strbuf_complete_line(&sb);
fputs(sb.buf, stderr);
free(add_data.sm_path);
return exit_code;
}
strbuf_release(&sb);
}
if(!add_data.sm_name)
add_data.sm_name = add_data.sm_path;
if (check_submodule_name(add_data.sm_name))
die(_("'%s' is not a valid submodule name"), add_data.sm_name);
add_data.prefix = prefix;
add_data.force = !!force;
add_data.quiet = !!quiet;
add_data.progress = !!progress;
add_data.dissociate = !!dissociate;
if (add_submodule(&add_data)) {
free(add_data.sm_path);
return 1;
}
configure_added_submodule(&add_data);
free(add_data.sm_path);
return 0;
}
@ -3076,13 +3095,11 @@ static struct cmd_struct commands[] = {
{"list", module_list, 0},
{"name", module_name, 0},
{"clone", module_clone, 0},
{"add-clone", add_clone, 0},
{"add-config", add_config, 0},
{"add", module_add, SUPPORT_SUPER_PREFIX},
{"update-module-mode", module_update_module_mode, 0},
{"update-clone", update_clone, 0},
{"ensure-core-worktree", ensure_core_worktree, 0},
{"relative-path", resolve_relative_path, 0},
{"resolve-relative-url", resolve_relative_url, 0},
{"resolve-relative-url-test", resolve_relative_url_test, 0},
{"foreach", module_foreach, SUPPORT_SUPER_PREFIX},
{"init", module_init, SUPPORT_SUPER_PREFIX},