builtin-am: apply patch with git-apply
[git/git.git] / builtin / am.c
CommitLineData
73c2779f
PT
1/*
2 * Builtin "git am"
3 *
4 * Based on git-am.sh by Junio C Hamano.
5 */
6#include "cache.h"
7#include "builtin.h"
8#include "exec_cmd.h"
8c3bd9e2
PT
9#include "parse-options.h"
10#include "dir.h"
11c2177f 11#include "run-command.h"
3e20dcf3 12#include "quote.h"
38a824fe 13#include "lockfile.h"
3e20dcf3
PT
14
15/**
16 * Returns 1 if the file is empty or does not exist, 0 otherwise.
17 */
18static int is_empty_file(const char *filename)
19{
20 struct stat st;
21
22 if (stat(filename, &st) < 0) {
23 if (errno == ENOENT)
24 return 1;
25 die_errno(_("could not stat %s"), filename);
26 }
27
28 return !st.st_size;
29}
11c2177f 30
c29807b2
PT
31/**
32 * Like strbuf_getline(), but treats both '\n' and "\r\n" as line terminators.
33 */
34static int strbuf_getline_crlf(struct strbuf *sb, FILE *fp)
35{
36 if (strbuf_getwholeline(sb, fp, '\n'))
37 return EOF;
38 if (sb->buf[sb->len - 1] == '\n') {
39 strbuf_setlen(sb, sb->len - 1);
40 if (sb->len > 0 && sb->buf[sb->len - 1] == '\r')
41 strbuf_setlen(sb, sb->len - 1);
42 }
43 return 0;
44}
45
38a824fe
PT
46/**
47 * Returns the length of the first line of msg.
48 */
49static int linelen(const char *msg)
50{
51 return strchrnul(msg, '\n') - msg;
52}
53
11c2177f
PT
54enum patch_format {
55 PATCH_FORMAT_UNKNOWN = 0,
56 PATCH_FORMAT_MBOX
57};
8c3bd9e2
PT
58
59struct am_state {
60 /* state directory path */
61 char *dir;
62
63 /* current and last patch numbers, 1-indexed */
64 int cur;
65 int last;
11c2177f 66
3e20dcf3
PT
67 /* commit metadata and message */
68 char *author_name;
69 char *author_email;
70 char *author_date;
71 char *msg;
72 size_t msg_len;
73
11c2177f
PT
74 /* number of digits in patch filename */
75 int prec;
8c3bd9e2
PT
76};
77
78/**
79 * Initializes am_state with the default values. The state directory is set to
80 * dir.
81 */
82static void am_state_init(struct am_state *state, const char *dir)
83{
84 memset(state, 0, sizeof(*state));
85
86 assert(dir);
87 state->dir = xstrdup(dir);
11c2177f
PT
88
89 state->prec = 4;
8c3bd9e2
PT
90}
91
92/**
93 * Releases memory allocated by an am_state.
94 */
95static void am_state_release(struct am_state *state)
96{
97 free(state->dir);
3e20dcf3
PT
98 free(state->author_name);
99 free(state->author_email);
100 free(state->author_date);
101 free(state->msg);
8c3bd9e2
PT
102}
103
104/**
105 * Returns path relative to the am_state directory.
106 */
107static inline const char *am_path(const struct am_state *state, const char *path)
108{
109 return mkpath("%s/%s", state->dir, path);
110}
111
112/**
113 * Returns 1 if there is an am session in progress, 0 otherwise.
114 */
115static int am_in_progress(const struct am_state *state)
116{
117 struct stat st;
118
119 if (lstat(state->dir, &st) < 0 || !S_ISDIR(st.st_mode))
120 return 0;
121 if (lstat(am_path(state, "last"), &st) || !S_ISREG(st.st_mode))
122 return 0;
123 if (lstat(am_path(state, "next"), &st) || !S_ISREG(st.st_mode))
124 return 0;
125 return 1;
126}
127
128/**
129 * Reads the contents of `file` in the `state` directory into `sb`. Returns the
130 * number of bytes read on success, -1 if the file does not exist. If `trim` is
131 * set, trailing whitespace will be removed.
132 */
133static int read_state_file(struct strbuf *sb, const struct am_state *state,
134 const char *file, int trim)
135{
136 strbuf_reset(sb);
137
138 if (strbuf_read_file(sb, am_path(state, file), 0) >= 0) {
139 if (trim)
140 strbuf_trim(sb);
141
142 return sb->len;
143 }
144
145 if (errno == ENOENT)
146 return -1;
147
148 die_errno(_("could not read '%s'"), am_path(state, file));
149}
150
3e20dcf3
PT
151/**
152 * Reads a KEY=VALUE shell variable assignment from `fp`, returning the VALUE
153 * as a newly-allocated string. VALUE must be a quoted string, and the KEY must
154 * match `key`. Returns NULL on failure.
155 *
156 * This is used by read_author_script() to read the GIT_AUTHOR_* variables from
157 * the author-script.
158 */
159static char *read_shell_var(FILE *fp, const char *key)
160{
161 struct strbuf sb = STRBUF_INIT;
162 const char *str;
163
164 if (strbuf_getline(&sb, fp, '\n'))
165 goto fail;
166
167 if (!skip_prefix(sb.buf, key, &str))
168 goto fail;
169
170 if (!skip_prefix(str, "=", &str))
171 goto fail;
172
173 strbuf_remove(&sb, 0, str - sb.buf);
174
175 str = sq_dequote(sb.buf);
176 if (!str)
177 goto fail;
178
179 return strbuf_detach(&sb, NULL);
180
181fail:
182 strbuf_release(&sb);
183 return NULL;
184}
185
186/**
187 * Reads and parses the state directory's "author-script" file, and sets
188 * state->author_name, state->author_email and state->author_date accordingly.
189 * Returns 0 on success, -1 if the file could not be parsed.
190 *
191 * The author script is of the format:
192 *
193 * GIT_AUTHOR_NAME='$author_name'
194 * GIT_AUTHOR_EMAIL='$author_email'
195 * GIT_AUTHOR_DATE='$author_date'
196 *
197 * where $author_name, $author_email and $author_date are quoted. We are strict
198 * with our parsing, as the file was meant to be eval'd in the old git-am.sh
199 * script, and thus if the file differs from what this function expects, it is
200 * better to bail out than to do something that the user does not expect.
201 */
202static int read_author_script(struct am_state *state)
203{
204 const char *filename = am_path(state, "author-script");
205 FILE *fp;
206
207 assert(!state->author_name);
208 assert(!state->author_email);
209 assert(!state->author_date);
210
211 fp = fopen(filename, "r");
212 if (!fp) {
213 if (errno == ENOENT)
214 return 0;
215 die_errno(_("could not open '%s' for reading"), filename);
216 }
217
218 state->author_name = read_shell_var(fp, "GIT_AUTHOR_NAME");
219 if (!state->author_name) {
220 fclose(fp);
221 return -1;
222 }
223
224 state->author_email = read_shell_var(fp, "GIT_AUTHOR_EMAIL");
225 if (!state->author_email) {
226 fclose(fp);
227 return -1;
228 }
229
230 state->author_date = read_shell_var(fp, "GIT_AUTHOR_DATE");
231 if (!state->author_date) {
232 fclose(fp);
233 return -1;
234 }
235
236 if (fgetc(fp) != EOF) {
237 fclose(fp);
238 return -1;
239 }
240
241 fclose(fp);
242 return 0;
243}
244
245/**
246 * Saves state->author_name, state->author_email and state->author_date in the
247 * state directory's "author-script" file.
248 */
249static void write_author_script(const struct am_state *state)
250{
251 struct strbuf sb = STRBUF_INIT;
252
253 strbuf_addstr(&sb, "GIT_AUTHOR_NAME=");
254 sq_quote_buf(&sb, state->author_name);
255 strbuf_addch(&sb, '\n');
256
257 strbuf_addstr(&sb, "GIT_AUTHOR_EMAIL=");
258 sq_quote_buf(&sb, state->author_email);
259 strbuf_addch(&sb, '\n');
260
261 strbuf_addstr(&sb, "GIT_AUTHOR_DATE=");
262 sq_quote_buf(&sb, state->author_date);
263 strbuf_addch(&sb, '\n');
264
265 write_file(am_path(state, "author-script"), 1, "%s", sb.buf);
266
267 strbuf_release(&sb);
268}
269
270/**
271 * Reads the commit message from the state directory's "final-commit" file,
272 * setting state->msg to its contents and state->msg_len to the length of its
273 * contents in bytes.
274 *
275 * Returns 0 on success, -1 if the file does not exist.
276 */
277static int read_commit_msg(struct am_state *state)
278{
279 struct strbuf sb = STRBUF_INIT;
280
281 assert(!state->msg);
282
283 if (read_state_file(&sb, state, "final-commit", 0) < 0) {
284 strbuf_release(&sb);
285 return -1;
286 }
287
288 state->msg = strbuf_detach(&sb, &state->msg_len);
289 return 0;
290}
291
292/**
293 * Saves state->msg in the state directory's "final-commit" file.
294 */
295static void write_commit_msg(const struct am_state *state)
296{
297 int fd;
298 const char *filename = am_path(state, "final-commit");
299
300 fd = xopen(filename, O_WRONLY | O_CREAT, 0666);
301 if (write_in_full(fd, state->msg, state->msg_len) < 0)
302 die_errno(_("could not write to %s"), filename);
303 close(fd);
304}
305
8c3bd9e2
PT
306/**
307 * Loads state from disk.
308 */
309static void am_load(struct am_state *state)
310{
311 struct strbuf sb = STRBUF_INIT;
312
313 if (read_state_file(&sb, state, "next", 1) < 0)
314 die("BUG: state file 'next' does not exist");
315 state->cur = strtol(sb.buf, NULL, 10);
316
317 if (read_state_file(&sb, state, "last", 1) < 0)
318 die("BUG: state file 'last' does not exist");
319 state->last = strtol(sb.buf, NULL, 10);
320
3e20dcf3
PT
321 if (read_author_script(state) < 0)
322 die(_("could not parse author script"));
323
324 read_commit_msg(state);
325
8c3bd9e2
PT
326 strbuf_release(&sb);
327}
328
329/**
330 * Removes the am_state directory, forcefully terminating the current am
331 * session.
332 */
333static void am_destroy(const struct am_state *state)
334{
335 struct strbuf sb = STRBUF_INIT;
336
337 strbuf_addstr(&sb, state->dir);
338 remove_dir_recursively(&sb, 0);
339 strbuf_release(&sb);
340}
341
c29807b2
PT
342/**
343 * Determines if the file looks like a piece of RFC2822 mail by grabbing all
344 * non-indented lines and checking if they look like they begin with valid
345 * header field names.
346 *
347 * Returns 1 if the file looks like a piece of mail, 0 otherwise.
348 */
349static int is_mail(FILE *fp)
350{
351 const char *header_regex = "^[!-9;-~]+:";
352 struct strbuf sb = STRBUF_INIT;
353 regex_t regex;
354 int ret = 1;
355
356 if (fseek(fp, 0L, SEEK_SET))
357 die_errno(_("fseek failed"));
358
359 if (regcomp(&regex, header_regex, REG_NOSUB | REG_EXTENDED))
360 die("invalid pattern: %s", header_regex);
361
362 while (!strbuf_getline_crlf(&sb, fp)) {
363 if (!sb.len)
364 break; /* End of header */
365
366 /* Ignore indented folded lines */
367 if (*sb.buf == '\t' || *sb.buf == ' ')
368 continue;
369
370 /* It's a header if it matches header_regex */
371 if (regexec(&regex, sb.buf, 0, NULL, 0)) {
372 ret = 0;
373 goto done;
374 }
375 }
376
377done:
378 regfree(&regex);
379 strbuf_release(&sb);
380 return ret;
381}
382
383/**
384 * Attempts to detect the patch_format of the patches contained in `paths`,
385 * returning the PATCH_FORMAT_* enum value. Returns PATCH_FORMAT_UNKNOWN if
386 * detection fails.
387 */
388static int detect_patch_format(const char **paths)
389{
390 enum patch_format ret = PATCH_FORMAT_UNKNOWN;
391 struct strbuf l1 = STRBUF_INIT;
392 FILE *fp;
393
394 /*
395 * We default to mbox format if input is from stdin and for directories
396 */
397 if (!*paths || !strcmp(*paths, "-") || is_directory(*paths))
398 return PATCH_FORMAT_MBOX;
399
400 /*
401 * Otherwise, check the first few lines of the first patch, starting
402 * from the first non-blank line, to try to detect its format.
403 */
404
405 fp = xfopen(*paths, "r");
406
407 while (!strbuf_getline_crlf(&l1, fp)) {
408 if (l1.len)
409 break;
410 }
411
412 if (starts_with(l1.buf, "From ") || starts_with(l1.buf, "From: ")) {
413 ret = PATCH_FORMAT_MBOX;
414 goto done;
415 }
416
417 if (l1.len && is_mail(fp)) {
418 ret = PATCH_FORMAT_MBOX;
419 goto done;
420 }
421
422done:
423 fclose(fp);
424 strbuf_release(&l1);
425 return ret;
426}
427
11c2177f
PT
428/**
429 * Splits out individual email patches from `paths`, where each path is either
430 * a mbox file or a Maildir. Returns 0 on success, -1 on failure.
431 */
432static int split_mail_mbox(struct am_state *state, const char **paths)
433{
434 struct child_process cp = CHILD_PROCESS_INIT;
435 struct strbuf last = STRBUF_INIT;
436
437 cp.git_cmd = 1;
438 argv_array_push(&cp.args, "mailsplit");
439 argv_array_pushf(&cp.args, "-d%d", state->prec);
440 argv_array_pushf(&cp.args, "-o%s", state->dir);
441 argv_array_push(&cp.args, "-b");
442 argv_array_push(&cp.args, "--");
443 argv_array_pushv(&cp.args, paths);
444
445 if (capture_command(&cp, &last, 8))
446 return -1;
447
448 state->cur = 1;
449 state->last = strtol(last.buf, NULL, 10);
450
451 return 0;
452}
453
454/**
455 * Splits a list of files/directories into individual email patches. Each path
456 * in `paths` must be a file/directory that is formatted according to
457 * `patch_format`.
458 *
459 * Once split out, the individual email patches will be stored in the state
460 * directory, with each patch's filename being its index, padded to state->prec
461 * digits.
462 *
463 * state->cur will be set to the index of the first mail, and state->last will
464 * be set to the index of the last mail.
465 *
466 * Returns 0 on success, -1 on failure.
467 */
468static int split_mail(struct am_state *state, enum patch_format patch_format,
469 const char **paths)
470{
471 switch (patch_format) {
472 case PATCH_FORMAT_MBOX:
473 return split_mail_mbox(state, paths);
474 default:
475 die("BUG: invalid patch_format");
476 }
477 return -1;
478}
479
8c3bd9e2
PT
480/**
481 * Setup a new am session for applying patches
482 */
11c2177f
PT
483static void am_setup(struct am_state *state, enum patch_format patch_format,
484 const char **paths)
8c3bd9e2 485{
c29807b2
PT
486 if (!patch_format)
487 patch_format = detect_patch_format(paths);
488
489 if (!patch_format) {
490 fprintf_ln(stderr, _("Patch format detection failed."));
491 exit(128);
492 }
493
8c3bd9e2
PT
494 if (mkdir(state->dir, 0777) < 0 && errno != EEXIST)
495 die_errno(_("failed to create directory '%s'"), state->dir);
496
11c2177f
PT
497 if (split_mail(state, patch_format, paths) < 0) {
498 am_destroy(state);
499 die(_("Failed to split patches."));
500 }
501
8c3bd9e2
PT
502 /*
503 * NOTE: Since the "next" and "last" files determine if an am_state
504 * session is in progress, they should be written last.
505 */
506
507 write_file(am_path(state, "next"), 1, "%d", state->cur);
508
509 write_file(am_path(state, "last"), 1, "%d", state->last);
510}
511
512/**
513 * Increments the patch pointer, and cleans am_state for the application of the
514 * next patch.
515 */
516static void am_next(struct am_state *state)
517{
3e20dcf3
PT
518 free(state->author_name);
519 state->author_name = NULL;
520
521 free(state->author_email);
522 state->author_email = NULL;
523
524 free(state->author_date);
525 state->author_date = NULL;
526
527 free(state->msg);
528 state->msg = NULL;
529 state->msg_len = 0;
530
531 unlink(am_path(state, "author-script"));
532 unlink(am_path(state, "final-commit"));
533
8c3bd9e2
PT
534 state->cur++;
535 write_file(am_path(state, "next"), 1, "%d", state->cur);
536}
537
3e20dcf3
PT
538/**
539 * Returns the filename of the current patch email.
540 */
541static const char *msgnum(const struct am_state *state)
542{
543 static struct strbuf sb = STRBUF_INIT;
544
545 strbuf_reset(&sb);
546 strbuf_addf(&sb, "%0*d", state->prec, state->cur);
547
548 return sb.buf;
549}
550
38a824fe
PT
551/**
552 * Refresh and write index.
553 */
554static void refresh_and_write_cache(void)
555{
556 struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
557
558 hold_locked_index(lock_file, 1);
559 refresh_cache(REFRESH_QUIET);
560 if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
561 die(_("unable to write index file"));
562}
563
3e20dcf3
PT
564/**
565 * Parses `mail` using git-mailinfo, extracting its patch and authorship info.
566 * state->msg will be set to the patch message. state->author_name,
567 * state->author_email and state->author_date will be set to the patch author's
568 * name, email and date respectively. The patch body will be written to the
569 * state directory's "patch" file.
570 *
571 * Returns 1 if the patch should be skipped, 0 otherwise.
572 */
573static int parse_mail(struct am_state *state, const char *mail)
574{
575 FILE *fp;
576 struct child_process cp = CHILD_PROCESS_INIT;
577 struct strbuf sb = STRBUF_INIT;
578 struct strbuf msg = STRBUF_INIT;
579 struct strbuf author_name = STRBUF_INIT;
580 struct strbuf author_date = STRBUF_INIT;
581 struct strbuf author_email = STRBUF_INIT;
582 int ret = 0;
583
584 cp.git_cmd = 1;
585 cp.in = xopen(mail, O_RDONLY, 0);
586 cp.out = xopen(am_path(state, "info"), O_WRONLY | O_CREAT, 0777);
587
588 argv_array_push(&cp.args, "mailinfo");
589 argv_array_push(&cp.args, am_path(state, "msg"));
590 argv_array_push(&cp.args, am_path(state, "patch"));
591
592 if (run_command(&cp) < 0)
593 die("could not parse patch");
594
595 close(cp.in);
596 close(cp.out);
597
598 /* Extract message and author information */
599 fp = xfopen(am_path(state, "info"), "r");
600 while (!strbuf_getline(&sb, fp, '\n')) {
601 const char *x;
602
603 if (skip_prefix(sb.buf, "Subject: ", &x)) {
604 if (msg.len)
605 strbuf_addch(&msg, '\n');
606 strbuf_addstr(&msg, x);
607 } else if (skip_prefix(sb.buf, "Author: ", &x))
608 strbuf_addstr(&author_name, x);
609 else if (skip_prefix(sb.buf, "Email: ", &x))
610 strbuf_addstr(&author_email, x);
611 else if (skip_prefix(sb.buf, "Date: ", &x))
612 strbuf_addstr(&author_date, x);
613 }
614 fclose(fp);
615
616 /* Skip pine's internal folder data */
617 if (!strcmp(author_name.buf, "Mail System Internal Data")) {
618 ret = 1;
619 goto finish;
620 }
621
622 if (is_empty_file(am_path(state, "patch"))) {
623 printf_ln(_("Patch is empty. Was it split wrong?"));
624 exit(128);
625 }
626
627 strbuf_addstr(&msg, "\n\n");
628 if (strbuf_read_file(&msg, am_path(state, "msg"), 0) < 0)
629 die_errno(_("could not read '%s'"), am_path(state, "msg"));
630 stripspace(&msg, 0);
631
632 assert(!state->author_name);
633 state->author_name = strbuf_detach(&author_name, NULL);
634
635 assert(!state->author_email);
636 state->author_email = strbuf_detach(&author_email, NULL);
637
638 assert(!state->author_date);
639 state->author_date = strbuf_detach(&author_date, NULL);
640
641 assert(!state->msg);
642 state->msg = strbuf_detach(&msg, &state->msg_len);
643
644finish:
645 strbuf_release(&msg);
646 strbuf_release(&author_date);
647 strbuf_release(&author_email);
648 strbuf_release(&author_name);
649 strbuf_release(&sb);
650 return ret;
651}
652
38a824fe
PT
653/**
654 * Applies current patch with git-apply. Returns 0 on success, -1 otherwise.
655 */
656static int run_apply(const struct am_state *state)
657{
658 struct child_process cp = CHILD_PROCESS_INIT;
659
660 cp.git_cmd = 1;
661
662 argv_array_push(&cp.args, "apply");
663 argv_array_push(&cp.args, "--index");
664 argv_array_push(&cp.args, am_path(state, "patch"));
665
666 if (run_command(&cp))
667 return -1;
668
669 /* Reload index as git-apply will have modified it. */
670 discard_cache();
671 read_cache();
672
673 return 0;
674}
675
8c3bd9e2
PT
676/**
677 * Applies all queued mail.
678 */
679static void am_run(struct am_state *state)
680{
38a824fe
PT
681 refresh_and_write_cache();
682
8c3bd9e2 683 while (state->cur <= state->last) {
3e20dcf3
PT
684 const char *mail = am_path(state, msgnum(state));
685
686 if (!file_exists(mail))
687 goto next;
688
689 if (parse_mail(state, mail))
690 goto next; /* mail should be skipped */
691
692 write_author_script(state);
693 write_commit_msg(state);
8c3bd9e2 694
38a824fe
PT
695 printf_ln(_("Applying: %.*s"), linelen(state->msg), state->msg);
696
697 if (run_apply(state) < 0) {
698 int advice_amworkdir = 1;
699
700 printf_ln(_("Patch failed at %s %.*s"), msgnum(state),
701 linelen(state->msg), state->msg);
702
703 git_config_get_bool("advice.amworkdir", &advice_amworkdir);
704
705 if (advice_amworkdir)
706 printf_ln(_("The copy of the patch that failed is found in: %s"),
707 am_path(state, "patch"));
708
709 exit(128);
710 }
711
712 /*
713 * NEEDSWORK: After the patch has been applied to the index
714 * with git-apply, we need to make commit as well.
715 */
8c3bd9e2 716
3e20dcf3 717next:
8c3bd9e2
PT
718 am_next(state);
719 }
720
721 am_destroy(state);
722}
73c2779f 723
11c2177f
PT
724/**
725 * parse_options() callback that validates and sets opt->value to the
726 * PATCH_FORMAT_* enum value corresponding to `arg`.
727 */
728static int parse_opt_patchformat(const struct option *opt, const char *arg, int unset)
729{
730 int *opt_value = opt->value;
731
732 if (!strcmp(arg, "mbox"))
733 *opt_value = PATCH_FORMAT_MBOX;
734 else
735 return error(_("Invalid value for --patch-format: %s"), arg);
736 return 0;
737}
738
73c2779f
PT
739int cmd_am(int argc, const char **argv, const char *prefix)
740{
8c3bd9e2 741 struct am_state state;
11c2177f 742 int patch_format = PATCH_FORMAT_UNKNOWN;
8c3bd9e2
PT
743
744 const char * const usage[] = {
745 N_("git am [options] [(<mbox>|<Maildir>)...]"),
746 NULL
747 };
748
749 struct option options[] = {
11c2177f
PT
750 OPT_CALLBACK(0, "patch-format", &patch_format, N_("format"),
751 N_("format the patch(es) are in"),
752 parse_opt_patchformat),
8c3bd9e2
PT
753 OPT_END()
754 };
73c2779f
PT
755
756 /*
757 * NEEDSWORK: Once all the features of git-am.sh have been
758 * re-implemented in builtin/am.c, this preamble can be removed.
759 */
760 if (!getenv("_GIT_USE_BUILTIN_AM")) {
761 const char *path = mkpath("%s/git-am", git_exec_path());
762
763 if (sane_execvp(path, (char **)argv) < 0)
764 die_errno("could not exec %s", path);
765 } else {
766 prefix = setup_git_directory();
767 trace_repo_setup(prefix);
768 setup_work_tree();
769 }
770
8c3bd9e2
PT
771 git_config(git_default_config, NULL);
772
773 am_state_init(&state, git_path("rebase-apply"));
774
775 argc = parse_options(argc, argv, prefix, options, usage, 0);
776
38a824fe
PT
777 if (read_index_preload(&the_index, NULL) < 0)
778 die(_("failed to read the index"));
779
8c3bd9e2
PT
780 if (am_in_progress(&state))
781 am_load(&state);
11c2177f
PT
782 else {
783 struct argv_array paths = ARGV_ARRAY_INIT;
784 int i;
785
786 for (i = 0; i < argc; i++) {
787 if (is_absolute_path(argv[i]) || !prefix)
788 argv_array_push(&paths, argv[i]);
789 else
790 argv_array_push(&paths, mkpath("%s/%s", prefix, argv[i]));
791 }
792
793 am_setup(&state, patch_format, paths.argv);
794
795 argv_array_clear(&paths);
796 }
8c3bd9e2
PT
797
798 am_run(&state);
799
800 am_state_release(&state);
801
73c2779f
PT
802 return 0;
803}