submodule--helper: convert the bulk of cmd_add() to C
Introduce the 'add' subcommand to `submodule--helper.c` that does all the work 'submodule add' past the parsing of flags. We also remove the constness of the sm_path field of the `add_data` struct. This is needed so that it can be modified by normalize_path_copy(). As with the previous conversions, this is meant to be a faithful conversion with no modification to the behaviour of `submodule add`. Signed-off-by: Atharva Raykar <raykar.ath@gmail.com> Mentored-by: Christian Couder <christian.couder@gmail.com> Helped-by: Kaartic Sivaraam <kaartic.sivaraam@gmail.com> Mentored-by: Shourya Shukla <periperidip@gmail.com> Based-on-patch-by: Shourya Shukla <periperidip@gmail.com> Based-on-patch-by: Prathamesh Chavan <pc44800@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:

committed by
Junio C Hamano

parent
ed86301f68
commit
a6226fd772
@ -2748,7 +2748,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;
|
||||
@ -3047,6 +3047,168 @@ static int add_config(int argc, const char **argv, const char *prefix)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void die_on_index_match(const char *path, int force)
|
||||
{
|
||||
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 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 submodule’s 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 [<options>] [--] <repository> [<path>]"),
|
||||
NULL
|
||||
};
|
||||
|
||||
argc = parse_options(argc, argv, prefix, options, usage, 0);
|
||||
|
||||
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 = compute_submodule_clone_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;
|
||||
}
|
||||
|
||||
#define SUPPORT_SUPER_PREFIX (1<<0)
|
||||
|
||||
struct cmd_struct {
|
||||
@ -3061,6 +3223,7 @@ static struct cmd_struct commands[] = {
|
||||
{"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},
|
||||
|
Reference in New Issue
Block a user