diff options
author | Edward Thomson <ethomson@edwardthomson.com> | 2022-02-26 22:17:36 -0500 |
---|---|---|
committer | Edward Thomson <ethomson@edwardthomson.com> | 2022-02-26 22:17:36 -0500 |
commit | 4014022414255de31fae5b8e04d92dc305511ad2 (patch) | |
tree | e3c2594abca2854b6912b29dfe233d2f58765475 | |
parent | a42808302cb3a942e0b27394e70abba873fc088a (diff) | |
download | libgit2-4014022414255de31fae5b8e04d92dc305511ad2.tar.gz |
cli: add a clone command
-rw-r--r-- | src/cli/cmd.h | 1 | ||||
-rw-r--r-- | src/cli/cmd_clone.c | 122 | ||||
-rw-r--r-- | src/cli/main.c | 1 |
3 files changed, 124 insertions, 0 deletions
diff --git a/src/cli/cmd.h b/src/cli/cmd.h index 664b5021a..8b1a1b38f 100644 --- a/src/cli/cmd.h +++ b/src/cli/cmd.h @@ -26,6 +26,7 @@ extern const cli_cmd_spec *cli_cmd_spec_byname(const char *name); /* Commands */ extern int cmd_cat_file(int argc, char **argv); +extern int cmd_clone(int argc, char **argv); extern int cmd_hash_object(int argc, char **argv); extern int cmd_help(int argc, char **argv); diff --git a/src/cli/cmd_clone.c b/src/cli/cmd_clone.c new file mode 100644 index 000000000..4dd5db858 --- /dev/null +++ b/src/cli/cmd_clone.c @@ -0,0 +1,122 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include <git2.h> +#include "cli.h" +#include "cmd.h" +#include "fs_path.h" +#include "futils.h" + +#define COMMAND_NAME "clone" + +static int show_help; +static int quiet; +static bool local_path_exists; + +static char *remote_path, *local_path; + +static const cli_opt_spec opts[] = { + { CLI_OPT_TYPE_SWITCH, "help", 0, &show_help, 1, + CLI_OPT_USAGE_HIDDEN | CLI_OPT_USAGE_STOP_PARSING, NULL, + "display help about the " COMMAND_NAME " command" }, + + { CLI_OPT_TYPE_BOOL, "quiet", 'q', &quiet, 0, + CLI_OPT_USAGE_DEFAULT, NULL, "do not display progress output" }, + + { CLI_OPT_TYPE_LITERAL }, + { CLI_OPT_TYPE_ARG, "repository", 0, &remote_path, 0, + CLI_OPT_USAGE_REQUIRED, "repository", "path to repository to clone" }, + { CLI_OPT_TYPE_ARG, "directory", 0, &local_path, 0, + CLI_OPT_USAGE_DEFAULT, "directory", "directory to clone into" }, + { 0 }, +}; + +static void print_help(void) +{ + cli_opt_usage_fprint(stdout, PROGRAM_NAME, COMMAND_NAME, opts); + printf("\n"); + + printf("Clone an existing repository into a local directory.\n"); + printf("\n"); + + printf("Options:\n"); + + cli_opt_help_fprint(stdout, opts); +} + +static char *compute_local_path(const char *orig_path) +{ + const char *slash; + char *local_path; + + if ((slash = strrchr(orig_path, '/')) == NULL && + (slash = strrchr(orig_path, '\\')) == NULL) + local_path = git__strdup(orig_path); + else + local_path = git__strdup(slash + 1); + + return local_path; +} + +static bool validate_local_path(const char *path) +{ + if (!git_fs_path_exists(path)) + return false; + + if (!git_fs_path_isdir(path) || !git_fs_path_is_empty_dir(path)) + cli_die("fatal: destination path '%s' already exists and is not an empty directory.\n", path); + + return true; +} + +static void cleanup(void) +{ + int rmdir_flags = GIT_RMDIR_REMOVE_FILES; + + if (local_path_exists) + rmdir_flags |= GIT_RMDIR_SKIP_ROOT; + + if (!git_fs_path_isdir(local_path)) + return; + + if (git_futils_rmdir_r(local_path, NULL, rmdir_flags) < 0) + cli_die_git(); +} + +int cmd_clone(int argc, char **argv) +{ + git_clone_options clone_opts = GIT_CLONE_OPTIONS_INIT; + git_repository *repo = NULL; + cli_opt invalid_opt; + char *computed_path = NULL; + + if (cli_opt_parse(&invalid_opt, opts, argv + 1, argc - 1, CLI_OPT_PARSE_GNU)) + return cli_opt_usage_error(COMMAND_NAME, opts, &invalid_opt); + + if (show_help) { + print_help(); + return 0; + } + + if (!local_path) + local_path = computed_path = compute_local_path(remote_path); + + local_path_exists = validate_local_path(local_path); + + if (!quiet) + printf("Cloning into '%s'...\n", local_path); + + if (git_clone(&repo, remote_path, local_path, &clone_opts) < 0) { + cleanup(); + cli_die_git(); + } + + git__free(computed_path); + git_repository_free(repo); + + return 0; +} diff --git a/src/cli/main.c b/src/cli/main.c index 08abb324f..72f577c7a 100644 --- a/src/cli/main.c +++ b/src/cli/main.c @@ -29,6 +29,7 @@ const cli_opt_spec cli_common_opts[] = { const cli_cmd_spec cli_cmds[] = { { "cat-file", cmd_cat_file, "Display an object in the repository" }, + { "clone", cmd_clone, "Clone an existing repository into a local directory" }, { "hash-object", cmd_hash_object, "Hash a raw object and product its object ID" }, { "help", cmd_help, "Display help information" }, { NULL } |