Blame


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