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" 9#include"parse-options.h" 10#include"dir.h" 11#include"run-command.h" 12#include"quote.h" 13#include"tempfile.h" 14#include"lockfile.h" 15#include"cache-tree.h" 16#include"refs.h" 17#include"commit.h" 18#include"diff.h" 19#include"diffcore.h" 20#include"unpack-trees.h" 21#include"branch.h" 22#include"sequencer.h" 23#include"revision.h" 24#include"merge-recursive.h" 25#include"revision.h" 26#include"log-tree.h" 27#include"notes-utils.h" 28#include"rerere.h" 29#include"prompt.h" 30#include"mailinfo.h" 31#include"apply.h" 32#include"string-list.h" 33 34/** 35 * Returns 1 if the file is empty or does not exist, 0 otherwise. 36 */ 37static intis_empty_file(const char*filename) 38{ 39struct stat st; 40 41if(stat(filename, &st) <0) { 42if(errno == ENOENT) 43return1; 44die_errno(_("could not stat%s"), filename); 45} 46 47return!st.st_size; 48} 49 50/** 51 * Returns the length of the first line of msg. 52 */ 53static intlinelen(const char*msg) 54{ 55returnstrchrnul(msg,'\n') - msg; 56} 57 58/** 59 * Returns true if `str` consists of only whitespace, false otherwise. 60 */ 61static intstr_isspace(const char*str) 62{ 63for(; *str; str++) 64if(!isspace(*str)) 65return0; 66 67return1; 68} 69 70enum patch_format { 71 PATCH_FORMAT_UNKNOWN =0, 72 PATCH_FORMAT_MBOX, 73 PATCH_FORMAT_STGIT, 74 PATCH_FORMAT_STGIT_SERIES, 75 PATCH_FORMAT_HG, 76 PATCH_FORMAT_MBOXRD 77}; 78 79enum keep_type { 80 KEEP_FALSE =0, 81 KEEP_TRUE,/* pass -k flag to git-mailinfo */ 82 KEEP_NON_PATCH /* pass -b flag to git-mailinfo */ 83}; 84 85enum scissors_type { 86 SCISSORS_UNSET = -1, 87 SCISSORS_FALSE =0,/* pass --no-scissors to git-mailinfo */ 88 SCISSORS_TRUE /* pass --scissors to git-mailinfo */ 89}; 90 91enum signoff_type { 92 SIGNOFF_FALSE =0, 93 SIGNOFF_TRUE =1, 94 SIGNOFF_EXPLICIT /* --signoff was set on the command-line */ 95}; 96 97struct am_state { 98/* state directory path */ 99char*dir; 100 101/* current and last patch numbers, 1-indexed */ 102int cur; 103int last; 104 105/* commit metadata and message */ 106char*author_name; 107char*author_email; 108char*author_date; 109char*msg; 110size_t msg_len; 111 112/* when --rebasing, records the original commit the patch came from */ 113struct object_id orig_commit; 114 115/* number of digits in patch filename */ 116int prec; 117 118/* various operating modes and command line options */ 119int interactive; 120int threeway; 121int quiet; 122int signoff;/* enum signoff_type */ 123int utf8; 124int keep;/* enum keep_type */ 125int message_id; 126int scissors;/* enum scissors_type */ 127struct argv_array git_apply_opts; 128const char*resolvemsg; 129int committer_date_is_author_date; 130int ignore_date; 131int allow_rerere_autoupdate; 132const char*sign_commit; 133int rebasing; 134}; 135 136/** 137 * Initializes am_state with the default values. 138 */ 139static voidam_state_init(struct am_state *state) 140{ 141int gpgsign; 142 143memset(state,0,sizeof(*state)); 144 145 state->dir =git_pathdup("rebase-apply"); 146 147 state->prec =4; 148 149git_config_get_bool("am.threeway", &state->threeway); 150 151 state->utf8 =1; 152 153git_config_get_bool("am.messageid", &state->message_id); 154 155 state->scissors = SCISSORS_UNSET; 156 157argv_array_init(&state->git_apply_opts); 158 159if(!git_config_get_bool("commit.gpgsign", &gpgsign)) 160 state->sign_commit = gpgsign ?"": NULL; 161} 162 163/** 164 * Releases memory allocated by an am_state. 165 */ 166static voidam_state_release(struct am_state *state) 167{ 168free(state->dir); 169free(state->author_name); 170free(state->author_email); 171free(state->author_date); 172free(state->msg); 173argv_array_clear(&state->git_apply_opts); 174} 175 176/** 177 * Returns path relative to the am_state directory. 178 */ 179staticinlineconst char*am_path(const struct am_state *state,const char*path) 180{ 181returnmkpath("%s/%s", state->dir, path); 182} 183 184/** 185 * For convenience to call write_file() 186 */ 187static voidwrite_state_text(const struct am_state *state, 188const char*name,const char*string) 189{ 190write_file(am_path(state, name),"%s", string); 191} 192 193static voidwrite_state_count(const struct am_state *state, 194const char*name,int value) 195{ 196write_file(am_path(state, name),"%d", value); 197} 198 199static voidwrite_state_bool(const struct am_state *state, 200const char*name,int value) 201{ 202write_state_text(state, name, value ?"t":"f"); 203} 204 205/** 206 * If state->quiet is false, calls fprintf(fp, fmt, ...), and appends a newline 207 * at the end. 208 */ 209static voidsay(const struct am_state *state,FILE*fp,const char*fmt, ...) 210{ 211va_list ap; 212 213va_start(ap, fmt); 214if(!state->quiet) { 215vfprintf(fp, fmt, ap); 216putc('\n', fp); 217} 218va_end(ap); 219} 220 221/** 222 * Returns 1 if there is an am session in progress, 0 otherwise. 223 */ 224static intam_in_progress(const struct am_state *state) 225{ 226struct stat st; 227 228if(lstat(state->dir, &st) <0|| !S_ISDIR(st.st_mode)) 229return0; 230if(lstat(am_path(state,"last"), &st) || !S_ISREG(st.st_mode)) 231return0; 232if(lstat(am_path(state,"next"), &st) || !S_ISREG(st.st_mode)) 233return0; 234return1; 235} 236 237/** 238 * Reads the contents of `file` in the `state` directory into `sb`. Returns the 239 * number of bytes read on success, -1 if the file does not exist. If `trim` is 240 * set, trailing whitespace will be removed. 241 */ 242static intread_state_file(struct strbuf *sb,const struct am_state *state, 243const char*file,int trim) 244{ 245strbuf_reset(sb); 246 247if(strbuf_read_file(sb,am_path(state, file),0) >=0) { 248if(trim) 249strbuf_trim(sb); 250 251return sb->len; 252} 253 254if(errno == ENOENT) 255return-1; 256 257die_errno(_("could not read '%s'"),am_path(state, file)); 258} 259 260/** 261 * Take a series of KEY='VALUE' lines where VALUE part is 262 * sq-quoted, and append <KEY, VALUE> at the end of the string list 263 */ 264static intparse_key_value_squoted(char*buf,struct string_list *list) 265{ 266while(*buf) { 267struct string_list_item *item; 268char*np; 269char*cp =strchr(buf,'='); 270if(!cp) 271return-1; 272 np =strchrnul(cp,'\n'); 273*cp++ ='\0'; 274 item =string_list_append(list, buf); 275 276 buf = np + (*np =='\n'); 277*np ='\0'; 278 cp =sq_dequote(cp); 279if(!cp) 280return-1; 281 item->util =xstrdup(cp); 282} 283return0; 284} 285 286/** 287 * Reads and parses the state directory's "author-script" file, and sets 288 * state->author_name, state->author_email and state->author_date accordingly. 289 * Returns 0 on success, -1 if the file could not be parsed. 290 * 291 * The author script is of the format: 292 * 293 * GIT_AUTHOR_NAME='$author_name' 294 * GIT_AUTHOR_EMAIL='$author_email' 295 * GIT_AUTHOR_DATE='$author_date' 296 * 297 * where $author_name, $author_email and $author_date are quoted. We are strict 298 * with our parsing, as the file was meant to be eval'd in the old git-am.sh 299 * script, and thus if the file differs from what this function expects, it is 300 * better to bail out than to do something that the user does not expect. 301 */ 302static intread_author_script(struct am_state *state) 303{ 304const char*filename =am_path(state,"author-script"); 305struct strbuf buf = STRBUF_INIT; 306struct string_list kv = STRING_LIST_INIT_DUP; 307int retval = -1;/* assume failure */ 308int fd; 309 310assert(!state->author_name); 311assert(!state->author_email); 312assert(!state->author_date); 313 314 fd =open(filename, O_RDONLY); 315if(fd <0) { 316if(errno == ENOENT) 317return0; 318die_errno(_("could not open '%s' for reading"), filename); 319} 320strbuf_read(&buf, fd,0); 321close(fd); 322if(parse_key_value_squoted(buf.buf, &kv)) 323goto finish; 324 325if(kv.nr !=3|| 326strcmp(kv.items[0].string,"GIT_AUTHOR_NAME") || 327strcmp(kv.items[1].string,"GIT_AUTHOR_EMAIL") || 328strcmp(kv.items[2].string,"GIT_AUTHOR_DATE")) 329goto finish; 330 state->author_name = kv.items[0].util; 331 state->author_email = kv.items[1].util; 332 state->author_date = kv.items[2].util; 333 retval =0; 334finish: 335string_list_clear(&kv, !!retval); 336strbuf_release(&buf); 337return retval; 338} 339 340/** 341 * Saves state->author_name, state->author_email and state->author_date in the 342 * state directory's "author-script" file. 343 */ 344static voidwrite_author_script(const struct am_state *state) 345{ 346struct strbuf sb = STRBUF_INIT; 347 348strbuf_addstr(&sb,"GIT_AUTHOR_NAME="); 349sq_quote_buf(&sb, state->author_name); 350strbuf_addch(&sb,'\n'); 351 352strbuf_addstr(&sb,"GIT_AUTHOR_EMAIL="); 353sq_quote_buf(&sb, state->author_email); 354strbuf_addch(&sb,'\n'); 355 356strbuf_addstr(&sb,"GIT_AUTHOR_DATE="); 357sq_quote_buf(&sb, state->author_date); 358strbuf_addch(&sb,'\n'); 359 360write_state_text(state,"author-script", sb.buf); 361 362strbuf_release(&sb); 363} 364 365/** 366 * Reads the commit message from the state directory's "final-commit" file, 367 * setting state->msg to its contents and state->msg_len to the length of its 368 * contents in bytes. 369 * 370 * Returns 0 on success, -1 if the file does not exist. 371 */ 372static intread_commit_msg(struct am_state *state) 373{ 374struct strbuf sb = STRBUF_INIT; 375 376assert(!state->msg); 377 378if(read_state_file(&sb, state,"final-commit",0) <0) { 379strbuf_release(&sb); 380return-1; 381} 382 383 state->msg =strbuf_detach(&sb, &state->msg_len); 384return0; 385} 386 387/** 388 * Saves state->msg in the state directory's "final-commit" file. 389 */ 390static voidwrite_commit_msg(const struct am_state *state) 391{ 392const char*filename =am_path(state,"final-commit"); 393write_file_buf(filename, state->msg, state->msg_len); 394} 395 396/** 397 * Loads state from disk. 398 */ 399static voidam_load(struct am_state *state) 400{ 401struct strbuf sb = STRBUF_INIT; 402 403if(read_state_file(&sb, state,"next",1) <0) 404die("BUG: state file 'next' does not exist"); 405 state->cur =strtol(sb.buf, NULL,10); 406 407if(read_state_file(&sb, state,"last",1) <0) 408die("BUG: state file 'last' does not exist"); 409 state->last =strtol(sb.buf, NULL,10); 410 411if(read_author_script(state) <0) 412die(_("could not parse author script")); 413 414read_commit_msg(state); 415 416if(read_state_file(&sb, state,"original-commit",1) <0) 417oidclr(&state->orig_commit); 418else if(get_oid_hex(sb.buf, &state->orig_commit) <0) 419die(_("could not parse%s"),am_path(state,"original-commit")); 420 421read_state_file(&sb, state,"threeway",1); 422 state->threeway = !strcmp(sb.buf,"t"); 423 424read_state_file(&sb, state,"quiet",1); 425 state->quiet = !strcmp(sb.buf,"t"); 426 427read_state_file(&sb, state,"sign",1); 428 state->signoff = !strcmp(sb.buf,"t"); 429 430read_state_file(&sb, state,"utf8",1); 431 state->utf8 = !strcmp(sb.buf,"t"); 432 433read_state_file(&sb, state,"keep",1); 434if(!strcmp(sb.buf,"t")) 435 state->keep = KEEP_TRUE; 436else if(!strcmp(sb.buf,"b")) 437 state->keep = KEEP_NON_PATCH; 438else 439 state->keep = KEEP_FALSE; 440 441read_state_file(&sb, state,"messageid",1); 442 state->message_id = !strcmp(sb.buf,"t"); 443 444read_state_file(&sb, state,"scissors",1); 445if(!strcmp(sb.buf,"t")) 446 state->scissors = SCISSORS_TRUE; 447else if(!strcmp(sb.buf,"f")) 448 state->scissors = SCISSORS_FALSE; 449else 450 state->scissors = SCISSORS_UNSET; 451 452read_state_file(&sb, state,"apply-opt",1); 453argv_array_clear(&state->git_apply_opts); 454if(sq_dequote_to_argv_array(sb.buf, &state->git_apply_opts) <0) 455die(_("could not parse%s"),am_path(state,"apply-opt")); 456 457 state->rebasing = !!file_exists(am_path(state,"rebasing")); 458 459strbuf_release(&sb); 460} 461 462/** 463 * Removes the am_state directory, forcefully terminating the current am 464 * session. 465 */ 466static voidam_destroy(const struct am_state *state) 467{ 468struct strbuf sb = STRBUF_INIT; 469 470strbuf_addstr(&sb, state->dir); 471remove_dir_recursively(&sb,0); 472strbuf_release(&sb); 473} 474 475/** 476 * Runs applypatch-msg hook. Returns its exit code. 477 */ 478static intrun_applypatch_msg_hook(struct am_state *state) 479{ 480int ret; 481 482assert(state->msg); 483 ret =run_hook_le(NULL,"applypatch-msg",am_path(state,"final-commit"), NULL); 484 485if(!ret) { 486FREE_AND_NULL(state->msg); 487if(read_commit_msg(state) <0) 488die(_("'%s' was deleted by the applypatch-msg hook"), 489am_path(state,"final-commit")); 490} 491 492return ret; 493} 494 495/** 496 * Runs post-rewrite hook. Returns it exit code. 497 */ 498static intrun_post_rewrite_hook(const struct am_state *state) 499{ 500struct child_process cp = CHILD_PROCESS_INIT; 501const char*hook =find_hook("post-rewrite"); 502int ret; 503 504if(!hook) 505return0; 506 507argv_array_push(&cp.args, hook); 508argv_array_push(&cp.args,"rebase"); 509 510 cp.in =xopen(am_path(state,"rewritten"), O_RDONLY); 511 cp.stdout_to_stderr =1; 512 513 ret =run_command(&cp); 514 515close(cp.in); 516return ret; 517} 518 519/** 520 * Reads the state directory's "rewritten" file, and copies notes from the old 521 * commits listed in the file to their rewritten commits. 522 * 523 * Returns 0 on success, -1 on failure. 524 */ 525static intcopy_notes_for_rebase(const struct am_state *state) 526{ 527struct notes_rewrite_cfg *c; 528struct strbuf sb = STRBUF_INIT; 529const char*invalid_line =_("Malformed input line: '%s'."); 530const char*msg ="Notes added by 'git rebase'"; 531FILE*fp; 532int ret =0; 533 534assert(state->rebasing); 535 536 c =init_copy_notes_for_rewrite("rebase"); 537if(!c) 538return0; 539 540 fp =xfopen(am_path(state,"rewritten"),"r"); 541 542while(!strbuf_getline_lf(&sb, fp)) { 543struct object_id from_obj, to_obj; 544 545if(sb.len != GIT_SHA1_HEXSZ *2+1) { 546 ret =error(invalid_line, sb.buf); 547goto finish; 548} 549 550if(get_oid_hex(sb.buf, &from_obj)) { 551 ret =error(invalid_line, sb.buf); 552goto finish; 553} 554 555if(sb.buf[GIT_SHA1_HEXSZ] !=' ') { 556 ret =error(invalid_line, sb.buf); 557goto finish; 558} 559 560if(get_oid_hex(sb.buf + GIT_SHA1_HEXSZ +1, &to_obj)) { 561 ret =error(invalid_line, sb.buf); 562goto finish; 563} 564 565if(copy_note_for_rewrite(c, from_obj.hash, to_obj.hash)) 566 ret =error(_("Failed to copy notes from '%s' to '%s'"), 567oid_to_hex(&from_obj),oid_to_hex(&to_obj)); 568} 569 570finish: 571finish_copy_notes_for_rewrite(c, msg); 572fclose(fp); 573strbuf_release(&sb); 574return ret; 575} 576 577/** 578 * Determines if the file looks like a piece of RFC2822 mail by grabbing all 579 * non-indented lines and checking if they look like they begin with valid 580 * header field names. 581 * 582 * Returns 1 if the file looks like a piece of mail, 0 otherwise. 583 */ 584static intis_mail(FILE*fp) 585{ 586const char*header_regex ="^[!-9;-~]+:"; 587struct strbuf sb = STRBUF_INIT; 588 regex_t regex; 589int ret =1; 590 591if(fseek(fp,0L, SEEK_SET)) 592die_errno(_("fseek failed")); 593 594if(regcomp(®ex, header_regex, REG_NOSUB | REG_EXTENDED)) 595die("invalid pattern:%s", header_regex); 596 597while(!strbuf_getline(&sb, fp)) { 598if(!sb.len) 599break;/* End of header */ 600 601/* Ignore indented folded lines */ 602if(*sb.buf =='\t'|| *sb.buf ==' ') 603continue; 604 605/* It's a header if it matches header_regex */ 606if(regexec(®ex, sb.buf,0, NULL,0)) { 607 ret =0; 608goto done; 609} 610} 611 612done: 613regfree(®ex); 614strbuf_release(&sb); 615return ret; 616} 617 618/** 619 * Attempts to detect the patch_format of the patches contained in `paths`, 620 * returning the PATCH_FORMAT_* enum value. Returns PATCH_FORMAT_UNKNOWN if 621 * detection fails. 622 */ 623static intdetect_patch_format(const char**paths) 624{ 625enum patch_format ret = PATCH_FORMAT_UNKNOWN; 626struct strbuf l1 = STRBUF_INIT; 627struct strbuf l2 = STRBUF_INIT; 628struct strbuf l3 = STRBUF_INIT; 629FILE*fp; 630 631/* 632 * We default to mbox format if input is from stdin and for directories 633 */ 634if(!*paths || !strcmp(*paths,"-") ||is_directory(*paths)) 635return PATCH_FORMAT_MBOX; 636 637/* 638 * Otherwise, check the first few lines of the first patch, starting 639 * from the first non-blank line, to try to detect its format. 640 */ 641 642 fp =xfopen(*paths,"r"); 643 644while(!strbuf_getline(&l1, fp)) { 645if(l1.len) 646break; 647} 648 649if(starts_with(l1.buf,"From ") ||starts_with(l1.buf,"From: ")) { 650 ret = PATCH_FORMAT_MBOX; 651goto done; 652} 653 654if(starts_with(l1.buf,"# This series applies on GIT commit")) { 655 ret = PATCH_FORMAT_STGIT_SERIES; 656goto done; 657} 658 659if(!strcmp(l1.buf,"# HG changeset patch")) { 660 ret = PATCH_FORMAT_HG; 661goto done; 662} 663 664strbuf_reset(&l2); 665strbuf_getline(&l2, fp); 666strbuf_reset(&l3); 667strbuf_getline(&l3, fp); 668 669/* 670 * If the second line is empty and the third is a From, Author or Date 671 * entry, this is likely an StGit patch. 672 */ 673if(l1.len && !l2.len && 674(starts_with(l3.buf,"From:") || 675starts_with(l3.buf,"Author:") || 676starts_with(l3.buf,"Date:"))) { 677 ret = PATCH_FORMAT_STGIT; 678goto done; 679} 680 681if(l1.len &&is_mail(fp)) { 682 ret = PATCH_FORMAT_MBOX; 683goto done; 684} 685 686done: 687fclose(fp); 688strbuf_release(&l1); 689return ret; 690} 691 692/** 693 * Splits out individual email patches from `paths`, where each path is either 694 * a mbox file or a Maildir. Returns 0 on success, -1 on failure. 695 */ 696static intsplit_mail_mbox(struct am_state *state,const char**paths, 697int keep_cr,int mboxrd) 698{ 699struct child_process cp = CHILD_PROCESS_INIT; 700struct strbuf last = STRBUF_INIT; 701 702 cp.git_cmd =1; 703argv_array_push(&cp.args,"mailsplit"); 704argv_array_pushf(&cp.args,"-d%d", state->prec); 705argv_array_pushf(&cp.args,"-o%s", state->dir); 706argv_array_push(&cp.args,"-b"); 707if(keep_cr) 708argv_array_push(&cp.args,"--keep-cr"); 709if(mboxrd) 710argv_array_push(&cp.args,"--mboxrd"); 711argv_array_push(&cp.args,"--"); 712argv_array_pushv(&cp.args, paths); 713 714if(capture_command(&cp, &last,8)) 715return-1; 716 717 state->cur =1; 718 state->last =strtol(last.buf, NULL,10); 719 720return0; 721} 722 723/** 724 * Callback signature for split_mail_conv(). The foreign patch should be 725 * read from `in`, and the converted patch (in RFC2822 mail format) should be 726 * written to `out`. Return 0 on success, or -1 on failure. 727 */ 728typedefint(*mail_conv_fn)(FILE*out,FILE*in,int keep_cr); 729 730/** 731 * Calls `fn` for each file in `paths` to convert the foreign patch to the 732 * RFC2822 mail format suitable for parsing with git-mailinfo. 733 * 734 * Returns 0 on success, -1 on failure. 735 */ 736static intsplit_mail_conv(mail_conv_fn fn,struct am_state *state, 737const char**paths,int keep_cr) 738{ 739static const char*stdin_only[] = {"-", NULL}; 740int i; 741 742if(!*paths) 743 paths = stdin_only; 744 745for(i =0; *paths; paths++, i++) { 746FILE*in, *out; 747const char*mail; 748int ret; 749 750if(!strcmp(*paths,"-")) 751 in = stdin; 752else 753 in =fopen(*paths,"r"); 754 755if(!in) 756returnerror_errno(_("could not open '%s' for reading"), 757*paths); 758 759 mail =mkpath("%s/%0*d", state->dir, state->prec, i +1); 760 761 out =fopen(mail,"w"); 762if(!out) { 763if(in != stdin) 764fclose(in); 765returnerror_errno(_("could not open '%s' for writing"), 766 mail); 767} 768 769 ret =fn(out, in, keep_cr); 770 771fclose(out); 772if(in != stdin) 773fclose(in); 774 775if(ret) 776returnerror(_("could not parse patch '%s'"), *paths); 777} 778 779 state->cur =1; 780 state->last = i; 781return0; 782} 783 784/** 785 * A split_mail_conv() callback that converts an StGit patch to an RFC2822 786 * message suitable for parsing with git-mailinfo. 787 */ 788static intstgit_patch_to_mail(FILE*out,FILE*in,int keep_cr) 789{ 790struct strbuf sb = STRBUF_INIT; 791int subject_printed =0; 792 793while(!strbuf_getline_lf(&sb, in)) { 794const char*str; 795 796if(str_isspace(sb.buf)) 797continue; 798else if(skip_prefix(sb.buf,"Author:", &str)) 799fprintf(out,"From:%s\n", str); 800else if(starts_with(sb.buf,"From") ||starts_with(sb.buf,"Date")) 801fprintf(out,"%s\n", sb.buf); 802else if(!subject_printed) { 803fprintf(out,"Subject:%s\n", sb.buf); 804 subject_printed =1; 805}else{ 806fprintf(out,"\n%s\n", sb.buf); 807break; 808} 809} 810 811strbuf_reset(&sb); 812while(strbuf_fread(&sb,8192, in) >0) { 813fwrite(sb.buf,1, sb.len, out); 814strbuf_reset(&sb); 815} 816 817strbuf_release(&sb); 818return0; 819} 820 821/** 822 * This function only supports a single StGit series file in `paths`. 823 * 824 * Given an StGit series file, converts the StGit patches in the series into 825 * RFC2822 messages suitable for parsing with git-mailinfo, and queues them in 826 * the state directory. 827 * 828 * Returns 0 on success, -1 on failure. 829 */ 830static intsplit_mail_stgit_series(struct am_state *state,const char**paths, 831int keep_cr) 832{ 833const char*series_dir; 834char*series_dir_buf; 835FILE*fp; 836struct argv_array patches = ARGV_ARRAY_INIT; 837struct strbuf sb = STRBUF_INIT; 838int ret; 839 840if(!paths[0] || paths[1]) 841returnerror(_("Only one StGIT patch series can be applied at once")); 842 843 series_dir_buf =xstrdup(*paths); 844 series_dir =dirname(series_dir_buf); 845 846 fp =fopen(*paths,"r"); 847if(!fp) 848returnerror_errno(_("could not open '%s' for reading"), *paths); 849 850while(!strbuf_getline_lf(&sb, fp)) { 851if(*sb.buf =='#') 852continue;/* skip comment lines */ 853 854argv_array_push(&patches,mkpath("%s/%s", series_dir, sb.buf)); 855} 856 857fclose(fp); 858strbuf_release(&sb); 859free(series_dir_buf); 860 861 ret =split_mail_conv(stgit_patch_to_mail, state, patches.argv, keep_cr); 862 863argv_array_clear(&patches); 864return ret; 865} 866 867/** 868 * A split_patches_conv() callback that converts a mercurial patch to a RFC2822 869 * message suitable for parsing with git-mailinfo. 870 */ 871static inthg_patch_to_mail(FILE*out,FILE*in,int keep_cr) 872{ 873struct strbuf sb = STRBUF_INIT; 874 875while(!strbuf_getline_lf(&sb, in)) { 876const char*str; 877 878if(skip_prefix(sb.buf,"# User ", &str)) 879fprintf(out,"From:%s\n", str); 880else if(skip_prefix(sb.buf,"# Date ", &str)) { 881 timestamp_t timestamp; 882long tz, tz2; 883char*end; 884 885 errno =0; 886 timestamp =parse_timestamp(str, &end,10); 887if(errno) 888returnerror(_("invalid timestamp")); 889 890if(!skip_prefix(end," ", &str)) 891returnerror(_("invalid Date line")); 892 893 errno =0; 894 tz =strtol(str, &end,10); 895if(errno) 896returnerror(_("invalid timezone offset")); 897 898if(*end) 899returnerror(_("invalid Date line")); 900 901/* 902 * mercurial's timezone is in seconds west of UTC, 903 * however git's timezone is in hours + minutes east of 904 * UTC. Convert it. 905 */ 906 tz2 =labs(tz) /3600*100+labs(tz) %3600/60; 907if(tz >0) 908 tz2 = -tz2; 909 910fprintf(out,"Date:%s\n",show_date(timestamp, tz2,DATE_MODE(RFC2822))); 911}else if(starts_with(sb.buf,"# ")) { 912continue; 913}else{ 914fprintf(out,"\n%s\n", sb.buf); 915break; 916} 917} 918 919strbuf_reset(&sb); 920while(strbuf_fread(&sb,8192, in) >0) { 921fwrite(sb.buf,1, sb.len, out); 922strbuf_reset(&sb); 923} 924 925strbuf_release(&sb); 926return0; 927} 928 929/** 930 * Splits a list of files/directories into individual email patches. Each path 931 * in `paths` must be a file/directory that is formatted according to 932 * `patch_format`. 933 * 934 * Once split out, the individual email patches will be stored in the state 935 * directory, with each patch's filename being its index, padded to state->prec 936 * digits. 937 * 938 * state->cur will be set to the index of the first mail, and state->last will 939 * be set to the index of the last mail. 940 * 941 * Set keep_cr to 0 to convert all lines ending with \r\n to end with \n, 1 942 * to disable this behavior, -1 to use the default configured setting. 943 * 944 * Returns 0 on success, -1 on failure. 945 */ 946static intsplit_mail(struct am_state *state,enum patch_format patch_format, 947const char**paths,int keep_cr) 948{ 949if(keep_cr <0) { 950 keep_cr =0; 951git_config_get_bool("am.keepcr", &keep_cr); 952} 953 954switch(patch_format) { 955case PATCH_FORMAT_MBOX: 956returnsplit_mail_mbox(state, paths, keep_cr,0); 957case PATCH_FORMAT_STGIT: 958returnsplit_mail_conv(stgit_patch_to_mail, state, paths, keep_cr); 959case PATCH_FORMAT_STGIT_SERIES: 960returnsplit_mail_stgit_series(state, paths, keep_cr); 961case PATCH_FORMAT_HG: 962returnsplit_mail_conv(hg_patch_to_mail, state, paths, keep_cr); 963case PATCH_FORMAT_MBOXRD: 964returnsplit_mail_mbox(state, paths, keep_cr,1); 965default: 966die("BUG: invalid patch_format"); 967} 968return-1; 969} 970 971/** 972 * Setup a new am session for applying patches 973 */ 974static voidam_setup(struct am_state *state,enum patch_format patch_format, 975const char**paths,int keep_cr) 976{ 977struct object_id curr_head; 978const char*str; 979struct strbuf sb = STRBUF_INIT; 980 981if(!patch_format) 982 patch_format =detect_patch_format(paths); 983 984if(!patch_format) { 985fprintf_ln(stderr,_("Patch format detection failed.")); 986exit(128); 987} 988 989if(mkdir(state->dir,0777) <0&& errno != EEXIST) 990die_errno(_("failed to create directory '%s'"), state->dir); 991 992if(split_mail(state, patch_format, paths, keep_cr) <0) { 993am_destroy(state); 994die(_("Failed to split patches.")); 995} 996 997if(state->rebasing) 998 state->threeway =1; 9991000write_state_bool(state,"threeway", state->threeway);1001write_state_bool(state,"quiet", state->quiet);1002write_state_bool(state,"sign", state->signoff);1003write_state_bool(state,"utf8", state->utf8);10041005switch(state->keep) {1006case KEEP_FALSE:1007 str ="f";1008break;1009case KEEP_TRUE:1010 str ="t";1011break;1012case KEEP_NON_PATCH:1013 str ="b";1014break;1015default:1016die("BUG: invalid value for state->keep");1017}10181019write_state_text(state,"keep", str);1020write_state_bool(state,"messageid", state->message_id);10211022switch(state->scissors) {1023case SCISSORS_UNSET:1024 str ="";1025break;1026case SCISSORS_FALSE:1027 str ="f";1028break;1029case SCISSORS_TRUE:1030 str ="t";1031break;1032default:1033die("BUG: invalid value for state->scissors");1034}1035write_state_text(state,"scissors", str);10361037sq_quote_argv(&sb, state->git_apply_opts.argv,0);1038write_state_text(state,"apply-opt", sb.buf);10391040if(state->rebasing)1041write_state_text(state,"rebasing","");1042else1043write_state_text(state,"applying","");10441045if(!get_oid("HEAD", &curr_head)) {1046write_state_text(state,"abort-safety",oid_to_hex(&curr_head));1047if(!state->rebasing)1048update_ref_oid("am","ORIG_HEAD", &curr_head, NULL,0,1049 UPDATE_REFS_DIE_ON_ERR);1050}else{1051write_state_text(state,"abort-safety","");1052if(!state->rebasing)1053delete_ref(NULL,"ORIG_HEAD", NULL,0);1054}10551056/*1057 * NOTE: Since the "next" and "last" files determine if an am_state1058 * session is in progress, they should be written last.1059 */10601061write_state_count(state,"next", state->cur);1062write_state_count(state,"last", state->last);10631064strbuf_release(&sb);1065}10661067/**1068 * Increments the patch pointer, and cleans am_state for the application of the1069 * next patch.1070 */1071static voidam_next(struct am_state *state)1072{1073struct object_id head;10741075free(state->author_name);1076 state->author_name = NULL;10771078free(state->author_email);1079 state->author_email = NULL;10801081free(state->author_date);1082 state->author_date = NULL;10831084free(state->msg);1085 state->msg = NULL;1086 state->msg_len =0;10871088unlink(am_path(state,"author-script"));1089unlink(am_path(state,"final-commit"));10901091oidclr(&state->orig_commit);1092unlink(am_path(state,"original-commit"));10931094if(!get_oid("HEAD", &head))1095write_state_text(state,"abort-safety",oid_to_hex(&head));1096else1097write_state_text(state,"abort-safety","");10981099 state->cur++;1100write_state_count(state,"next", state->cur);1101}11021103/**1104 * Returns the filename of the current patch email.1105 */1106static const char*msgnum(const struct am_state *state)1107{1108static struct strbuf sb = STRBUF_INIT;11091110strbuf_reset(&sb);1111strbuf_addf(&sb,"%0*d", state->prec, state->cur);11121113return sb.buf;1114}11151116/**1117 * Refresh and write index.1118 */1119static voidrefresh_and_write_cache(void)1120{1121struct lock_file *lock_file =xcalloc(1,sizeof(struct lock_file));11221123hold_locked_index(lock_file, LOCK_DIE_ON_ERROR);1124refresh_cache(REFRESH_QUIET);1125if(write_locked_index(&the_index, lock_file, COMMIT_LOCK))1126die(_("unable to write index file"));1127}11281129/**1130 * Returns 1 if the index differs from HEAD, 0 otherwise. When on an unborn1131 * branch, returns 1 if there are entries in the index, 0 otherwise. If an1132 * strbuf is provided, the space-separated list of files that differ will be1133 * appended to it.1134 */1135static intindex_has_changes(struct strbuf *sb)1136{1137struct object_id head;1138int i;11391140if(!get_sha1_tree("HEAD", head.hash)) {1141struct diff_options opt;11421143diff_setup(&opt);1144DIFF_OPT_SET(&opt, EXIT_WITH_STATUS);1145if(!sb)1146DIFF_OPT_SET(&opt, QUICK);1147do_diff_cache(&head, &opt);1148diffcore_std(&opt);1149for(i =0; sb && i < diff_queued_diff.nr; i++) {1150if(i)1151strbuf_addch(sb,' ');1152strbuf_addstr(sb, diff_queued_diff.queue[i]->two->path);1153}1154diff_flush(&opt);1155returnDIFF_OPT_TST(&opt, HAS_CHANGES) !=0;1156}else{1157for(i =0; sb && i < active_nr; i++) {1158if(i)1159strbuf_addch(sb,' ');1160strbuf_addstr(sb, active_cache[i]->name);1161}1162return!!active_nr;1163}1164}11651166/**1167 * Dies with a user-friendly message on how to proceed after resolving the1168 * problem. This message can be overridden with state->resolvemsg.1169 */1170static void NORETURN die_user_resolve(const struct am_state *state)1171{1172if(state->resolvemsg) {1173printf_ln("%s", state->resolvemsg);1174}else{1175const char*cmdline = state->interactive ?"git am -i":"git am";11761177printf_ln(_("When you have resolved this problem, run\"%s--continue\"."), cmdline);1178printf_ln(_("If you prefer to skip this patch, run\"%s--skip\"instead."), cmdline);1179printf_ln(_("To restore the original branch and stop patching, run\"%s--abort\"."), cmdline);1180}11811182exit(128);1183}11841185/**1186 * Appends signoff to the "msg" field of the am_state.1187 */1188static voidam_append_signoff(struct am_state *state)1189{1190char*cp;1191struct strbuf mine = STRBUF_INIT;1192struct strbuf sb = STRBUF_INIT;11931194strbuf_attach(&sb, state->msg, state->msg_len, state->msg_len);11951196/* our sign-off */1197strbuf_addf(&mine,"\n%s%s\n",1198 sign_off_header,1199fmt_name(getenv("GIT_COMMITTER_NAME"),1200getenv("GIT_COMMITTER_EMAIL")));12011202/* Does sb end with it already? */1203if(mine.len < sb.len &&1204!strcmp(mine.buf, sb.buf + sb.len - mine.len))1205goto exit;/* no need to duplicate */12061207/* Does it have any Signed-off-by: in the text */1208for(cp = sb.buf;1209 cp && *cp && (cp =strstr(cp, sign_off_header)) != NULL;1210 cp =strchr(cp,'\n')) {1211if(sb.buf == cp || cp[-1] =='\n')1212break;1213}12141215strbuf_addstr(&sb, mine.buf + !!cp);1216exit:1217strbuf_release(&mine);1218 state->msg =strbuf_detach(&sb, &state->msg_len);1219}12201221/**1222 * Parses `mail` using git-mailinfo, extracting its patch and authorship info.1223 * state->msg will be set to the patch message. state->author_name,1224 * state->author_email and state->author_date will be set to the patch author's1225 * name, email and date respectively. The patch body will be written to the1226 * state directory's "patch" file.1227 *1228 * Returns 1 if the patch should be skipped, 0 otherwise.1229 */1230static intparse_mail(struct am_state *state,const char*mail)1231{1232FILE*fp;1233struct strbuf sb = STRBUF_INIT;1234struct strbuf msg = STRBUF_INIT;1235struct strbuf author_name = STRBUF_INIT;1236struct strbuf author_date = STRBUF_INIT;1237struct strbuf author_email = STRBUF_INIT;1238int ret =0;1239struct mailinfo mi;12401241setup_mailinfo(&mi);12421243if(state->utf8)1244 mi.metainfo_charset =get_commit_output_encoding();1245else1246 mi.metainfo_charset = NULL;12471248switch(state->keep) {1249case KEEP_FALSE:1250break;1251case KEEP_TRUE:1252 mi.keep_subject =1;1253break;1254case KEEP_NON_PATCH:1255 mi.keep_non_patch_brackets_in_subject =1;1256break;1257default:1258die("BUG: invalid value for state->keep");1259}12601261if(state->message_id)1262 mi.add_message_id =1;12631264switch(state->scissors) {1265case SCISSORS_UNSET:1266break;1267case SCISSORS_FALSE:1268 mi.use_scissors =0;1269break;1270case SCISSORS_TRUE:1271 mi.use_scissors =1;1272break;1273default:1274die("BUG: invalid value for state->scissors");1275}12761277 mi.input =xfopen(mail,"r");1278 mi.output =xfopen(am_path(state,"info"),"w");1279if(mailinfo(&mi,am_path(state,"msg"),am_path(state,"patch")))1280die("could not parse patch");12811282fclose(mi.input);1283fclose(mi.output);12841285/* Extract message and author information */1286 fp =xfopen(am_path(state,"info"),"r");1287while(!strbuf_getline_lf(&sb, fp)) {1288const char*x;12891290if(skip_prefix(sb.buf,"Subject: ", &x)) {1291if(msg.len)1292strbuf_addch(&msg,'\n');1293strbuf_addstr(&msg, x);1294}else if(skip_prefix(sb.buf,"Author: ", &x))1295strbuf_addstr(&author_name, x);1296else if(skip_prefix(sb.buf,"Email: ", &x))1297strbuf_addstr(&author_email, x);1298else if(skip_prefix(sb.buf,"Date: ", &x))1299strbuf_addstr(&author_date, x);1300}1301fclose(fp);13021303/* Skip pine's internal folder data */1304if(!strcmp(author_name.buf,"Mail System Internal Data")) {1305 ret =1;1306goto finish;1307}13081309if(is_empty_file(am_path(state,"patch"))) {1310printf_ln(_("Patch is empty."));1311die_user_resolve(state);1312}13131314strbuf_addstr(&msg,"\n\n");1315strbuf_addbuf(&msg, &mi.log_message);1316strbuf_stripspace(&msg,0);13171318assert(!state->author_name);1319 state->author_name =strbuf_detach(&author_name, NULL);13201321assert(!state->author_email);1322 state->author_email =strbuf_detach(&author_email, NULL);13231324assert(!state->author_date);1325 state->author_date =strbuf_detach(&author_date, NULL);13261327assert(!state->msg);1328 state->msg =strbuf_detach(&msg, &state->msg_len);13291330finish:1331strbuf_release(&msg);1332strbuf_release(&author_date);1333strbuf_release(&author_email);1334strbuf_release(&author_name);1335strbuf_release(&sb);1336clear_mailinfo(&mi);1337return ret;1338}13391340/**1341 * Sets commit_id to the commit hash where the mail was generated from.1342 * Returns 0 on success, -1 on failure.1343 */1344static intget_mail_commit_oid(struct object_id *commit_id,const char*mail)1345{1346struct strbuf sb = STRBUF_INIT;1347FILE*fp =xfopen(mail,"r");1348const char*x;1349int ret =0;13501351if(strbuf_getline_lf(&sb, fp) ||1352!skip_prefix(sb.buf,"From ", &x) ||1353get_oid_hex(x, commit_id) <0)1354 ret = -1;13551356strbuf_release(&sb);1357fclose(fp);1358return ret;1359}13601361/**1362 * Sets state->msg, state->author_name, state->author_email, state->author_date1363 * to the commit's respective info.1364 */1365static voidget_commit_info(struct am_state *state,struct commit *commit)1366{1367const char*buffer, *ident_line, *msg;1368size_t ident_len;1369struct ident_split id;13701371 buffer =logmsg_reencode(commit, NULL,get_commit_output_encoding());13721373 ident_line =find_commit_header(buffer,"author", &ident_len);13741375if(split_ident_line(&id, ident_line, ident_len) <0)1376die(_("invalid ident line: %.*s"), (int)ident_len, ident_line);13771378assert(!state->author_name);1379if(id.name_begin)1380 state->author_name =1381xmemdupz(id.name_begin, id.name_end - id.name_begin);1382else1383 state->author_name =xstrdup("");13841385assert(!state->author_email);1386if(id.mail_begin)1387 state->author_email =1388xmemdupz(id.mail_begin, id.mail_end - id.mail_begin);1389else1390 state->author_email =xstrdup("");13911392assert(!state->author_date);1393 state->author_date =xstrdup(show_ident_date(&id,DATE_MODE(NORMAL)));13941395assert(!state->msg);1396 msg =strstr(buffer,"\n\n");1397if(!msg)1398die(_("unable to parse commit%s"),oid_to_hex(&commit->object.oid));1399 state->msg =xstrdup(msg +2);1400 state->msg_len =strlen(state->msg);1401unuse_commit_buffer(commit, buffer);1402}14031404/**1405 * Writes `commit` as a patch to the state directory's "patch" file.1406 */1407static voidwrite_commit_patch(const struct am_state *state,struct commit *commit)1408{1409struct rev_info rev_info;1410FILE*fp;14111412 fp =xfopen(am_path(state,"patch"),"w");1413init_revisions(&rev_info, NULL);1414 rev_info.diff =1;1415 rev_info.abbrev =0;1416 rev_info.disable_stdin =1;1417 rev_info.show_root_diff =1;1418 rev_info.diffopt.output_format = DIFF_FORMAT_PATCH;1419 rev_info.no_commit_id =1;1420DIFF_OPT_SET(&rev_info.diffopt, BINARY);1421DIFF_OPT_SET(&rev_info.diffopt, FULL_INDEX);1422 rev_info.diffopt.use_color =0;1423 rev_info.diffopt.file = fp;1424 rev_info.diffopt.close_file =1;1425add_pending_object(&rev_info, &commit->object,"");1426diff_setup_done(&rev_info.diffopt);1427log_tree_commit(&rev_info, commit);1428}14291430/**1431 * Writes the diff of the index against HEAD as a patch to the state1432 * directory's "patch" file.1433 */1434static voidwrite_index_patch(const struct am_state *state)1435{1436struct tree *tree;1437struct object_id head;1438struct rev_info rev_info;1439FILE*fp;14401441if(!get_sha1_tree("HEAD", head.hash))1442 tree =lookup_tree(&head);1443else1444 tree =lookup_tree(&empty_tree_oid);14451446 fp =xfopen(am_path(state,"patch"),"w");1447init_revisions(&rev_info, NULL);1448 rev_info.diff =1;1449 rev_info.disable_stdin =1;1450 rev_info.no_commit_id =1;1451 rev_info.diffopt.output_format = DIFF_FORMAT_PATCH;1452 rev_info.diffopt.use_color =0;1453 rev_info.diffopt.file = fp;1454 rev_info.diffopt.close_file =1;1455add_pending_object(&rev_info, &tree->object,"");1456diff_setup_done(&rev_info.diffopt);1457run_diff_index(&rev_info,1);1458}14591460/**1461 * Like parse_mail(), but parses the mail by looking up its commit ID1462 * directly. This is used in --rebasing mode to bypass git-mailinfo's munging1463 * of patches.1464 *1465 * state->orig_commit will be set to the original commit ID.1466 *1467 * Will always return 0 as the patch should never be skipped.1468 */1469static intparse_mail_rebase(struct am_state *state,const char*mail)1470{1471struct commit *commit;1472struct object_id commit_oid;14731474if(get_mail_commit_oid(&commit_oid, mail) <0)1475die(_("could not parse%s"), mail);14761477 commit =lookup_commit_or_die(&commit_oid, mail);14781479get_commit_info(state, commit);14801481write_commit_patch(state, commit);14821483oidcpy(&state->orig_commit, &commit_oid);1484write_state_text(state,"original-commit",oid_to_hex(&commit_oid));14851486return0;1487}14881489/**1490 * Applies current patch with git-apply. Returns 0 on success, -1 otherwise. If1491 * `index_file` is not NULL, the patch will be applied to that index.1492 */1493static intrun_apply(const struct am_state *state,const char*index_file)1494{1495struct argv_array apply_paths = ARGV_ARRAY_INIT;1496struct argv_array apply_opts = ARGV_ARRAY_INIT;1497struct apply_state apply_state;1498int res, opts_left;1499static struct lock_file lock_file;1500int force_apply =0;1501int options =0;15021503if(init_apply_state(&apply_state, NULL, &lock_file))1504die("BUG: init_apply_state() failed");15051506argv_array_push(&apply_opts,"apply");1507argv_array_pushv(&apply_opts, state->git_apply_opts.argv);15081509 opts_left =apply_parse_options(apply_opts.argc, apply_opts.argv,1510&apply_state, &force_apply, &options,1511 NULL);15121513if(opts_left !=0)1514die("unknown option passed through to git apply");15151516if(index_file) {1517 apply_state.index_file = index_file;1518 apply_state.cached =1;1519}else1520 apply_state.check_index =1;15211522/*1523 * If we are allowed to fall back on 3-way merge, don't give false1524 * errors during the initial attempt.1525 */1526if(state->threeway && !index_file)1527 apply_state.apply_verbosity = verbosity_silent;15281529if(check_apply_state(&apply_state, force_apply))1530die("BUG: check_apply_state() failed");15311532argv_array_push(&apply_paths,am_path(state,"patch"));15331534 res =apply_all_patches(&apply_state, apply_paths.argc, apply_paths.argv, options);15351536argv_array_clear(&apply_paths);1537argv_array_clear(&apply_opts);1538clear_apply_state(&apply_state);15391540if(res)1541return res;15421543if(index_file) {1544/* Reload index as apply_all_patches() will have modified it. */1545discard_cache();1546read_cache_from(index_file);1547}15481549return0;1550}15511552/**1553 * Builds an index that contains just the blobs needed for a 3way merge.1554 */1555static intbuild_fake_ancestor(const struct am_state *state,const char*index_file)1556{1557struct child_process cp = CHILD_PROCESS_INIT;15581559 cp.git_cmd =1;1560argv_array_push(&cp.args,"apply");1561argv_array_pushv(&cp.args, state->git_apply_opts.argv);1562argv_array_pushf(&cp.args,"--build-fake-ancestor=%s", index_file);1563argv_array_push(&cp.args,am_path(state,"patch"));15641565if(run_command(&cp))1566return-1;15671568return0;1569}15701571/**1572 * Attempt a threeway merge, using index_path as the temporary index.1573 */1574static intfall_back_threeway(const struct am_state *state,const char*index_path)1575{1576struct object_id orig_tree, their_tree, our_tree;1577const struct object_id *bases[1] = { &orig_tree };1578struct merge_options o;1579struct commit *result;1580char*their_tree_name;15811582if(get_oid("HEAD", &our_tree) <0)1583hashcpy(our_tree.hash, EMPTY_TREE_SHA1_BIN);15841585if(build_fake_ancestor(state, index_path))1586returnerror("could not build fake ancestor");15871588discard_cache();1589read_cache_from(index_path);15901591if(write_index_as_tree(orig_tree.hash, &the_index, index_path,0, NULL))1592returnerror(_("Repository lacks necessary blobs to fall back on 3-way merge."));15931594say(state, stdout,_("Using index info to reconstruct a base tree..."));15951596if(!state->quiet) {1597/*1598 * List paths that needed 3-way fallback, so that the user can1599 * review them with extra care to spot mismerges.1600 */1601struct rev_info rev_info;1602const char*diff_filter_str ="--diff-filter=AM";16031604init_revisions(&rev_info, NULL);1605 rev_info.diffopt.output_format = DIFF_FORMAT_NAME_STATUS;1606diff_opt_parse(&rev_info.diffopt, &diff_filter_str,1, rev_info.prefix);1607add_pending_oid(&rev_info,"HEAD", &our_tree,0);1608diff_setup_done(&rev_info.diffopt);1609run_diff_index(&rev_info,1);1610}16111612if(run_apply(state, index_path))1613returnerror(_("Did you hand edit your patch?\n"1614"It does not apply to blobs recorded in its index."));16151616if(write_index_as_tree(their_tree.hash, &the_index, index_path,0, NULL))1617returnerror("could not write tree");16181619say(state, stdout,_("Falling back to patching base and 3-way merge..."));16201621discard_cache();1622read_cache();16231624/*1625 * This is not so wrong. Depending on which base we picked, orig_tree1626 * may be wildly different from ours, but their_tree has the same set of1627 * wildly different changes in parts the patch did not touch, so1628 * recursive ends up canceling them, saying that we reverted all those1629 * changes.1630 */16311632init_merge_options(&o);16331634 o.branch1 ="HEAD";1635 their_tree_name =xstrfmt("%.*s",linelen(state->msg), state->msg);1636 o.branch2 = their_tree_name;16371638if(state->quiet)1639 o.verbosity =0;16401641if(merge_recursive_generic(&o, &our_tree, &their_tree,1, bases, &result)) {1642rerere(state->allow_rerere_autoupdate);1643free(their_tree_name);1644returnerror(_("Failed to merge in the changes."));1645}16461647free(their_tree_name);1648return0;1649}16501651/**1652 * Commits the current index with state->msg as the commit message and1653 * state->author_name, state->author_email and state->author_date as the author1654 * information.1655 */1656static voiddo_commit(const struct am_state *state)1657{1658struct object_id tree, parent, commit;1659const struct object_id *old_oid;1660struct commit_list *parents = NULL;1661const char*reflog_msg, *author;1662struct strbuf sb = STRBUF_INIT;16631664if(run_hook_le(NULL,"pre-applypatch", NULL))1665exit(1);16661667if(write_cache_as_tree(tree.hash,0, NULL))1668die(_("git write-tree failed to write a tree"));16691670if(!get_sha1_commit("HEAD", parent.hash)) {1671 old_oid = &parent;1672commit_list_insert(lookup_commit(&parent), &parents);1673}else{1674 old_oid = NULL;1675say(state, stderr,_("applying to an empty history"));1676}16771678 author =fmt_ident(state->author_name, state->author_email,1679 state->ignore_date ? NULL : state->author_date,1680 IDENT_STRICT);16811682if(state->committer_date_is_author_date)1683setenv("GIT_COMMITTER_DATE",1684 state->ignore_date ?"": state->author_date,1);16851686if(commit_tree(state->msg, state->msg_len, tree.hash, parents, commit.hash,1687 author, state->sign_commit))1688die(_("failed to write commit object"));16891690 reflog_msg =getenv("GIT_REFLOG_ACTION");1691if(!reflog_msg)1692 reflog_msg ="am";16931694strbuf_addf(&sb,"%s: %.*s", reflog_msg,linelen(state->msg),1695 state->msg);16961697update_ref_oid(sb.buf,"HEAD", &commit, old_oid,0,1698 UPDATE_REFS_DIE_ON_ERR);16991700if(state->rebasing) {1701FILE*fp =xfopen(am_path(state,"rewritten"),"a");17021703assert(!is_null_oid(&state->orig_commit));1704fprintf(fp,"%s",oid_to_hex(&state->orig_commit));1705fprintf(fp,"%s\n",oid_to_hex(&commit));1706fclose(fp);1707}17081709run_hook_le(NULL,"post-applypatch", NULL);17101711strbuf_release(&sb);1712}17131714/**1715 * Validates the am_state for resuming -- the "msg" and authorship fields must1716 * be filled up.1717 */1718static voidvalidate_resume_state(const struct am_state *state)1719{1720if(!state->msg)1721die(_("cannot resume:%sdoes not exist."),1722am_path(state,"final-commit"));17231724if(!state->author_name || !state->author_email || !state->author_date)1725die(_("cannot resume:%sdoes not exist."),1726am_path(state,"author-script"));1727}17281729/**1730 * Interactively prompt the user on whether the current patch should be1731 * applied.1732 *1733 * Returns 0 if the user chooses to apply the patch, 1 if the user chooses to1734 * skip it.1735 */1736static intdo_interactive(struct am_state *state)1737{1738assert(state->msg);17391740if(!isatty(0))1741die(_("cannot be interactive without stdin connected to a terminal."));17421743for(;;) {1744const char*reply;17451746puts(_("Commit Body is:"));1747puts("--------------------------");1748printf("%s", state->msg);1749puts("--------------------------");17501751/*1752 * TRANSLATORS: Make sure to include [y], [n], [e], [v] and [a]1753 * in your translation. The program will only accept English1754 * input at this point.1755 */1756 reply =git_prompt(_("Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all: "), PROMPT_ECHO);17571758if(!reply) {1759continue;1760}else if(*reply =='y'|| *reply =='Y') {1761return0;1762}else if(*reply =='a'|| *reply =='A') {1763 state->interactive =0;1764return0;1765}else if(*reply =='n'|| *reply =='N') {1766return1;1767}else if(*reply =='e'|| *reply =='E') {1768struct strbuf msg = STRBUF_INIT;17691770if(!launch_editor(am_path(state,"final-commit"), &msg, NULL)) {1771free(state->msg);1772 state->msg =strbuf_detach(&msg, &state->msg_len);1773}1774strbuf_release(&msg);1775}else if(*reply =='v'|| *reply =='V') {1776const char*pager =git_pager(1);1777struct child_process cp = CHILD_PROCESS_INIT;17781779if(!pager)1780 pager ="cat";1781prepare_pager_args(&cp, pager);1782argv_array_push(&cp.args,am_path(state,"patch"));1783run_command(&cp);1784}1785}1786}17871788/**1789 * Applies all queued mail.1790 *1791 * If `resume` is true, we are "resuming". The "msg" and authorship fields, as1792 * well as the state directory's "patch" file is used as-is for applying the1793 * patch and committing it.1794 */1795static voidam_run(struct am_state *state,int resume)1796{1797const char*argv_gc_auto[] = {"gc","--auto", NULL};1798struct strbuf sb = STRBUF_INIT;17991800unlink(am_path(state,"dirtyindex"));18011802refresh_and_write_cache();18031804if(index_has_changes(&sb)) {1805write_state_bool(state,"dirtyindex",1);1806die(_("Dirty index: cannot apply patches (dirty:%s)"), sb.buf);1807}18081809strbuf_release(&sb);18101811while(state->cur <= state->last) {1812const char*mail =am_path(state,msgnum(state));1813int apply_status;18141815reset_ident_date();18161817if(!file_exists(mail))1818goto next;18191820if(resume) {1821validate_resume_state(state);1822}else{1823int skip;18241825if(state->rebasing)1826 skip =parse_mail_rebase(state, mail);1827else1828 skip =parse_mail(state, mail);18291830if(skip)1831goto next;/* mail should be skipped */18321833if(state->signoff)1834am_append_signoff(state);18351836write_author_script(state);1837write_commit_msg(state);1838}18391840if(state->interactive &&do_interactive(state))1841goto next;18421843if(run_applypatch_msg_hook(state))1844exit(1);18451846say(state, stdout,_("Applying: %.*s"),linelen(state->msg), state->msg);18471848 apply_status =run_apply(state, NULL);18491850if(apply_status && state->threeway) {1851struct strbuf sb = STRBUF_INIT;18521853strbuf_addstr(&sb,am_path(state,"patch-merge-index"));1854 apply_status =fall_back_threeway(state, sb.buf);1855strbuf_release(&sb);18561857/*1858 * Applying the patch to an earlier tree and merging1859 * the result may have produced the same tree as ours.1860 */1861if(!apply_status && !index_has_changes(NULL)) {1862say(state, stdout,_("No changes -- Patch already applied."));1863goto next;1864}1865}18661867if(apply_status) {1868int advice_amworkdir =1;18691870printf_ln(_("Patch failed at%s%.*s"),msgnum(state),1871linelen(state->msg), state->msg);18721873git_config_get_bool("advice.amworkdir", &advice_amworkdir);18741875if(advice_amworkdir)1876printf_ln(_("The copy of the patch that failed is found in:%s"),1877am_path(state,"patch"));18781879die_user_resolve(state);1880}18811882do_commit(state);18831884next:1885am_next(state);18861887if(resume)1888am_load(state);1889 resume =0;1890}18911892if(!is_empty_file(am_path(state,"rewritten"))) {1893assert(state->rebasing);1894copy_notes_for_rebase(state);1895run_post_rewrite_hook(state);1896}18971898/*1899 * In rebasing mode, it's up to the caller to take care of1900 * housekeeping.1901 */1902if(!state->rebasing) {1903am_destroy(state);1904close_all_packs();1905run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);1906}1907}19081909/**1910 * Resume the current am session after patch application failure. The user did1911 * all the hard work, and we do not have to do any patch application. Just1912 * trust and commit what the user has in the index and working tree.1913 */1914static voidam_resolve(struct am_state *state)1915{1916validate_resume_state(state);19171918say(state, stdout,_("Applying: %.*s"),linelen(state->msg), state->msg);19191920if(!index_has_changes(NULL)) {1921printf_ln(_("No changes - did you forget to use 'git add'?\n"1922"If there is nothing left to stage, chances are that something else\n"1923"already introduced the same changes; you might want to skip this patch."));1924die_user_resolve(state);1925}19261927if(unmerged_cache()) {1928printf_ln(_("You still have unmerged paths in your index.\n"1929"You should 'git add' each file with resolved conflicts to mark them as such.\n"1930"You might run `git rm` on a file to accept\"deleted by them\"for it."));1931die_user_resolve(state);1932}19331934if(state->interactive) {1935write_index_patch(state);1936if(do_interactive(state))1937goto next;1938}19391940rerere(0);19411942do_commit(state);19431944next:1945am_next(state);1946am_load(state);1947am_run(state,0);1948}19491950/**1951 * Performs a checkout fast-forward from `head` to `remote`. If `reset` is1952 * true, any unmerged entries will be discarded. Returns 0 on success, -1 on1953 * failure.1954 */1955static intfast_forward_to(struct tree *head,struct tree *remote,int reset)1956{1957struct lock_file *lock_file;1958struct unpack_trees_options opts;1959struct tree_desc t[2];19601961if(parse_tree(head) ||parse_tree(remote))1962return-1;19631964 lock_file =xcalloc(1,sizeof(struct lock_file));1965hold_locked_index(lock_file, LOCK_DIE_ON_ERROR);19661967refresh_cache(REFRESH_QUIET);19681969memset(&opts,0,sizeof(opts));1970 opts.head_idx =1;1971 opts.src_index = &the_index;1972 opts.dst_index = &the_index;1973 opts.update =1;1974 opts.merge =1;1975 opts.reset = reset;1976 opts.fn = twoway_merge;1977init_tree_desc(&t[0], head->buffer, head->size);1978init_tree_desc(&t[1], remote->buffer, remote->size);19791980if(unpack_trees(2, t, &opts)) {1981rollback_lock_file(lock_file);1982return-1;1983}19841985if(write_locked_index(&the_index, lock_file, COMMIT_LOCK))1986die(_("unable to write new index file"));19871988return0;1989}19901991/**1992 * Merges a tree into the index. The index's stat info will take precedence1993 * over the merged tree's. Returns 0 on success, -1 on failure.1994 */1995static intmerge_tree(struct tree *tree)1996{1997struct lock_file *lock_file;1998struct unpack_trees_options opts;1999struct tree_desc t[1];20002001if(parse_tree(tree))2002return-1;20032004 lock_file =xcalloc(1,sizeof(struct lock_file));2005hold_locked_index(lock_file, LOCK_DIE_ON_ERROR);20062007memset(&opts,0,sizeof(opts));2008 opts.head_idx =1;2009 opts.src_index = &the_index;2010 opts.dst_index = &the_index;2011 opts.merge =1;2012 opts.fn = oneway_merge;2013init_tree_desc(&t[0], tree->buffer, tree->size);20142015if(unpack_trees(1, t, &opts)) {2016rollback_lock_file(lock_file);2017return-1;2018}20192020if(write_locked_index(&the_index, lock_file, COMMIT_LOCK))2021die(_("unable to write new index file"));20222023return0;2024}20252026/**2027 * Clean the index without touching entries that are not modified between2028 * `head` and `remote`.2029 */2030static intclean_index(const struct object_id *head,const struct object_id *remote)2031{2032struct tree *head_tree, *remote_tree, *index_tree;2033struct object_id index;20342035 head_tree =parse_tree_indirect(head);2036if(!head_tree)2037returnerror(_("Could not parse object '%s'."),oid_to_hex(head));20382039 remote_tree =parse_tree_indirect(remote);2040if(!remote_tree)2041returnerror(_("Could not parse object '%s'."),oid_to_hex(remote));20422043read_cache_unmerged();20442045if(fast_forward_to(head_tree, head_tree,1))2046return-1;20472048if(write_cache_as_tree(index.hash,0, NULL))2049return-1;20502051 index_tree =parse_tree_indirect(&index);2052if(!index_tree)2053returnerror(_("Could not parse object '%s'."),oid_to_hex(&index));20542055if(fast_forward_to(index_tree, remote_tree,0))2056return-1;20572058if(merge_tree(remote_tree))2059return-1;20602061remove_branch_state();20622063return0;2064}20652066/**2067 * Resets rerere's merge resolution metadata.2068 */2069static voidam_rerere_clear(void)2070{2071struct string_list merge_rr = STRING_LIST_INIT_DUP;2072rerere_clear(&merge_rr);2073string_list_clear(&merge_rr,1);2074}20752076/**2077 * Resume the current am session by skipping the current patch.2078 */2079static voidam_skip(struct am_state *state)2080{2081struct object_id head;20822083am_rerere_clear();20842085if(get_oid("HEAD", &head))2086hashcpy(head.hash, EMPTY_TREE_SHA1_BIN);20872088if(clean_index(&head, &head))2089die(_("failed to clean index"));20902091am_next(state);2092am_load(state);2093am_run(state,0);2094}20952096/**2097 * Returns true if it is safe to reset HEAD to the ORIG_HEAD, false otherwise.2098 *2099 * It is not safe to reset HEAD when:2100 * 1. git-am previously failed because the index was dirty.2101 * 2. HEAD has moved since git-am previously failed.2102 */2103static intsafe_to_abort(const struct am_state *state)2104{2105struct strbuf sb = STRBUF_INIT;2106struct object_id abort_safety, head;21072108if(file_exists(am_path(state,"dirtyindex")))2109return0;21102111if(read_state_file(&sb, state,"abort-safety",1) >0) {2112if(get_oid_hex(sb.buf, &abort_safety))2113die(_("could not parse%s"),am_path(state,"abort-safety"));2114}else2115oidclr(&abort_safety);21162117if(get_oid("HEAD", &head))2118oidclr(&head);21192120if(!oidcmp(&head, &abort_safety))2121return1;21222123warning(_("You seem to have moved HEAD since the last 'am' failure.\n"2124"Not rewinding to ORIG_HEAD"));21252126return0;2127}21282129/**2130 * Aborts the current am session if it is safe to do so.2131 */2132static voidam_abort(struct am_state *state)2133{2134struct object_id curr_head, orig_head;2135int has_curr_head, has_orig_head;2136char*curr_branch;21372138if(!safe_to_abort(state)) {2139am_destroy(state);2140return;2141}21422143am_rerere_clear();21442145 curr_branch =resolve_refdup("HEAD",0, curr_head.hash, NULL);2146 has_curr_head = curr_branch && !is_null_oid(&curr_head);2147if(!has_curr_head)2148hashcpy(curr_head.hash, EMPTY_TREE_SHA1_BIN);21492150 has_orig_head = !get_oid("ORIG_HEAD", &orig_head);2151if(!has_orig_head)2152hashcpy(orig_head.hash, EMPTY_TREE_SHA1_BIN);21532154clean_index(&curr_head, &orig_head);21552156if(has_orig_head)2157update_ref_oid("am --abort","HEAD", &orig_head,2158 has_curr_head ? &curr_head : NULL,0,2159 UPDATE_REFS_DIE_ON_ERR);2160else if(curr_branch)2161delete_ref(NULL, curr_branch, NULL, REF_NODEREF);21622163free(curr_branch);2164am_destroy(state);2165}21662167/**2168 * parse_options() callback that validates and sets opt->value to the2169 * PATCH_FORMAT_* enum value corresponding to `arg`.2170 */2171static intparse_opt_patchformat(const struct option *opt,const char*arg,int unset)2172{2173int*opt_value = opt->value;21742175if(!strcmp(arg,"mbox"))2176*opt_value = PATCH_FORMAT_MBOX;2177else if(!strcmp(arg,"stgit"))2178*opt_value = PATCH_FORMAT_STGIT;2179else if(!strcmp(arg,"stgit-series"))2180*opt_value = PATCH_FORMAT_STGIT_SERIES;2181else if(!strcmp(arg,"hg"))2182*opt_value = PATCH_FORMAT_HG;2183else if(!strcmp(arg,"mboxrd"))2184*opt_value = PATCH_FORMAT_MBOXRD;2185else2186returnerror(_("Invalid value for --patch-format:%s"), arg);2187return0;2188}21892190enum resume_mode {2191 RESUME_FALSE =0,2192 RESUME_APPLY,2193 RESUME_RESOLVED,2194 RESUME_SKIP,2195 RESUME_ABORT2196};21972198static intgit_am_config(const char*k,const char*v,void*cb)2199{2200int status;22012202 status =git_gpg_config(k, v, NULL);2203if(status)2204return status;22052206returngit_default_config(k, v, NULL);2207}22082209intcmd_am(int argc,const char**argv,const char*prefix)2210{2211struct am_state state;2212int binary = -1;2213int keep_cr = -1;2214int patch_format = PATCH_FORMAT_UNKNOWN;2215enum resume_mode resume = RESUME_FALSE;2216int in_progress;22172218const char*const usage[] = {2219N_("git am [<options>] [(<mbox> | <Maildir>)...]"),2220N_("git am [<options>] (--continue | --skip | --abort)"),2221 NULL2222};22232224struct option options[] = {2225OPT_BOOL('i',"interactive", &state.interactive,2226N_("run interactively")),2227OPT_HIDDEN_BOOL('b',"binary", &binary,2228N_("historical option -- no-op")),2229OPT_BOOL('3',"3way", &state.threeway,2230N_("allow fall back on 3way merging if needed")),2231OPT__QUIET(&state.quiet,N_("be quiet")),2232OPT_SET_INT('s',"signoff", &state.signoff,2233N_("add a Signed-off-by line to the commit message"),2234 SIGNOFF_EXPLICIT),2235OPT_BOOL('u',"utf8", &state.utf8,2236N_("recode into utf8 (default)")),2237OPT_SET_INT('k',"keep", &state.keep,2238N_("pass -k flag to git-mailinfo"), KEEP_TRUE),2239OPT_SET_INT(0,"keep-non-patch", &state.keep,2240N_("pass -b flag to git-mailinfo"), KEEP_NON_PATCH),2241OPT_BOOL('m',"message-id", &state.message_id,2242N_("pass -m flag to git-mailinfo")),2243{ OPTION_SET_INT,0,"keep-cr", &keep_cr, NULL,2244N_("pass --keep-cr flag to git-mailsplit for mbox format"),2245 PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL,1},2246{ OPTION_SET_INT,0,"no-keep-cr", &keep_cr, NULL,2247N_("do not pass --keep-cr flag to git-mailsplit independent of am.keepcr"),2248 PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL,0},2249OPT_BOOL('c',"scissors", &state.scissors,2250N_("strip everything before a scissors line")),2251OPT_PASSTHRU_ARGV(0,"whitespace", &state.git_apply_opts,N_("action"),2252N_("pass it through git-apply"),22530),2254OPT_PASSTHRU_ARGV(0,"ignore-space-change", &state.git_apply_opts, NULL,2255N_("pass it through git-apply"),2256 PARSE_OPT_NOARG),2257OPT_PASSTHRU_ARGV(0,"ignore-whitespace", &state.git_apply_opts, NULL,2258N_("pass it through git-apply"),2259 PARSE_OPT_NOARG),2260OPT_PASSTHRU_ARGV(0,"directory", &state.git_apply_opts,N_("root"),2261N_("pass it through git-apply"),22620),2263OPT_PASSTHRU_ARGV(0,"exclude", &state.git_apply_opts,N_("path"),2264N_("pass it through git-apply"),22650),2266OPT_PASSTHRU_ARGV(0,"include", &state.git_apply_opts,N_("path"),2267N_("pass it through git-apply"),22680),2269OPT_PASSTHRU_ARGV('C', NULL, &state.git_apply_opts,N_("n"),2270N_("pass it through git-apply"),22710),2272OPT_PASSTHRU_ARGV('p', NULL, &state.git_apply_opts,N_("num"),2273N_("pass it through git-apply"),22740),2275OPT_CALLBACK(0,"patch-format", &patch_format,N_("format"),2276N_("format the patch(es) are in"),2277 parse_opt_patchformat),2278OPT_PASSTHRU_ARGV(0,"reject", &state.git_apply_opts, NULL,2279N_("pass it through git-apply"),2280 PARSE_OPT_NOARG),2281OPT_STRING(0,"resolvemsg", &state.resolvemsg, NULL,2282N_("override error message when patch failure occurs")),2283OPT_CMDMODE(0,"continue", &resume,2284N_("continue applying patches after resolving a conflict"),2285 RESUME_RESOLVED),2286OPT_CMDMODE('r',"resolved", &resume,2287N_("synonyms for --continue"),2288 RESUME_RESOLVED),2289OPT_CMDMODE(0,"skip", &resume,2290N_("skip the current patch"),2291 RESUME_SKIP),2292OPT_CMDMODE(0,"abort", &resume,2293N_("restore the original branch and abort the patching operation."),2294 RESUME_ABORT),2295OPT_BOOL(0,"committer-date-is-author-date",2296&state.committer_date_is_author_date,2297N_("lie about committer date")),2298OPT_BOOL(0,"ignore-date", &state.ignore_date,2299N_("use current timestamp for author date")),2300OPT_RERERE_AUTOUPDATE(&state.allow_rerere_autoupdate),2301{ OPTION_STRING,'S',"gpg-sign", &state.sign_commit,N_("key-id"),2302N_("GPG-sign commits"),2303 PARSE_OPT_OPTARG, NULL, (intptr_t)""},2304OPT_HIDDEN_BOOL(0,"rebasing", &state.rebasing,2305N_("(internal use for git-rebase)")),2306OPT_END()2307};23082309if(argc ==2&& !strcmp(argv[1],"-h"))2310usage_with_options(usage, options);23112312git_config(git_am_config, NULL);23132314am_state_init(&state);23152316 in_progress =am_in_progress(&state);2317if(in_progress)2318am_load(&state);23192320 argc =parse_options(argc, argv, prefix, options, usage,0);23212322if(binary >=0)2323fprintf_ln(stderr,_("The -b/--binary option has been a no-op for long time, and\n"2324"it will be removed. Please do not use it anymore."));23252326/* Ensure a valid committer ident can be constructed */2327git_committer_info(IDENT_STRICT);23282329if(read_index_preload(&the_index, NULL) <0)2330die(_("failed to read the index"));23312332if(in_progress) {2333/*2334 * Catch user error to feed us patches when there is a session2335 * in progress:2336 *2337 * 1. mbox path(s) are provided on the command-line.2338 * 2. stdin is not a tty: the user is trying to feed us a patch2339 * from standard input. This is somewhat unreliable -- stdin2340 * could be /dev/null for example and the caller did not2341 * intend to feed us a patch but wanted to continue2342 * unattended.2343 */2344if(argc || (resume == RESUME_FALSE && !isatty(0)))2345die(_("previous rebase directory%sstill exists but mbox given."),2346 state.dir);23472348if(resume == RESUME_FALSE)2349 resume = RESUME_APPLY;23502351if(state.signoff == SIGNOFF_EXPLICIT)2352am_append_signoff(&state);2353}else{2354struct argv_array paths = ARGV_ARRAY_INIT;2355int i;23562357/*2358 * Handle stray state directory in the independent-run case. In2359 * the --rebasing case, it is up to the caller to take care of2360 * stray directories.2361 */2362if(file_exists(state.dir) && !state.rebasing) {2363if(resume == RESUME_ABORT) {2364am_destroy(&state);2365am_state_release(&state);2366return0;2367}23682369die(_("Stray%sdirectory found.\n"2370"Use\"git am --abort\"to remove it."),2371 state.dir);2372}23732374if(resume)2375die(_("Resolve operation not in progress, we are not resuming."));23762377for(i =0; i < argc; i++) {2378if(is_absolute_path(argv[i]) || !prefix)2379argv_array_push(&paths, argv[i]);2380else2381argv_array_push(&paths,mkpath("%s/%s", prefix, argv[i]));2382}23832384am_setup(&state, patch_format, paths.argv, keep_cr);23852386argv_array_clear(&paths);2387}23882389switch(resume) {2390case RESUME_FALSE:2391am_run(&state,0);2392break;2393case RESUME_APPLY:2394am_run(&state,1);2395break;2396case RESUME_RESOLVED:2397am_resolve(&state);2398break;2399case RESUME_SKIP:2400am_skip(&state);2401break;2402case RESUME_ABORT:2403am_abort(&state);2404break;2405default:2406die("BUG: invalid resume value");2407}24082409am_state_release(&state);24102411return0;2412}