-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
Introduce the 'add' subcommand to submodule--helper that does all the work 'submodule add' past the parsing of flags. While at it, remove the now-unused shell interface to 'resolve_relative_url()' and repurpose it as an internal helper function. Since the 'die()' of C prepends the word 'fatal', we modify t7400.6 to reflect the same. 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>
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -197,34 +197,23 @@ 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 *url) | ||
{ | ||
char *remoteurl = NULL; | ||
char *remote = get_default_remote(); | ||
const char *up_path = NULL; | ||
char *res; | ||
const char *url; | ||
char *remote = get_default_remote(); | ||
char *remoteurl = NULL; | ||
struct strbuf sb = 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 */ | ||
remoteurl = xgetcwd(); | ||
|
||
if (argc == 3) | ||
up_path = argv[2]; | ||
|
||
res = relative_url(remoteurl, url, up_path); | ||
puts(res); | ||
free(res); | ||
res = relative_url(remoteurl, url, NULL); | ||
free(remoteurl); | ||
return 0; | ||
return res; | ||
} | ||
|
||
static int resolve_relative_url_test(int argc, const char **argv, const char *prefix) | ||
|
@@ -3059,6 +3048,163 @@ 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); | ||
|
||
/* TODO: Should this just be read_cache()? */ | ||
read_cache_preload(NULL); | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
chriscool
|
||
if (ps.nr) { | ||
int i; | ||
char *ps_matched = xcalloc(ps.nr, 1); | ||
|
||
/* TODO: audit for interaction with sparse-index. */ | ||
ensure_full_index(&the_index); | ||
This comment has been minimized.
Sorry, something went wrong.
tfidfwastaken
Author
Owner
|
||
|
||
/* | ||
* 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); | ||
else 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>] [--] [<path>]"), | ||
This comment has been minimized.
Sorry, something went wrong.
sivaraam
|
||
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); | ||
This comment has been minimized.
Sorry, something went wrong.
sivaraam
|
||
} else if (argc == 1) { | ||
This comment has been minimized.
Sorry, something went wrong. |
||
add_data.repo = argv[0]; | ||
add_data.sm_path = guess_dir_name_from_git_url(add_data.repo, 0, 0); | ||
} else { | ||
add_data.repo = argv[0]; | ||
This comment has been minimized.
Sorry, something went wrong.
chriscool
|
||
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 " | ||
This comment has been minimized.
Sorry, something went wrong.
sivaraam
|
||
"of the working tree")); | ||
|
||
/* dereference source url relative to parent's url */ | ||
add_data.realrepo = resolve_relative_url(add_data.repo); | ||
} 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); | ||
return exit_code; | ||
} | ||
strbuf_release(&sb); | ||
} | ||
|
||
add_data.sm_name = 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)) | ||
return 1; | ||
configure_added_submodule(&add_data); | ||
free(add_data.sm_path); | ||
|
||
return 0; | ||
} | ||
|
||
#define SUPPORT_SUPER_PREFIX (1<<0) | ||
|
||
struct cmd_struct { | ||
|
@@ -3071,13 +3217,13 @@ static struct cmd_struct commands[] = { | |
{"list", module_list, 0}, | ||
{"name", module_name, 0}, | ||
{"clone", module_clone, 0}, | ||
{"add", module_add, SUPPORT_SUPER_PREFIX}, | ||
{"add-clone", add_clone, 0}, | ||
{"add-config", add_config, 0}, | ||
{"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}, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -145,104 +145,7 @@ cmd_add() | |
shift | ||
done | ||
|
||
if ! git submodule--helper config --check-writeable >/dev/null 2>&1 | ||
then | ||
die "$(eval_gettext "please make sure that the .gitmodules file is in the working tree")" | ||
fi | ||
|
||
if test -n "$reference_path" | ||
then | ||
is_absolute_path "$reference_path" || | ||
reference_path="$wt_prefix$reference_path" | ||
|
||
reference="--reference=$reference_path" | ||
fi | ||
|
||
repo=$1 | ||
sm_path=$2 | ||
|
||
if test -z "$sm_path"; then | ||
sm_path=$(printf '%s\n' "$repo" | | ||
sed -e 's|/$||' -e 's|:*/*\.git$||' -e 's|.*[/:]||g') | ||
fi | ||
|
||
if test -z "$repo" || test -z "$sm_path"; then | ||
usage | ||
fi | ||
|
||
is_absolute_path "$sm_path" || sm_path="$wt_prefix$sm_path" | ||
|
||
# assure repo is absolute or relative to parent | ||
case "$repo" in | ||
./*|../*) | ||
test -z "$wt_prefix" || | ||
die "$(gettext "Relative path can only be used from the toplevel of the working tree")" | ||
|
||
# dereference source url relative to parent's url | ||
realrepo=$(git submodule--helper resolve-relative-url "$repo") || exit | ||
;; | ||
*:*|/*) | ||
# absolute url | ||
realrepo=$repo | ||
;; | ||
*) | ||
die "$(eval_gettext "repo URL: '\$repo' must be absolute or begin with ./|../")" | ||
;; | ||
esac | ||
|
||
# normalize path: | ||
# multiple //; leading ./; /./; /../; trailing / | ||
sm_path=$(printf '%s/\n' "$sm_path" | | ||
sed -e ' | ||
s|//*|/|g | ||
s|^\(\./\)*|| | ||
s|/\(\./\)*|/|g | ||
:start | ||
s|\([^/]*\)/\.\./|| | ||
tstart | ||
s|/*$|| | ||
') | ||
if test -z "$force" | ||
then | ||
git ls-files --error-unmatch "$sm_path" > /dev/null 2>&1 && | ||
die "$(eval_gettext "'\$sm_path' already exists in the index")" | ||
else | ||
git ls-files -s "$sm_path" | sane_grep -v "^160000" > /dev/null 2>&1 && | ||
die "$(eval_gettext "'\$sm_path' already exists in the index and is not a submodule")" | ||
fi | ||
|
||
if test -d "$sm_path" && | ||
test -z $(git -C "$sm_path" rev-parse --show-cdup 2>/dev/null) | ||
then | ||
git -C "$sm_path" rev-parse --verify -q HEAD >/dev/null || | ||
die "$(eval_gettext "'\$sm_path' does not have a commit checked out")" | ||
fi | ||
|
||
if test -z "$force" | ||
then | ||
dryerr=$(git add --dry-run --ignore-missing --no-warn-embedded-repo "$sm_path" 2>&1 >/dev/null) | ||
res=$? | ||
if test $res -ne 0 | ||
then | ||
echo >&2 "$dryerr" | ||
exit $res | ||
fi | ||
fi | ||
|
||
if test -n "$custom_name" | ||
then | ||
sm_name="$custom_name" | ||
else | ||
sm_name="$sm_path" | ||
fi | ||
|
||
if ! git submodule--helper check-name "$sm_name" | ||
then | ||
die "$(eval_gettext "'$sm_name' is not a valid submodule name")" | ||
fi | ||
|
||
git submodule--helper add-clone ${GIT_QUIET:+--quiet} ${force:+"--force"} ${progress:+"--progress"} ${branch:+--branch "$branch"} --prefix "$wt_prefix" --path "$sm_path" --name "$sm_name" --url "$realrepo" ${reference:+"$reference"} ${dissociate:+"--dissociate"} ${depth:+"$depth"} || exit | ||
git submodule--helper add-config ${force:+--force} ${branch:+--branch "$branch"} --url "$repo" --resolved-url "$realrepo" --path "$sm_path" --name "$sm_name" | ||
git ${wt_prefix:+-C "$wt_prefix"} ${prefix:+--super-prefix "$prefix"} submodule--helper add ${GIT_QUIET:+--quiet} ${force:+--force} ${progress:+"--progress"} ${branch:+--branch "$branch"} ${reference_path:+--reference "$reference_path"} ${dissociate:+--dissociate} ${custom_name:+--name "$custom_name"} ${depth:+"$depth"} -- "$@" | ||
This comment has been minimized.
Sorry, something went wrong.
sivaraam
|
||
} | ||
|
||
# | ||
|
I'm not too sure about the difference between
read_cache()
andread_cache_preload(NULL)
.I understand the latter preloads the index (in parallel) according to a pathspec argument, but does that imply the former is doing some kind of on-demand loading? Moreover, does passing
NULL
toread_cache_preload()
preload the whole index?Which form should be preferred for which use case?
I think I did not understand those functions correctly.