submodule--helper: refactor module_clone()

Separate out the core logic of module_clone() from the flag parsing---this way we can call the equivalent of the `submodule--helper clone` subcommand directly within C, without needing to push arguments in a strvec. Signed-off-by: Atharva Raykar <raykar.ath@gmail.com> Mentored-by: Christian Couder <christian.couder@gmail.com> Mentored-by: Shourya Shukla <periperidip@gmail.com> Suggested-by: Junio C Hamano <gitster@pobox.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Atharva Raykar committed Jul 10, 2021 at 13:18 UTC a98b02c11289879868dd0d5f80e894d8d01dc73b
1 file changed +128 -113
builtin/submodule--helper.c
+128 -113
@@ -1658,45 +1658,20 @@ static int module_deinit(int argc, const char **argv, const char *prefix)
1658 return 0;
1659 }
1660
1661 -static int clone_submodule(const char *path, const char *gitdir, const char *url,
1662 - const char *depth, struct string_list *reference, int dissociate,
1663 - int quiet, int progress, int single_branch)
1664 -{
1665 - struct child_process cp = CHILD_PROCESS_INIT;
1666 -
1667 - strvec_push(&cp.args, "clone");
1668 - strvec_push(&cp.args, "--no-checkout");
1669 - if (quiet)
1670 - strvec_push(&cp.args, "--quiet");
1671 - if (progress)
1672 - strvec_push(&cp.args, "--progress");
1673 - if (depth && *depth)
1674 - strvec_pushl(&cp.args, "--depth", depth, NULL);
1675 - if (reference->nr) {
1676 - struct string_list_item *item;
1677 - for_each_string_list_item(item, reference)
1678 - strvec_pushl(&cp.args, "--reference",
1679 - item->string, NULL);
1680 - }
1681 - if (dissociate)
1682 - strvec_push(&cp.args, "--dissociate");
1683 - if (gitdir && *gitdir)
1684 - strvec_pushl(&cp.args, "--separate-git-dir", gitdir, NULL);
1685 - if (single_branch >= 0)
1686 - strvec_push(&cp.args, single_branch ?
1687 - "--single-branch" :
1688 - "--no-single-branch");
1689 -
1690 - strvec_push(&cp.args, "--");
1691 - strvec_push(&cp.args, url);
1692 - strvec_push(&cp.args, path);
1693 -
1694 - cp.git_cmd = 1;
1695 - prepare_submodule_repo_env(&cp.env_array);
1696 - cp.no_stdin = 1;
1697 -
1698 - return run_command(&cp);
1699 -}
1661 +struct module_clone_data {
1662 + const char *prefix;
1663 + const char *path;
1664 + const char *name;
1665 + const char *url;
1666 + const char *depth;
1667 + struct string_list reference;
1668 + unsigned int quiet: 1;
1669 + unsigned int progress: 1;
1670 + unsigned int dissociate: 1;
1671 + unsigned int require_init: 1;
1672 + int single_branch;
1673 +};
1674 +#define MODULE_CLONE_DATA_INIT { .reference = STRING_LIST_INIT_NODUP, .single_branch = -1 }
1675
1676 struct submodule_alternate_setup {
1677 const char *submodule_name;
@@ -1802,37 +1777,128 @@ static void prepare_possible_alternates(const char *sm_name,
1777 free(error_strategy);
1778 }
1779
1805 -static int module_clone(int argc, const char **argv, const char *prefix)
1780 +static int clone_submodule(struct module_clone_data *clone_data)
1781 {
1807 - const char *name = NULL, *url = NULL, *depth = NULL;
1808 - int quiet = 0;
1809 - int progress = 0;
1810 - char *p, *path = NULL, *sm_gitdir;
1811 - struct strbuf sb = STRBUF_INIT;
1812 - struct string_list reference = STRING_LIST_INIT_NODUP;
1813 - int dissociate = 0, require_init = 0;
1782 + char *p, *sm_gitdir;
1783 char *sm_alternate = NULL, *error_strategy = NULL;
1815 - int single_branch = -1;
1784 + struct strbuf sb = STRBUF_INIT;
1785 + struct child_process cp = CHILD_PROCESS_INIT;
1786 +
1787 + strbuf_addf(&sb, "%s/modules/%s", get_git_dir(), clone_data->name);
1788 + sm_gitdir = absolute_pathdup(sb.buf);
1789 + strbuf_reset(&sb);
1790 +
1791 + if (!is_absolute_path(clone_data->path)) {
1792 + strbuf_addf(&sb, "%s/%s", get_git_work_tree(), clone_data->path);
1793 + clone_data->path = strbuf_detach(&sb, NULL);
1794 + } else {
1795 + clone_data->path = xstrdup(clone_data->path);
1796 + }
1797 +
1798 + if (validate_submodule_git_dir(sm_gitdir, clone_data->name) < 0)
1799 + die(_("refusing to create/use '%s' in another submodule's "
1800 + "git dir"), sm_gitdir);
1801 +
1802 + if (!file_exists(sm_gitdir)) {
1803 + if (safe_create_leading_directories_const(sm_gitdir) < 0)
1804 + die(_("could not create directory '%s'"), sm_gitdir);
1805 +
1806 + prepare_possible_alternates(clone_data->name, &clone_data->reference);
1807 +
1808 + strvec_push(&cp.args, "clone");
1809 + strvec_push(&cp.args, "--no-checkout");
1810 + if (clone_data->quiet)
1811 + strvec_push(&cp.args, "--quiet");
1812 + if (clone_data->progress)
1813 + strvec_push(&cp.args, "--progress");
1814 + if (clone_data->depth && *(clone_data->depth))
1815 + strvec_pushl(&cp.args, "--depth", clone_data->depth, NULL);
1816 + if (clone_data->reference.nr) {
1817 + struct string_list_item *item;
1818 + for_each_string_list_item(item, &clone_data->reference)
1819 + strvec_pushl(&cp.args, "--reference",
1820 + item->string, NULL);
1821 + }
1822 + if (clone_data->dissociate)
1823 + strvec_push(&cp.args, "--dissociate");
1824 + if (sm_gitdir && *sm_gitdir)
1825 + strvec_pushl(&cp.args, "--separate-git-dir", sm_gitdir, NULL);
1826 + if (clone_data->single_branch >= 0)
1827 + strvec_push(&cp.args, clone_data->single_branch ?
1828 + "--single-branch" :
1829 + "--no-single-branch");
1830 +
1831 + strvec_push(&cp.args, "--");
1832 + strvec_push(&cp.args, clone_data->url);
1833 + strvec_push(&cp.args, clone_data->path);
1834 +
1835 + cp.git_cmd = 1;
1836 + prepare_submodule_repo_env(&cp.env_array);
1837 + cp.no_stdin = 1;
1838 +
1839 + if(run_command(&cp))
1840 + die(_("clone of '%s' into submodule path '%s' failed"),
1841 + clone_data->url, clone_data->path);
1842 + } else {
1843 + if (clone_data->require_init && !access(clone_data->path, X_OK) &&
1844 + !is_empty_dir(clone_data->path))
1845 + die(_("directory not empty: '%s'"), clone_data->path);
1846 + if (safe_create_leading_directories_const(clone_data->path) < 0)
1847 + die(_("could not create directory '%s'"), clone_data->path);
1848 + strbuf_addf(&sb, "%s/index", sm_gitdir);
1849 + unlink_or_warn(sb.buf);
1850 + strbuf_reset(&sb);
1851 + }
1852 +
1853 + connect_work_tree_and_git_dir(clone_data->path, sm_gitdir, 0);
1854 +
1855 + p = git_pathdup_submodule(clone_data->path, "config");
1856 + if (!p)
1857 + die(_("could not get submodule directory for '%s'"), clone_data->path);
1858 +
1859 + /* setup alternateLocation and alternateErrorStrategy in the cloned submodule if needed */
1860 + git_config_get_string("submodule.alternateLocation", &sm_alternate);
1861 + if (sm_alternate)
1862 + git_config_set_in_file(p, "submodule.alternateLocation",
1863 + sm_alternate);
1864 + git_config_get_string("submodule.alternateErrorStrategy", &error_strategy);
1865 + if (error_strategy)
1866 + git_config_set_in_file(p, "submodule.alternateErrorStrategy",
1867 + error_strategy);
1868 +
1869 + free(sm_alternate);
1870 + free(error_strategy);
1871 +
1872 + strbuf_release(&sb);
1873 + free(sm_gitdir);
1874 + free(p);
1875 + return 0;
1876 +}
1877 +
1878 +static int module_clone(int argc, const char **argv, const char *prefix)
1879 +{
1880 + int dissociate = 0, quiet = 0, progress = 0, require_init = 0;
1881 + struct module_clone_data clone_data = MODULE_CLONE_DATA_INIT;
1882
1883 struct option module_clone_options[] = {
1818 - OPT_STRING(0, "prefix", &prefix,
1884 + OPT_STRING(0, "prefix", &clone_data.prefix,
1885 N_("path"),
1886 N_("alternative anchor for relative paths")),
1821 - OPT_STRING(0, "path", &path,
1887 + OPT_STRING(0, "path", &clone_data.path,
1888 N_("path"),
1889 N_("where the new submodule will be cloned to")),
1824 - OPT_STRING(0, "name", &name,
1890 + OPT_STRING(0, "name", &clone_data.name,
1891 N_("string"),
1892 N_("name of the new submodule")),
1827 - OPT_STRING(0, "url", &url,
1893 + OPT_STRING(0, "url", &clone_data.url,
1894 N_("string"),
1895 N_("url where to clone the submodule from")),
1830 - OPT_STRING_LIST(0, "reference", &reference,
1896 + OPT_STRING_LIST(0, "reference", &clone_data.reference,
1897 N_("repo"),
1898 N_("reference repository")),
1899 OPT_BOOL(0, "dissociate", &dissociate,
1900 N_("use --reference only while cloning")),
1835 - OPT_STRING(0, "depth", &depth,
1901 + OPT_STRING(0, "depth", &clone_data.depth,
1902 N_("string"),
1903 N_("depth for shallow clones")),
1904 OPT__QUIET(&quiet, "Suppress output for cloning a submodule"),
@@ -1840,7 +1906,7 @@ static int module_clone(int argc, const char **argv, const char *prefix)
1906 N_("force cloning progress")),
1907 OPT_BOOL(0, "require-init", &require_init,
1908 N_("disallow cloning into non-empty directory")),
1843 - OPT_BOOL(0, "single-branch", &single_branch,
1909 + OPT_BOOL(0, "single-branch", &clone_data.single_branch,
1910 N_("clone only one branch, HEAD or --branch")),
1911 OPT_END()
1912 };
@@ -1856,67 +1922,16 @@ static int module_clone(int argc, const char **argv, const char *prefix)
1922 argc = parse_options(argc, argv, prefix, module_clone_options,
1923 git_submodule_helper_usage, 0);
1924
1859 - if (argc || !url || !path || !*path)
1925 + clone_data.dissociate = !!dissociate;
1926 + clone_data.quiet = !!quiet;
1927 + clone_data.progress = !!progress;
1928 + clone_data.require_init = !!require_init;
1929 +
1930 + if (argc || !clone_data.url || !clone_data.path || !*(clone_data.path))
1931 usage_with_options(git_submodule_helper_usage,
1932 module_clone_options);
1933
1863 - strbuf_addf(&sb, "%s/modules/%s", get_git_dir(), name);
1864 - sm_gitdir = absolute_pathdup(sb.buf);
1865 - strbuf_reset(&sb);
1866 -
1867 - if (!is_absolute_path(path)) {
1868 - strbuf_addf(&sb, "%s/%s", get_git_work_tree(), path);
1869 - path = strbuf_detach(&sb, NULL);
1870 - } else
1871 - path = xstrdup(path);
1872 -
1873 - if (validate_submodule_git_dir(sm_gitdir, name) < 0)
1874 - die(_("refusing to create/use '%s' in another submodule's "
1875 - "git dir"), sm_gitdir);
1876 -
1877 - if (!file_exists(sm_gitdir)) {
1878 - if (safe_create_leading_directories_const(sm_gitdir) < 0)
1879 - die(_("could not create directory '%s'"), sm_gitdir);
1880 -
1881 - prepare_possible_alternates(name, &reference);
1882 -
1883 - if (clone_submodule(path, sm_gitdir, url, depth, &reference, dissociate,
1884 - quiet, progress, single_branch))
1885 - die(_("clone of '%s' into submodule path '%s' failed"),
1886 - url, path);
1887 - } else {
1888 - if (require_init && !access(path, X_OK) && !is_empty_dir(path))
1889 - die(_("directory not empty: '%s'"), path);
1890 - if (safe_create_leading_directories_const(path) < 0)
1891 - die(_("could not create directory '%s'"), path);
1892 - strbuf_addf(&sb, "%s/index", sm_gitdir);
1893 - unlink_or_warn(sb.buf);
1894 - strbuf_reset(&sb);
1895 - }
1896 -
1897 - connect_work_tree_and_git_dir(path, sm_gitdir, 0);
1898 -
1899 - p = git_pathdup_submodule(path, "config");
1900 - if (!p)
1901 - die(_("could not get submodule directory for '%s'"), path);
1902 -
1903 - /* setup alternateLocation and alternateErrorStrategy in the cloned submodule if needed */
1904 - git_config_get_string("submodule.alternateLocation", &sm_alternate);
1905 - if (sm_alternate)
1906 - git_config_set_in_file(p, "submodule.alternateLocation",
1907 - sm_alternate);
1908 - git_config_get_string("submodule.alternateErrorStrategy", &error_strategy);
1909 - if (error_strategy)
1910 - git_config_set_in_file(p, "submodule.alternateErrorStrategy",
1911 - error_strategy);
1912 -
1913 - free(sm_alternate);
1914 - free(error_strategy);
1915 -
1916 - strbuf_release(&sb);
1917 - free(sm_gitdir);
1918 - free(path);
1919 - free(p);
1934 + clone_submodule(&clone_data);
1935 return 0;
1936 }
1937