Blame


1 c8846eb9 2020-10-12 neels /*
2 c8846eb9 2020-10-12 neels * Copyright (c) 2017 Martin Pieuchot <mpi@openbsd.org>
3 c8846eb9 2020-10-12 neels * Copyright (c) 2018, 2019, 2020 Stefan Sperling <stsp@openbsd.org>
4 c8846eb9 2020-10-12 neels * Copyright (c) 2020 Ori Bernstein <ori@openbsd.org>
5 c8846eb9 2020-10-12 neels *
6 c8846eb9 2020-10-12 neels * Permission to use, copy, modify, and distribute this software for any
7 c8846eb9 2020-10-12 neels * purpose with or without fee is hereby granted, provided that the above
8 c8846eb9 2020-10-12 neels * copyright notice and this permission notice appear in all copies.
9 c8846eb9 2020-10-12 neels *
10 c8846eb9 2020-10-12 neels * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 c8846eb9 2020-10-12 neels * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 c8846eb9 2020-10-12 neels * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 c8846eb9 2020-10-12 neels * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 c8846eb9 2020-10-12 neels * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 c8846eb9 2020-10-12 neels * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 c8846eb9 2020-10-12 neels * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 c8846eb9 2020-10-12 neels */
18 c8846eb9 2020-10-12 neels
19 c8846eb9 2020-10-12 neels #include <sys/queue.h>
20 c8846eb9 2020-10-12 neels #include <sys/types.h>
21 c8846eb9 2020-10-12 neels #include <sys/stat.h>
22 c8846eb9 2020-10-12 neels #include <sys/param.h>
23 c8846eb9 2020-10-12 neels #include <sys/wait.h>
24 c8846eb9 2020-10-12 neels
25 c8846eb9 2020-10-12 neels static const struct got_error *
26 c8846eb9 2020-10-12 neels cmd_import(int argc, char *argv[])
27 c8846eb9 2020-10-12 neels {
28 c8846eb9 2020-10-12 neels const struct got_error *error = NULL;
29 c8846eb9 2020-10-12 neels char *path_dir = NULL, *repo_path = NULL, *logmsg = NULL;
30 c8846eb9 2020-10-12 neels char *gitconfig_path = NULL, *editor = NULL, *author = NULL;
31 c8846eb9 2020-10-12 neels const char *branch_name = "main";
32 c8846eb9 2020-10-12 neels char *refname = NULL, *id_str = NULL, *logmsg_path = NULL;
33 c8846eb9 2020-10-12 neels struct got_repository *repo = NULL;
34 c8846eb9 2020-10-12 neels struct got_reference *branch_ref = NULL, *head_ref = NULL;
35 c8846eb9 2020-10-12 neels struct got_object_id *new_commit_id = NULL;
36 c8846eb9 2020-10-12 neels int ch;
37 c8846eb9 2020-10-12 neels struct got_pathlist_head ignores;
38 c8846eb9 2020-10-12 neels struct got_pathlist_entry *pe;
39 c8846eb9 2020-10-12 neels int preserve_logmsg = 0;
40 c8846eb9 2020-10-12 neels
41 c8846eb9 2020-10-12 neels TAILQ_INIT(&ignores);
42 c8846eb9 2020-10-12 neels
43 c8846eb9 2020-10-12 neels while ((ch = getopt(argc, argv, "b:m:r:I:")) != -1) {
44 c8846eb9 2020-10-12 neels switch (ch) {
45 c8846eb9 2020-10-12 neels case 'b':
46 c8846eb9 2020-10-12 neels branch_name = optarg;
47 c8846eb9 2020-10-12 neels break;
48 c8846eb9 2020-10-12 neels case 'm':
49 c8846eb9 2020-10-12 neels logmsg = strdup(optarg);
50 c8846eb9 2020-10-12 neels if (logmsg == NULL) {
51 c8846eb9 2020-10-12 neels error = got_error_from_errno("strdup");
52 c8846eb9 2020-10-12 neels goto done;
53 c8846eb9 2020-10-12 neels }
54 c8846eb9 2020-10-12 neels break;
55 c8846eb9 2020-10-12 neels case 'r':
56 c8846eb9 2020-10-12 neels repo_path = realpath(optarg, NULL);
57 c8846eb9 2020-10-12 neels if (repo_path == NULL) {
58 c8846eb9 2020-10-12 neels error = got_error_from_errno2("realpath",
59 c8846eb9 2020-10-12 neels optarg);
60 c8846eb9 2020-10-12 neels goto done;
61 c8846eb9 2020-10-12 neels }
62 c8846eb9 2020-10-12 neels break;
63 c8846eb9 2020-10-12 neels case 'I':
64 c8846eb9 2020-10-12 neels if (optarg[0] == '\0')
65 c8846eb9 2020-10-12 neels break;
66 c8846eb9 2020-10-12 neels error = got_pathlist_insert(&pe, &ignores, optarg,
67 c8846eb9 2020-10-12 neels NULL);
68 c8846eb9 2020-10-12 neels if (error)
69 c8846eb9 2020-10-12 neels goto done;
70 c8846eb9 2020-10-12 neels break;
71 c8846eb9 2020-10-12 neels default:
72 c8846eb9 2020-10-12 neels usage_import();
73 c8846eb9 2020-10-12 neels /* NOTREACHED */
74 c8846eb9 2020-10-12 neels }
75 c8846eb9 2020-10-12 neels }
76 c8846eb9 2020-10-12 neels
77 c8846eb9 2020-10-12 neels #ifndef PROFILE
78 c8846eb9 2020-10-12 neels if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
79 c8846eb9 2020-10-12 neels "unveil",
80 c8846eb9 2020-10-12 neels NULL) == -1)
81 c8846eb9 2020-10-12 neels err(1, "pledge");
82 c8846eb9 2020-10-12 neels #endif
83 c8846eb9 2020-10-12 neels if (argc != 1)
84 c8846eb9 2020-10-12 neels usage_import();
85 c8846eb9 2020-10-12 neels
86 c8846eb9 2020-10-12 neels if (repo_path == NULL) {
87 c8846eb9 2020-10-12 neels repo_path = getcwd(NULL, 0);
88 c8846eb9 2020-10-12 neels if (repo_path == NULL)
89 c8846eb9 2020-10-12 neels return got_error_from_errno("getcwd");
90 c8846eb9 2020-10-12 neels }
91 c8846eb9 2020-10-12 neels error = get_gitconfig_path(&gitconfig_path);
92 c8846eb9 2020-10-12 neels if (error)
93 c8846eb9 2020-10-12 neels goto done;
94 c8846eb9 2020-10-12 neels error = got_repo_open(&repo, repo_path, gitconfig_path);
95 c8846eb9 2020-10-12 neels if (error)
96 c8846eb9 2020-10-12 neels goto done;
97 c8846eb9 2020-10-12 neels
98 c8846eb9 2020-10-12 neels error = get_author(&author, repo, NULL);
99 c8846eb9 2020-10-12 neels if (error)
100 c8846eb9 2020-10-12 neels return error;
101 c8846eb9 2020-10-12 neels
102 c8846eb9 2020-10-12 neels /*
103 c8846eb9 2020-10-12 neels * Don't let the user create a branch name with a leading '-'.
104 c8846eb9 2020-10-12 neels * While technically a valid reference name, this case is usually
105 c8846eb9 2020-10-12 neels * an unintended typo.
106 c8846eb9 2020-10-12 neels */
107 c8846eb9 2020-10-12 neels if (branch_name[0] == '-')
108 c8846eb9 2020-10-12 neels return got_error_path(branch_name, GOT_ERR_REF_NAME_MINUS);
109 c8846eb9 2020-10-12 neels
110 c8846eb9 2020-10-12 neels if (asprintf(&refname, "refs/heads/%s", branch_name) == -1) {
111 c8846eb9 2020-10-12 neels error = got_error_from_errno("asprintf");
112 c8846eb9 2020-10-12 neels goto done;
113 c8846eb9 2020-10-12 neels }
114 c8846eb9 2020-10-12 neels
115 c8846eb9 2020-10-12 neels error = got_ref_open(&branch_ref, repo, refname, 0);
116 c8846eb9 2020-10-12 neels if (error) {
117 c8846eb9 2020-10-12 neels if (error->code != GOT_ERR_NOT_REF)
118 c8846eb9 2020-10-12 neels goto done;
119 c8846eb9 2020-10-12 neels } else {
120 c8846eb9 2020-10-12 neels error = got_error_msg(GOT_ERR_BRANCH_EXISTS,
121 c8846eb9 2020-10-12 neels "import target branch already exists");
122 c8846eb9 2020-10-12 neels goto done;
123 c8846eb9 2020-10-12 neels }
124 c8846eb9 2020-10-12 neels
125 c8846eb9 2020-10-12 neels path_dir = realpath(argv[0], NULL);
126 c8846eb9 2020-10-12 neels if (path_dir == NULL) {
127 c8846eb9 2020-10-12 neels error = got_error_from_errno2("realpath", argv[0]);
128 c8846eb9 2020-10-12 neels goto done;
129 c8846eb9 2020-10-12 neels }
130 c8846eb9 2020-10-12 neels got_path_strip_trailing_slashes(path_dir);
131 c8846eb9 2020-10-12 neels
132 c8846eb9 2020-10-12 neels /*
133 c8846eb9 2020-10-12 neels * unveil(2) traverses exec(2); if an editor is used we have
134 c8846eb9 2020-10-12 neels * to apply unveil after the log message has been written.
135 c8846eb9 2020-10-12 neels */
136 c8846eb9 2020-10-12 neels if (logmsg == NULL || strlen(logmsg) == 0) {
137 c8846eb9 2020-10-12 neels error = get_editor(&editor);
138 c8846eb9 2020-10-12 neels if (error)
139 c8846eb9 2020-10-12 neels goto done;
140 c8846eb9 2020-10-12 neels free(logmsg);
141 c8846eb9 2020-10-12 neels error = collect_import_msg(&logmsg, &logmsg_path, editor,
142 c8846eb9 2020-10-12 neels path_dir, refname);
143 c8846eb9 2020-10-12 neels if (error) {
144 c8846eb9 2020-10-12 neels if (error->code != GOT_ERR_COMMIT_MSG_EMPTY &&
145 c8846eb9 2020-10-12 neels logmsg_path != NULL)
146 c8846eb9 2020-10-12 neels preserve_logmsg = 1;
147 c8846eb9 2020-10-12 neels goto done;
148 c8846eb9 2020-10-12 neels }
149 c8846eb9 2020-10-12 neels }
150 c8846eb9 2020-10-12 neels
151 c8846eb9 2020-10-12 neels if (unveil(path_dir, "r") != 0) {
152 c8846eb9 2020-10-12 neels error = got_error_from_errno2("unveil", path_dir);
153 c8846eb9 2020-10-12 neels if (logmsg_path)
154 c8846eb9 2020-10-12 neels preserve_logmsg = 1;
155 c8846eb9 2020-10-12 neels goto done;
156 c8846eb9 2020-10-12 neels }
157 c8846eb9 2020-10-12 neels
158 c8846eb9 2020-10-12 neels error = apply_unveil(got_repo_get_path(repo), 0, NULL);
159 c8846eb9 2020-10-12 neels if (error) {
160 c8846eb9 2020-10-12 neels if (logmsg_path)
161 c8846eb9 2020-10-12 neels preserve_logmsg = 1;
162 c8846eb9 2020-10-12 neels goto done;
163 c8846eb9 2020-10-12 neels }
164 c8846eb9 2020-10-12 neels
165 c8846eb9 2020-10-12 neels error = got_repo_import(&new_commit_id, path_dir, logmsg,
166 c8846eb9 2020-10-12 neels author, &ignores, repo, import_progress, NULL);
167 c8846eb9 2020-10-12 neels if (error) {
168 c8846eb9 2020-10-12 neels if (logmsg_path)
169 c8846eb9 2020-10-12 neels preserve_logmsg = 1;
170 c8846eb9 2020-10-12 neels goto done;
171 c8846eb9 2020-10-12 neels }
172 c8846eb9 2020-10-12 neels
173 c8846eb9 2020-10-12 neels error = got_ref_alloc(&branch_ref, refname, new_commit_id);
174 c8846eb9 2020-10-12 neels if (error) {
175 c8846eb9 2020-10-12 neels if (logmsg_path)
176 c8846eb9 2020-10-12 neels preserve_logmsg = 1;
177 c8846eb9 2020-10-12 neels goto done;
178 c8846eb9 2020-10-12 neels }
179 c8846eb9 2020-10-12 neels
180 c8846eb9 2020-10-12 neels error = got_ref_write(branch_ref, repo);
181 c8846eb9 2020-10-12 neels if (error) {
182 c8846eb9 2020-10-12 neels if (logmsg_path)
183 c8846eb9 2020-10-12 neels preserve_logmsg = 1;
184 c8846eb9 2020-10-12 neels goto done;
185 c8846eb9 2020-10-12 neels }
186 c8846eb9 2020-10-12 neels
187 c8846eb9 2020-10-12 neels error = got_object_id_str(&id_str, new_commit_id);
188 c8846eb9 2020-10-12 neels if (error) {
189 c8846eb9 2020-10-12 neels if (logmsg_path)
190 c8846eb9 2020-10-12 neels preserve_logmsg = 1;
191 c8846eb9 2020-10-12 neels goto done;
192 c8846eb9 2020-10-12 neels }
193 c8846eb9 2020-10-12 neels
194 c8846eb9 2020-10-12 neels error = got_ref_open(&head_ref, repo, GOT_REF_HEAD, 0);
195 c8846eb9 2020-10-12 neels if (error) {
196 c8846eb9 2020-10-12 neels if (error->code != GOT_ERR_NOT_REF) {
197 c8846eb9 2020-10-12 neels if (logmsg_path)
198 c8846eb9 2020-10-12 neels preserve_logmsg = 1;
199 c8846eb9 2020-10-12 neels goto done;
200 c8846eb9 2020-10-12 neels }
201 c8846eb9 2020-10-12 neels
202 c8846eb9 2020-10-12 neels error = got_ref_alloc_symref(&head_ref, GOT_REF_HEAD,
203 c8846eb9 2020-10-12 neels branch_ref);
204 c8846eb9 2020-10-12 neels if (error) {
205 c8846eb9 2020-10-12 neels if (logmsg_path)
206 c8846eb9 2020-10-12 neels preserve_logmsg = 1;
207 c8846eb9 2020-10-12 neels goto done;
208 c8846eb9 2020-10-12 neels }
209 c8846eb9 2020-10-12 neels
210 c8846eb9 2020-10-12 neels error = got_ref_write(head_ref, repo);
211 c8846eb9 2020-10-12 neels if (error) {
212 c8846eb9 2020-10-12 neels if (logmsg_path)
213 c8846eb9 2020-10-12 neels preserve_logmsg = 1;
214 c8846eb9 2020-10-12 neels goto done;
215 c8846eb9 2020-10-12 neels }
216 c8846eb9 2020-10-12 neels }
217 c8846eb9 2020-10-12 neels
218 c8846eb9 2020-10-12 neels printf("Created branch %s with commit %s\n",
219 c8846eb9 2020-10-12 neels got_ref_get_name(branch_ref), id_str);
220 c8846eb9 2020-10-12 neels done:
221 c8846eb9 2020-10-12 neels if (preserve_logmsg) {
222 c8846eb9 2020-10-12 neels fprintf(stderr, "%s: log message preserved in %s\n",
223 c8846eb9 2020-10-12 neels getprogname(), logmsg_path);
224 c8846eb9 2020-10-12 neels } else if (logmsg_path && unlink(logmsg_path) == -1 && error == NULL)
225 c8846eb9 2020-10-12 neels error = got_error_from_errno2("unlink", logmsg_path);
226 c8846eb9 2020-10-12 neels free(logmsg);
227 c8846eb9 2020-10-12 neels free(logmsg_path);
228 c8846eb9 2020-10-12 neels free(repo_path);
229 c8846eb9 2020-10-12 neels free(editor);
230 c8846eb9 2020-10-12 neels free(refname);
231 c8846eb9 2020-10-12 neels free(new_commit_id);
232 c8846eb9 2020-10-12 neels free(id_str);
233 c8846eb9 2020-10-12 neels free(author);
234 c8846eb9 2020-10-12 neels free(gitconfig_path);
235 c8846eb9 2020-10-12 neels if (branch_ref)
236 c8846eb9 2020-10-12 neels got_ref_close(branch_ref);
237 c8846eb9 2020-10-12 neels if (head_ref)
238 c8846eb9 2020-10-12 neels got_ref_close(head_ref);
239 c8846eb9 2020-10-12 neels return error;
240 c8846eb9 2020-10-12 neels }
241 c8846eb9 2020-10-12 neels
242 c8846eb9 2020-10-12 neels __dead static void
243 c8846eb9 2020-10-12 neels usage_clone(void)
244 c8846eb9 2020-10-12 neels {
245 c8846eb9 2020-10-12 neels fprintf(stderr, "usage: %s clone [-a] [-b branch] [-l] [-m] [-q] [-v] "
246 c8846eb9 2020-10-12 neels "[-R reference] repository-url [directory]\n", getprogname());
247 c8846eb9 2020-10-12 neels exit(1);
248 c8846eb9 2020-10-12 neels }
249 c8846eb9 2020-10-12 neels
250 c8846eb9 2020-10-12 neels static const struct got_error *
251 c8846eb9 2020-10-12 neels cmd_clone(int argc, char *argv[])
252 c8846eb9 2020-10-12 neels {
253 c8846eb9 2020-10-12 neels const struct got_error *error = NULL;
254 c8846eb9 2020-10-12 neels const char *uri, *dirname;
255 c8846eb9 2020-10-12 neels char *proto, *host, *port, *repo_name, *server_path;
256 c8846eb9 2020-10-12 neels char *default_destdir = NULL, *id_str = NULL;
257 c8846eb9 2020-10-12 neels const char *repo_path;
258 c8846eb9 2020-10-12 neels struct got_repository *repo = NULL;
259 c8846eb9 2020-10-12 neels struct got_pathlist_head refs, symrefs, wanted_branches, wanted_refs;
260 c8846eb9 2020-10-12 neels struct got_pathlist_entry *pe;
261 c8846eb9 2020-10-12 neels struct got_object_id *pack_hash = NULL;
262 c8846eb9 2020-10-12 neels int ch, fetchfd = -1, fetchstatus;
263 c8846eb9 2020-10-12 neels pid_t fetchpid = -1;
264 c8846eb9 2020-10-12 neels x
265 c8846eb9 2020-10-12 neels
266 c8846eb9 2020-10-12 neels /* Create got.conf(5). */
267 c8846eb9 2020-10-12 neels gotconfig_path = got_repo_get_path_gotconfig(repo);
268 c8846eb9 2020-10-12 neels if (gotconfig_path == NULL) {
269 c8846eb9 2020-10-12 neels error = got_error_from_errno("got_repo_get_path_gotconfig");
270 c8846eb9 2020-10-12 neels goto done;
271 c8846eb9 2020-10-12 neels }
272 c8846eb9 2020-10-12 neels gotconfig_file = fopen(gotconfig_path, "a");
273 c8846eb9 2020-10-12 neels if (gotconfig_file == NULL) {
274 c8846eb9 2020-10-12 neels error = got_error_from_errno2("fopen", gotconfig_path);
275 c8846eb9 2020-10-12 neels goto done;
276 c8846eb9 2020-10-12 neels }
277 c8846eb9 2020-10-12 neels got_path_strip_trailing_slashes(server_path);
278 c8846eb9 2020-10-12 neels if (asprintf(&gotconfig,
279 c8846eb9 2020-10-12 neels "remote \"%s\" {\n"
280 c8846eb9 2020-10-12 neels "\tserver %s\n"
281 c8846eb9 2020-10-12 neels "\tprotocol %s\n"
282 c8846eb9 2020-10-12 neels "%s%s%s"
283 c8846eb9 2020-10-12 neels "\trepository \"%s\"\n"
284 c8846eb9 2020-10-12 neels "%s"
285 c8846eb9 2020-10-12 neels "}\n",
286 c8846eb9 2020-10-12 neels GOT_FETCH_DEFAULT_REMOTE_NAME, host, proto,
287 c8846eb9 2020-10-12 neels port ? "\tport " : "", port ? port : "", port ? "\n" : "",
288 c8846eb9 2020-10-12 neels server_path,
289 c8846eb9 2020-10-12 neels mirror_references ? "\tmirror-references yes\n" : "") == -1) {
290 c8846eb9 2020-10-12 neels error = got_error_from_errno("asprintf");
291 c8846eb9 2020-10-12 neels goto done;
292 c8846eb9 2020-10-12 neels }
293 c8846eb9 2020-10-12 neels n = fwrite(gotconfig, 1, strlen(gotconfig), gotconfig_file);
294 c8846eb9 2020-10-12 neels if (n != strlen(gotconfig)) {
295 c8846eb9 2020-10-12 neels error = got_ferror(gotconfig_file, GOT_ERR_IO);
296 c8846eb9 2020-10-12 neels goto done;
297 c8846eb9 2020-10-12 neels }
298 c8846eb9 2020-10-12 neels }