mirror of
https://github.com/freebsd/freebsd-src
synced 2024-10-04 15:40:44 +00:00
59c8e88e72
git-subtree-dir: contrib/libdiff git-subtree-mainline:f6d489f402
git-subtree-split:9eb461aa4b
Reviewed by: imp Sponsored by: Klara, Inc.
299 lines
7.5 KiB
Plaintext
299 lines
7.5 KiB
Plaintext
/*
|
|
* Copyright (c) 2017 Martin Pieuchot <mpi@openbsd.org>
|
|
* Copyright (c) 2018, 2019, 2020 Stefan Sperling <stsp@openbsd.org>
|
|
* Copyright (c) 2020 Ori Bernstein <ori@openbsd.org>
|
|
*
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
|
|
#include <sys/queue.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/param.h>
|
|
#include <sys/wait.h>
|
|
|
|
static const struct got_error *
|
|
cmd_import(int argc, char *argv[])
|
|
{
|
|
const struct got_error *error = NULL;
|
|
char *path_dir = NULL, *repo_path = NULL, *logmsg = NULL;
|
|
char *gitconfig_path = NULL, *editor = NULL, *author = NULL;
|
|
const char *branch_name = "main";
|
|
char *refname = NULL, *id_str = NULL, *logmsg_path = NULL;
|
|
struct got_repository *repo = NULL;
|
|
struct got_reference *branch_ref = NULL, *head_ref = NULL;
|
|
struct got_object_id *new_commit_id = NULL;
|
|
int ch;
|
|
struct got_pathlist_head ignores;
|
|
struct got_pathlist_entry *pe;
|
|
int preserve_logmsg = 0;
|
|
|
|
TAILQ_INIT(&ignores);
|
|
|
|
while ((ch = getopt(argc, argv, "b:m:r:I:")) != -1) {
|
|
switch (ch) {
|
|
case 'b':
|
|
branch_name = optarg;
|
|
break;
|
|
case 'm':
|
|
logmsg = strdup(optarg);
|
|
if (logmsg == NULL) {
|
|
error = got_error_from_errno("strdup");
|
|
goto done;
|
|
}
|
|
break;
|
|
case 'r':
|
|
repo_path = realpath(optarg, NULL);
|
|
if (repo_path == NULL) {
|
|
error = got_error_from_errno2("realpath",
|
|
optarg);
|
|
goto done;
|
|
}
|
|
break;
|
|
case 'I':
|
|
if (optarg[0] == '\0')
|
|
break;
|
|
error = got_pathlist_insert(&pe, &ignores, optarg,
|
|
NULL);
|
|
if (error)
|
|
goto done;
|
|
break;
|
|
default:
|
|
usage_import();
|
|
/* NOTREACHED */
|
|
}
|
|
}
|
|
|
|
#ifndef PROFILE
|
|
if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
|
|
"unveil",
|
|
NULL) == -1)
|
|
err(1, "pledge");
|
|
#endif
|
|
if (argc != 1)
|
|
usage_import();
|
|
|
|
if (repo_path == NULL) {
|
|
repo_path = getcwd(NULL, 0);
|
|
if (repo_path == NULL)
|
|
return got_error_from_errno("getcwd");
|
|
}
|
|
error = get_gitconfig_path(&gitconfig_path);
|
|
if (error)
|
|
goto done;
|
|
error = got_repo_open(&repo, repo_path, gitconfig_path);
|
|
if (error)
|
|
goto done;
|
|
|
|
error = get_author(&author, repo, NULL);
|
|
if (error)
|
|
return error;
|
|
|
|
/*
|
|
* Don't let the user create a branch name with a leading '-'.
|
|
* While technically a valid reference name, this case is usually
|
|
* an unintended typo.
|
|
*/
|
|
if (branch_name[0] == '-')
|
|
return got_error_path(branch_name, GOT_ERR_REF_NAME_MINUS);
|
|
|
|
if (asprintf(&refname, "refs/heads/%s", branch_name) == -1) {
|
|
error = got_error_from_errno("asprintf");
|
|
goto done;
|
|
}
|
|
|
|
error = got_ref_open(&branch_ref, repo, refname, 0);
|
|
if (error) {
|
|
if (error->code != GOT_ERR_NOT_REF)
|
|
goto done;
|
|
} else {
|
|
error = got_error_msg(GOT_ERR_BRANCH_EXISTS,
|
|
"import target branch already exists");
|
|
goto done;
|
|
}
|
|
|
|
path_dir = realpath(argv[0], NULL);
|
|
if (path_dir == NULL) {
|
|
error = got_error_from_errno2("realpath", argv[0]);
|
|
goto done;
|
|
}
|
|
got_path_strip_trailing_slashes(path_dir);
|
|
|
|
/*
|
|
* unveil(2) traverses exec(2); if an editor is used we have
|
|
* to apply unveil after the log message has been written.
|
|
*/
|
|
if (logmsg == NULL || strlen(logmsg) == 0) {
|
|
error = get_editor(&editor);
|
|
if (error)
|
|
goto done;
|
|
free(logmsg);
|
|
error = collect_import_msg(&logmsg, &logmsg_path, editor,
|
|
path_dir, refname);
|
|
if (error) {
|
|
if (error->code != GOT_ERR_COMMIT_MSG_EMPTY &&
|
|
logmsg_path != NULL)
|
|
preserve_logmsg = 1;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
if (unveil(path_dir, "r") != 0) {
|
|
error = got_error_from_errno2("unveil", path_dir);
|
|
if (logmsg_path)
|
|
preserve_logmsg = 1;
|
|
goto done;
|
|
}
|
|
|
|
error = apply_unveil(got_repo_get_path(repo), 0, NULL);
|
|
if (error) {
|
|
if (logmsg_path)
|
|
preserve_logmsg = 1;
|
|
goto done;
|
|
}
|
|
|
|
error = got_repo_import(&new_commit_id, path_dir, logmsg,
|
|
author, &ignores, repo, import_progress, NULL);
|
|
if (error) {
|
|
if (logmsg_path)
|
|
preserve_logmsg = 1;
|
|
goto done;
|
|
}
|
|
|
|
error = got_ref_alloc(&branch_ref, refname, new_commit_id);
|
|
if (error) {
|
|
if (logmsg_path)
|
|
preserve_logmsg = 1;
|
|
goto done;
|
|
}
|
|
|
|
error = got_ref_write(branch_ref, repo);
|
|
if (error) {
|
|
if (logmsg_path)
|
|
preserve_logmsg = 1;
|
|
goto done;
|
|
}
|
|
|
|
error = got_object_id_str(&id_str, new_commit_id);
|
|
if (error) {
|
|
if (logmsg_path)
|
|
preserve_logmsg = 1;
|
|
goto done;
|
|
}
|
|
|
|
error = got_ref_open(&head_ref, repo, GOT_REF_HEAD, 0);
|
|
if (error) {
|
|
if (error->code != GOT_ERR_NOT_REF) {
|
|
if (logmsg_path)
|
|
preserve_logmsg = 1;
|
|
goto done;
|
|
}
|
|
|
|
error = got_ref_alloc_symref(&head_ref, GOT_REF_HEAD,
|
|
branch_ref);
|
|
if (error) {
|
|
if (logmsg_path)
|
|
preserve_logmsg = 1;
|
|
goto done;
|
|
}
|
|
|
|
error = got_ref_write(head_ref, repo);
|
|
if (error) {
|
|
if (logmsg_path)
|
|
preserve_logmsg = 1;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
printf("Created branch %s with commit %s\n",
|
|
got_ref_get_name(branch_ref), id_str);
|
|
done:
|
|
if (preserve_logmsg) {
|
|
fprintf(stderr, "%s: log message preserved in %s\n",
|
|
getprogname(), logmsg_path);
|
|
} else if (logmsg_path && unlink(logmsg_path) == -1 && error == NULL)
|
|
error = got_error_from_errno2("unlink", logmsg_path);
|
|
free(logmsg);
|
|
free(logmsg_path);
|
|
free(repo_path);
|
|
free(editor);
|
|
free(refname);
|
|
free(new_commit_id);
|
|
free(id_str);
|
|
free(author);
|
|
free(gitconfig_path);
|
|
if (branch_ref)
|
|
got_ref_close(branch_ref);
|
|
if (head_ref)
|
|
got_ref_close(head_ref);
|
|
return error;
|
|
}
|
|
|
|
__dead static void
|
|
usage_clone(void)
|
|
{
|
|
fprintf(stderr, "usage: %s clone [-a] [-b branch] [-l] [-m] [-q] [-v] "
|
|
"[-R reference] repository-url [directory]\n", getprogname());
|
|
exit(1);
|
|
}
|
|
|
|
static const struct got_error *
|
|
cmd_clone(int argc, char *argv[])
|
|
{
|
|
const struct got_error *error = NULL;
|
|
const char *uri, *dirname;
|
|
char *proto, *host, *port, *repo_name, *server_path;
|
|
char *default_destdir = NULL, *id_str = NULL;
|
|
const char *repo_path;
|
|
struct got_repository *repo = NULL;
|
|
struct got_pathlist_head refs, symrefs, wanted_branches, wanted_refs;
|
|
struct got_pathlist_entry *pe;
|
|
struct got_object_id *pack_hash = NULL;
|
|
int ch, fetchfd = -1, fetchstatus;
|
|
pid_t fetchpid = -1;
|
|
x
|
|
|
|
/* Create got.conf(5). */
|
|
gotconfig_path = got_repo_get_path_gotconfig(repo);
|
|
if (gotconfig_path == NULL) {
|
|
error = got_error_from_errno("got_repo_get_path_gotconfig");
|
|
goto done;
|
|
}
|
|
gotconfig_file = fopen(gotconfig_path, "a");
|
|
if (gotconfig_file == NULL) {
|
|
error = got_error_from_errno2("fopen", gotconfig_path);
|
|
goto done;
|
|
}
|
|
got_path_strip_trailing_slashes(server_path);
|
|
if (asprintf(&gotconfig,
|
|
"remote \"%s\" {\n"
|
|
"\tserver %s\n"
|
|
"\tprotocol %s\n"
|
|
"%s%s%s"
|
|
"\trepository \"%s\"\n"
|
|
"%s"
|
|
"}\n",
|
|
GOT_FETCH_DEFAULT_REMOTE_NAME, host, proto,
|
|
port ? "\tport " : "", port ? port : "", port ? "\n" : "",
|
|
server_path,
|
|
mirror_references ? "\tmirror-references yes\n" : "") == -1) {
|
|
error = got_error_from_errno("asprintf");
|
|
goto done;
|
|
}
|
|
n = fwrite(gotconfig, 1, strlen(gotconfig), gotconfig_file);
|
|
if (n != strlen(gotconfig)) {
|
|
error = got_ferror(gotconfig_file, GOT_ERR_IO);
|
|
goto done;
|
|
}
|
|
}
|