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 32/** 33 * Returns 1 if the file is empty or does not exist, 0 otherwise. 34 */ 35static intis_empty_file(const char*filename) 36{ 37struct stat st; 38 39if(stat(filename, &st) <0) { 40if(errno == ENOENT) 41return1; 42die_errno(_("could not stat%s"), filename); 43} 44 45return!st.st_size; 46} 47 48/** 49 * Returns the length of the first line of msg. 50 */ 51static intlinelen(const char*msg) 52{ 53returnstrchrnul(msg,'\n') - msg; 54} 55 56/** 57 * Returns true if `str` consists of only whitespace, false otherwise. 58 */ 59static intstr_isspace(const char*str) 60{ 61for(; *str; str++) 62if(!isspace(*str)) 63return0; 64 65return1; 66} 67 68enum patch_format { 69 PATCH_FORMAT_UNKNOWN =0, 70 PATCH_FORMAT_MBOX, 71 PATCH_FORMAT_STGIT, 72 PATCH_FORMAT_STGIT_SERIES, 73 PATCH_FORMAT_HG, 74 PATCH_FORMAT_MBOXRD 75}; 76 77enum keep_type { 78 KEEP_FALSE =0, 79 KEEP_TRUE,/* pass -k flag to git-mailinfo */ 80 KEEP_NON_PATCH /* pass -b flag to git-mailinfo */ 81}; 82 83enum scissors_type { 84 SCISSORS_UNSET = -1, 85 SCISSORS_FALSE =0,/* pass --no-scissors to git-mailinfo */ 86 SCISSORS_TRUE /* pass --scissors to git-mailinfo */ 87}; 88 89enum signoff_type { 90 SIGNOFF_FALSE =0, 91 SIGNOFF_TRUE =1, 92 SIGNOFF_EXPLICIT /* --signoff was set on the command-line */ 93}; 94 95struct am_state { 96/* state directory path */ 97char*dir; 98 99/* current and last patch numbers, 1-indexed */ 100int cur; 101int last; 102 103/* commit metadata and message */ 104char*author_name; 105char*author_email; 106char*author_date; 107char*msg; 108size_t msg_len; 109 110/* when --rebasing, records the original commit the patch came from */ 111unsigned char orig_commit[GIT_SHA1_RAWSZ]; 112 113/* number of digits in patch filename */ 114int prec; 115 116/* various operating modes and command line options */ 117int interactive; 118int threeway; 119int quiet; 120int signoff;/* enum signoff_type */ 121int utf8; 122int keep;/* enum keep_type */ 123int message_id; 124int scissors;/* enum scissors_type */ 125struct argv_array git_apply_opts; 126const char*resolvemsg; 127int committer_date_is_author_date; 128int ignore_date; 129int allow_rerere_autoupdate; 130const char*sign_commit; 131int rebasing; 132}; 133 134/** 135 * Initializes am_state with the default values. The state directory is set to 136 * dir. 137 */ 138static voidam_state_init(struct am_state *state,const char*dir) 139{ 140int gpgsign; 141 142memset(state,0,sizeof(*state)); 143 144assert(dir); 145 state->dir =xstrdup(dir); 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 * Reads a KEY=VALUE shell variable assignment from `fp`, returning the VALUE 262 * as a newly-allocated string. VALUE must be a quoted string, and the KEY must 263 * match `key`. Returns NULL on failure. 264 * 265 * This is used by read_author_script() to read the GIT_AUTHOR_* variables from 266 * the author-script. 267 */ 268static char*read_shell_var(FILE*fp,const char*key) 269{ 270struct strbuf sb = STRBUF_INIT; 271const char*str; 272 273if(strbuf_getline_lf(&sb, fp)) 274goto fail; 275 276if(!skip_prefix(sb.buf, key, &str)) 277goto fail; 278 279if(!skip_prefix(str,"=", &str)) 280goto fail; 281 282strbuf_remove(&sb,0, str - sb.buf); 283 284 str =sq_dequote(sb.buf); 285if(!str) 286goto fail; 287 288returnstrbuf_detach(&sb, NULL); 289 290fail: 291strbuf_release(&sb); 292return NULL; 293} 294 295/** 296 * Reads and parses the state directory's "author-script" file, and sets 297 * state->author_name, state->author_email and state->author_date accordingly. 298 * Returns 0 on success, -1 if the file could not be parsed. 299 * 300 * The author script is of the format: 301 * 302 * GIT_AUTHOR_NAME='$author_name' 303 * GIT_AUTHOR_EMAIL='$author_email' 304 * GIT_AUTHOR_DATE='$author_date' 305 * 306 * where $author_name, $author_email and $author_date are quoted. We are strict 307 * with our parsing, as the file was meant to be eval'd in the old git-am.sh 308 * script, and thus if the file differs from what this function expects, it is 309 * better to bail out than to do something that the user does not expect. 310 */ 311static intread_author_script(struct am_state *state) 312{ 313const char*filename =am_path(state,"author-script"); 314FILE*fp; 315 316assert(!state->author_name); 317assert(!state->author_email); 318assert(!state->author_date); 319 320 fp =fopen(filename,"r"); 321if(!fp) { 322if(errno == ENOENT) 323return0; 324die_errno(_("could not open '%s' for reading"), filename); 325} 326 327 state->author_name =read_shell_var(fp,"GIT_AUTHOR_NAME"); 328if(!state->author_name) { 329fclose(fp); 330return-1; 331} 332 333 state->author_email =read_shell_var(fp,"GIT_AUTHOR_EMAIL"); 334if(!state->author_email) { 335fclose(fp); 336return-1; 337} 338 339 state->author_date =read_shell_var(fp,"GIT_AUTHOR_DATE"); 340if(!state->author_date) { 341fclose(fp); 342return-1; 343} 344 345if(fgetc(fp) != EOF) { 346fclose(fp); 347return-1; 348} 349 350fclose(fp); 351return0; 352} 353 354/** 355 * Saves state->author_name, state->author_email and state->author_date in the 356 * state directory's "author-script" file. 357 */ 358static voidwrite_author_script(const struct am_state *state) 359{ 360struct strbuf sb = STRBUF_INIT; 361 362strbuf_addstr(&sb,"GIT_AUTHOR_NAME="); 363sq_quote_buf(&sb, state->author_name); 364strbuf_addch(&sb,'\n'); 365 366strbuf_addstr(&sb,"GIT_AUTHOR_EMAIL="); 367sq_quote_buf(&sb, state->author_email); 368strbuf_addch(&sb,'\n'); 369 370strbuf_addstr(&sb,"GIT_AUTHOR_DATE="); 371sq_quote_buf(&sb, state->author_date); 372strbuf_addch(&sb,'\n'); 373 374write_state_text(state,"author-script", sb.buf); 375 376strbuf_release(&sb); 377} 378 379/** 380 * Reads the commit message from the state directory's "final-commit" file, 381 * setting state->msg to its contents and state->msg_len to the length of its 382 * contents in bytes. 383 * 384 * Returns 0 on success, -1 if the file does not exist. 385 */ 386static intread_commit_msg(struct am_state *state) 387{ 388struct strbuf sb = STRBUF_INIT; 389 390assert(!state->msg); 391 392if(read_state_file(&sb, state,"final-commit",0) <0) { 393strbuf_release(&sb); 394return-1; 395} 396 397 state->msg =strbuf_detach(&sb, &state->msg_len); 398return0; 399} 400 401/** 402 * Saves state->msg in the state directory's "final-commit" file. 403 */ 404static voidwrite_commit_msg(const struct am_state *state) 405{ 406const char*filename =am_path(state,"final-commit"); 407write_file_buf(filename, state->msg, state->msg_len); 408} 409 410/** 411 * Loads state from disk. 412 */ 413static voidam_load(struct am_state *state) 414{ 415struct strbuf sb = STRBUF_INIT; 416 417if(read_state_file(&sb, state,"next",1) <0) 418die("BUG: state file 'next' does not exist"); 419 state->cur =strtol(sb.buf, NULL,10); 420 421if(read_state_file(&sb, state,"last",1) <0) 422die("BUG: state file 'last' does not exist"); 423 state->last =strtol(sb.buf, NULL,10); 424 425if(read_author_script(state) <0) 426die(_("could not parse author script")); 427 428read_commit_msg(state); 429 430if(read_state_file(&sb, state,"original-commit",1) <0) 431hashclr(state->orig_commit); 432else if(get_sha1_hex(sb.buf, state->orig_commit) <0) 433die(_("could not parse%s"),am_path(state,"original-commit")); 434 435read_state_file(&sb, state,"threeway",1); 436 state->threeway = !strcmp(sb.buf,"t"); 437 438read_state_file(&sb, state,"quiet",1); 439 state->quiet = !strcmp(sb.buf,"t"); 440 441read_state_file(&sb, state,"sign",1); 442 state->signoff = !strcmp(sb.buf,"t"); 443 444read_state_file(&sb, state,"utf8",1); 445 state->utf8 = !strcmp(sb.buf,"t"); 446 447read_state_file(&sb, state,"keep",1); 448if(!strcmp(sb.buf,"t")) 449 state->keep = KEEP_TRUE; 450else if(!strcmp(sb.buf,"b")) 451 state->keep = KEEP_NON_PATCH; 452else 453 state->keep = KEEP_FALSE; 454 455read_state_file(&sb, state,"messageid",1); 456 state->message_id = !strcmp(sb.buf,"t"); 457 458read_state_file(&sb, state,"scissors",1); 459if(!strcmp(sb.buf,"t")) 460 state->scissors = SCISSORS_TRUE; 461else if(!strcmp(sb.buf,"f")) 462 state->scissors = SCISSORS_FALSE; 463else 464 state->scissors = SCISSORS_UNSET; 465 466read_state_file(&sb, state,"apply-opt",1); 467argv_array_clear(&state->git_apply_opts); 468if(sq_dequote_to_argv_array(sb.buf, &state->git_apply_opts) <0) 469die(_("could not parse%s"),am_path(state,"apply-opt")); 470 471 state->rebasing = !!file_exists(am_path(state,"rebasing")); 472 473strbuf_release(&sb); 474} 475 476/** 477 * Removes the am_state directory, forcefully terminating the current am 478 * session. 479 */ 480static voidam_destroy(const struct am_state *state) 481{ 482struct strbuf sb = STRBUF_INIT; 483 484strbuf_addstr(&sb, state->dir); 485remove_dir_recursively(&sb,0); 486strbuf_release(&sb); 487} 488 489/** 490 * Runs applypatch-msg hook. Returns its exit code. 491 */ 492static intrun_applypatch_msg_hook(struct am_state *state) 493{ 494int ret; 495 496assert(state->msg); 497 ret =run_hook_le(NULL,"applypatch-msg",am_path(state,"final-commit"), NULL); 498 499if(!ret) { 500free(state->msg); 501 state->msg = NULL; 502if(read_commit_msg(state) <0) 503die(_("'%s' was deleted by the applypatch-msg hook"), 504am_path(state,"final-commit")); 505} 506 507return ret; 508} 509 510/** 511 * Runs post-rewrite hook. Returns it exit code. 512 */ 513static intrun_post_rewrite_hook(const struct am_state *state) 514{ 515struct child_process cp = CHILD_PROCESS_INIT; 516const char*hook =find_hook("post-rewrite"); 517int ret; 518 519if(!hook) 520return0; 521 522argv_array_push(&cp.args, hook); 523argv_array_push(&cp.args,"rebase"); 524 525 cp.in =xopen(am_path(state,"rewritten"), O_RDONLY); 526 cp.stdout_to_stderr =1; 527 528 ret =run_command(&cp); 529 530close(cp.in); 531return ret; 532} 533 534/** 535 * Reads the state directory's "rewritten" file, and copies notes from the old 536 * commits listed in the file to their rewritten commits. 537 * 538 * Returns 0 on success, -1 on failure. 539 */ 540static intcopy_notes_for_rebase(const struct am_state *state) 541{ 542struct notes_rewrite_cfg *c; 543struct strbuf sb = STRBUF_INIT; 544const char*invalid_line =_("Malformed input line: '%s'."); 545const char*msg ="Notes added by 'git rebase'"; 546FILE*fp; 547int ret =0; 548 549assert(state->rebasing); 550 551 c =init_copy_notes_for_rewrite("rebase"); 552if(!c) 553return0; 554 555 fp =xfopen(am_path(state,"rewritten"),"r"); 556 557while(!strbuf_getline_lf(&sb, fp)) { 558unsigned char from_obj[GIT_SHA1_RAWSZ], to_obj[GIT_SHA1_RAWSZ]; 559 560if(sb.len != GIT_SHA1_HEXSZ *2+1) { 561 ret =error(invalid_line, sb.buf); 562goto finish; 563} 564 565if(get_sha1_hex(sb.buf, from_obj)) { 566 ret =error(invalid_line, sb.buf); 567goto finish; 568} 569 570if(sb.buf[GIT_SHA1_HEXSZ] !=' ') { 571 ret =error(invalid_line, sb.buf); 572goto finish; 573} 574 575if(get_sha1_hex(sb.buf + GIT_SHA1_HEXSZ +1, to_obj)) { 576 ret =error(invalid_line, sb.buf); 577goto finish; 578} 579 580if(copy_note_for_rewrite(c, from_obj, to_obj)) 581 ret =error(_("Failed to copy notes from '%s' to '%s'"), 582sha1_to_hex(from_obj),sha1_to_hex(to_obj)); 583} 584 585finish: 586finish_copy_notes_for_rewrite(c, msg); 587fclose(fp); 588strbuf_release(&sb); 589return ret; 590} 591 592/** 593 * Determines if the file looks like a piece of RFC2822 mail by grabbing all 594 * non-indented lines and checking if they look like they begin with valid 595 * header field names. 596 * 597 * Returns 1 if the file looks like a piece of mail, 0 otherwise. 598 */ 599static intis_mail(FILE*fp) 600{ 601const char*header_regex ="^[!-9;-~]+:"; 602struct strbuf sb = STRBUF_INIT; 603 regex_t regex; 604int ret =1; 605 606if(fseek(fp,0L, SEEK_SET)) 607die_errno(_("fseek failed")); 608 609if(regcomp(®ex, header_regex, REG_NOSUB | REG_EXTENDED)) 610die("invalid pattern:%s", header_regex); 611 612while(!strbuf_getline(&sb, fp)) { 613if(!sb.len) 614break;/* End of header */ 615 616/* Ignore indented folded lines */ 617if(*sb.buf =='\t'|| *sb.buf ==' ') 618continue; 619 620/* It's a header if it matches header_regex */ 621if(regexec(®ex, sb.buf,0, NULL,0)) { 622 ret =0; 623goto done; 624} 625} 626 627done: 628regfree(®ex); 629strbuf_release(&sb); 630return ret; 631} 632 633/** 634 * Attempts to detect the patch_format of the patches contained in `paths`, 635 * returning the PATCH_FORMAT_* enum value. Returns PATCH_FORMAT_UNKNOWN if 636 * detection fails. 637 */ 638static intdetect_patch_format(const char**paths) 639{ 640enum patch_format ret = PATCH_FORMAT_UNKNOWN; 641struct strbuf l1 = STRBUF_INIT; 642struct strbuf l2 = STRBUF_INIT; 643struct strbuf l3 = STRBUF_INIT; 644FILE*fp; 645 646/* 647 * We default to mbox format if input is from stdin and for directories 648 */ 649if(!*paths || !strcmp(*paths,"-") ||is_directory(*paths)) 650return PATCH_FORMAT_MBOX; 651 652/* 653 * Otherwise, check the first few lines of the first patch, starting 654 * from the first non-blank line, to try to detect its format. 655 */ 656 657 fp =xfopen(*paths,"r"); 658 659while(!strbuf_getline(&l1, fp)) { 660if(l1.len) 661break; 662} 663 664if(starts_with(l1.buf,"From ") ||starts_with(l1.buf,"From: ")) { 665 ret = PATCH_FORMAT_MBOX; 666goto done; 667} 668 669if(starts_with(l1.buf,"# This series applies on GIT commit")) { 670 ret = PATCH_FORMAT_STGIT_SERIES; 671goto done; 672} 673 674if(!strcmp(l1.buf,"# HG changeset patch")) { 675 ret = PATCH_FORMAT_HG; 676goto done; 677} 678 679strbuf_reset(&l2); 680strbuf_getline(&l2, fp); 681strbuf_reset(&l3); 682strbuf_getline(&l3, fp); 683 684/* 685 * If the second line is empty and the third is a From, Author or Date 686 * entry, this is likely an StGit patch. 687 */ 688if(l1.len && !l2.len && 689(starts_with(l3.buf,"From:") || 690starts_with(l3.buf,"Author:") || 691starts_with(l3.buf,"Date:"))) { 692 ret = PATCH_FORMAT_STGIT; 693goto done; 694} 695 696if(l1.len &&is_mail(fp)) { 697 ret = PATCH_FORMAT_MBOX; 698goto done; 699} 700 701done: 702fclose(fp); 703strbuf_release(&l1); 704return ret; 705} 706 707/** 708 * Splits out individual email patches from `paths`, where each path is either 709 * a mbox file or a Maildir. Returns 0 on success, -1 on failure. 710 */ 711static intsplit_mail_mbox(struct am_state *state,const char**paths, 712int keep_cr,int mboxrd) 713{ 714struct child_process cp = CHILD_PROCESS_INIT; 715struct strbuf last = STRBUF_INIT; 716 717 cp.git_cmd =1; 718argv_array_push(&cp.args,"mailsplit"); 719argv_array_pushf(&cp.args,"-d%d", state->prec); 720argv_array_pushf(&cp.args,"-o%s", state->dir); 721argv_array_push(&cp.args,"-b"); 722if(keep_cr) 723argv_array_push(&cp.args,"--keep-cr"); 724if(mboxrd) 725argv_array_push(&cp.args,"--mboxrd"); 726argv_array_push(&cp.args,"--"); 727argv_array_pushv(&cp.args, paths); 728 729if(capture_command(&cp, &last,8)) 730return-1; 731 732 state->cur =1; 733 state->last =strtol(last.buf, NULL,10); 734 735return0; 736} 737 738/** 739 * Callback signature for split_mail_conv(). The foreign patch should be 740 * read from `in`, and the converted patch (in RFC2822 mail format) should be 741 * written to `out`. Return 0 on success, or -1 on failure. 742 */ 743typedefint(*mail_conv_fn)(FILE*out,FILE*in,int keep_cr); 744 745/** 746 * Calls `fn` for each file in `paths` to convert the foreign patch to the 747 * RFC2822 mail format suitable for parsing with git-mailinfo. 748 * 749 * Returns 0 on success, -1 on failure. 750 */ 751static intsplit_mail_conv(mail_conv_fn fn,struct am_state *state, 752const char**paths,int keep_cr) 753{ 754static const char*stdin_only[] = {"-", NULL}; 755int i; 756 757if(!*paths) 758 paths = stdin_only; 759 760for(i =0; *paths; paths++, i++) { 761FILE*in, *out; 762const char*mail; 763int ret; 764 765if(!strcmp(*paths,"-")) 766 in = stdin; 767else 768 in =fopen(*paths,"r"); 769 770if(!in) 771returnerror_errno(_("could not open '%s' for reading"), 772*paths); 773 774 mail =mkpath("%s/%0*d", state->dir, state->prec, i +1); 775 776 out =fopen(mail,"w"); 777if(!out) 778returnerror_errno(_("could not open '%s' for writing"), 779 mail); 780 781 ret =fn(out, in, keep_cr); 782 783fclose(out); 784fclose(in); 785 786if(ret) 787returnerror(_("could not parse patch '%s'"), *paths); 788} 789 790 state->cur =1; 791 state->last = i; 792return0; 793} 794 795/** 796 * A split_mail_conv() callback that converts an StGit patch to an RFC2822 797 * message suitable for parsing with git-mailinfo. 798 */ 799static intstgit_patch_to_mail(FILE*out,FILE*in,int keep_cr) 800{ 801struct strbuf sb = STRBUF_INIT; 802int subject_printed =0; 803 804while(!strbuf_getline_lf(&sb, in)) { 805const char*str; 806 807if(str_isspace(sb.buf)) 808continue; 809else if(skip_prefix(sb.buf,"Author:", &str)) 810fprintf(out,"From:%s\n", str); 811else if(starts_with(sb.buf,"From") ||starts_with(sb.buf,"Date")) 812fprintf(out,"%s\n", sb.buf); 813else if(!subject_printed) { 814fprintf(out,"Subject:%s\n", sb.buf); 815 subject_printed =1; 816}else{ 817fprintf(out,"\n%s\n", sb.buf); 818break; 819} 820} 821 822strbuf_reset(&sb); 823while(strbuf_fread(&sb,8192, in) >0) { 824fwrite(sb.buf,1, sb.len, out); 825strbuf_reset(&sb); 826} 827 828strbuf_release(&sb); 829return0; 830} 831 832/** 833 * This function only supports a single StGit series file in `paths`. 834 * 835 * Given an StGit series file, converts the StGit patches in the series into 836 * RFC2822 messages suitable for parsing with git-mailinfo, and queues them in 837 * the state directory. 838 * 839 * Returns 0 on success, -1 on failure. 840 */ 841static intsplit_mail_stgit_series(struct am_state *state,const char**paths, 842int keep_cr) 843{ 844const char*series_dir; 845char*series_dir_buf; 846FILE*fp; 847struct argv_array patches = ARGV_ARRAY_INIT; 848struct strbuf sb = STRBUF_INIT; 849int ret; 850 851if(!paths[0] || paths[1]) 852returnerror(_("Only one StGIT patch series can be applied at once")); 853 854 series_dir_buf =xstrdup(*paths); 855 series_dir =dirname(series_dir_buf); 856 857 fp =fopen(*paths,"r"); 858if(!fp) 859returnerror_errno(_("could not open '%s' for reading"), *paths); 860 861while(!strbuf_getline_lf(&sb, fp)) { 862if(*sb.buf =='#') 863continue;/* skip comment lines */ 864 865argv_array_push(&patches,mkpath("%s/%s", series_dir, sb.buf)); 866} 867 868fclose(fp); 869strbuf_release(&sb); 870free(series_dir_buf); 871 872 ret =split_mail_conv(stgit_patch_to_mail, state, patches.argv, keep_cr); 873 874argv_array_clear(&patches); 875return ret; 876} 877 878/** 879 * A split_patches_conv() callback that converts a mercurial patch to a RFC2822 880 * message suitable for parsing with git-mailinfo. 881 */ 882static inthg_patch_to_mail(FILE*out,FILE*in,int keep_cr) 883{ 884struct strbuf sb = STRBUF_INIT; 885 886while(!strbuf_getline_lf(&sb, in)) { 887const char*str; 888 889if(skip_prefix(sb.buf,"# User ", &str)) 890fprintf(out,"From:%s\n", str); 891else if(skip_prefix(sb.buf,"# Date ", &str)) { 892unsigned long timestamp; 893long tz, tz2; 894char*end; 895 896 errno =0; 897 timestamp =strtoul(str, &end,10); 898if(errno) 899returnerror(_("invalid timestamp")); 900 901if(!skip_prefix(end," ", &str)) 902returnerror(_("invalid Date line")); 903 904 errno =0; 905 tz =strtol(str, &end,10); 906if(errno) 907returnerror(_("invalid timezone offset")); 908 909if(*end) 910returnerror(_("invalid Date line")); 911 912/* 913 * mercurial's timezone is in seconds west of UTC, 914 * however git's timezone is in hours + minutes east of 915 * UTC. Convert it. 916 */ 917 tz2 =labs(tz) /3600*100+labs(tz) %3600/60; 918if(tz >0) 919 tz2 = -tz2; 920 921fprintf(out,"Date:%s\n",show_date(timestamp, tz2,DATE_MODE(RFC2822))); 922}else if(starts_with(sb.buf,"# ")) { 923continue; 924}else{ 925fprintf(out,"\n%s\n", sb.buf); 926break; 927} 928} 929 930strbuf_reset(&sb); 931while(strbuf_fread(&sb,8192, in) >0) { 932fwrite(sb.buf,1, sb.len, out); 933strbuf_reset(&sb); 934} 935 936strbuf_release(&sb); 937return0; 938} 939 940/** 941 * Splits a list of files/directories into individual email patches. Each path 942 * in `paths` must be a file/directory that is formatted according to 943 * `patch_format`. 944 * 945 * Once split out, the individual email patches will be stored in the state 946 * directory, with each patch's filename being its index, padded to state->prec 947 * digits. 948 * 949 * state->cur will be set to the index of the first mail, and state->last will 950 * be set to the index of the last mail. 951 * 952 * Set keep_cr to 0 to convert all lines ending with \r\n to end with \n, 1 953 * to disable this behavior, -1 to use the default configured setting. 954 * 955 * Returns 0 on success, -1 on failure. 956 */ 957static intsplit_mail(struct am_state *state,enum patch_format patch_format, 958const char**paths,int keep_cr) 959{ 960if(keep_cr <0) { 961 keep_cr =0; 962git_config_get_bool("am.keepcr", &keep_cr); 963} 964 965switch(patch_format) { 966case PATCH_FORMAT_MBOX: 967returnsplit_mail_mbox(state, paths, keep_cr,0); 968case PATCH_FORMAT_STGIT: 969returnsplit_mail_conv(stgit_patch_to_mail, state, paths, keep_cr); 970case PATCH_FORMAT_STGIT_SERIES: 971returnsplit_mail_stgit_series(state, paths, keep_cr); 972case PATCH_FORMAT_HG: 973returnsplit_mail_conv(hg_patch_to_mail, state, paths, keep_cr); 974case PATCH_FORMAT_MBOXRD: 975returnsplit_mail_mbox(state, paths, keep_cr,1); 976default: 977die("BUG: invalid patch_format"); 978} 979return-1; 980} 981 982/** 983 * Setup a new am session for applying patches 984 */ 985static voidam_setup(struct am_state *state,enum patch_format patch_format, 986const char**paths,int keep_cr) 987{ 988unsigned char curr_head[GIT_SHA1_RAWSZ]; 989const char*str; 990struct strbuf sb = STRBUF_INIT; 991 992if(!patch_format) 993 patch_format =detect_patch_format(paths); 994 995if(!patch_format) { 996fprintf_ln(stderr,_("Patch format detection failed.")); 997exit(128); 998} 9991000if(mkdir(state->dir,0777) <0&& errno != EEXIST)1001die_errno(_("failed to create directory '%s'"), state->dir);10021003if(split_mail(state, patch_format, paths, keep_cr) <0) {1004am_destroy(state);1005die(_("Failed to split patches."));1006}10071008if(state->rebasing)1009 state->threeway =1;10101011write_state_bool(state,"threeway", state->threeway);1012write_state_bool(state,"quiet", state->quiet);1013write_state_bool(state,"sign", state->signoff);1014write_state_bool(state,"utf8", state->utf8);10151016switch(state->keep) {1017case KEEP_FALSE:1018 str ="f";1019break;1020case KEEP_TRUE:1021 str ="t";1022break;1023case KEEP_NON_PATCH:1024 str ="b";1025break;1026default:1027die("BUG: invalid value for state->keep");1028}10291030write_state_text(state,"keep", str);1031write_state_bool(state,"messageid", state->message_id);10321033switch(state->scissors) {1034case SCISSORS_UNSET:1035 str ="";1036break;1037case SCISSORS_FALSE:1038 str ="f";1039break;1040case SCISSORS_TRUE:1041 str ="t";1042break;1043default:1044die("BUG: invalid value for state->scissors");1045}1046write_state_text(state,"scissors", str);10471048sq_quote_argv(&sb, state->git_apply_opts.argv,0);1049write_state_text(state,"apply-opt", sb.buf);10501051if(state->rebasing)1052write_state_text(state,"rebasing","");1053else1054write_state_text(state,"applying","");10551056if(!get_sha1("HEAD", curr_head)) {1057write_state_text(state,"abort-safety",sha1_to_hex(curr_head));1058if(!state->rebasing)1059update_ref("am","ORIG_HEAD", curr_head, NULL,0,1060 UPDATE_REFS_DIE_ON_ERR);1061}else{1062write_state_text(state,"abort-safety","");1063if(!state->rebasing)1064delete_ref("ORIG_HEAD", NULL,0);1065}10661067/*1068 * NOTE: Since the "next" and "last" files determine if an am_state1069 * session is in progress, they should be written last.1070 */10711072write_state_count(state,"next", state->cur);1073write_state_count(state,"last", state->last);10741075strbuf_release(&sb);1076}10771078/**1079 * Increments the patch pointer, and cleans am_state for the application of the1080 * next patch.1081 */1082static voidam_next(struct am_state *state)1083{1084unsigned char head[GIT_SHA1_RAWSZ];10851086free(state->author_name);1087 state->author_name = NULL;10881089free(state->author_email);1090 state->author_email = NULL;10911092free(state->author_date);1093 state->author_date = NULL;10941095free(state->msg);1096 state->msg = NULL;1097 state->msg_len =0;10981099unlink(am_path(state,"author-script"));1100unlink(am_path(state,"final-commit"));11011102hashclr(state->orig_commit);1103unlink(am_path(state,"original-commit"));11041105if(!get_sha1("HEAD", head))1106write_state_text(state,"abort-safety",sha1_to_hex(head));1107else1108write_state_text(state,"abort-safety","");11091110 state->cur++;1111write_state_count(state,"next", state->cur);1112}11131114/**1115 * Returns the filename of the current patch email.1116 */1117static const char*msgnum(const struct am_state *state)1118{1119static struct strbuf sb = STRBUF_INIT;11201121strbuf_reset(&sb);1122strbuf_addf(&sb,"%0*d", state->prec, state->cur);11231124return sb.buf;1125}11261127/**1128 * Refresh and write index.1129 */1130static voidrefresh_and_write_cache(void)1131{1132struct lock_file *lock_file =xcalloc(1,sizeof(struct lock_file));11331134hold_locked_index(lock_file,1);1135refresh_cache(REFRESH_QUIET);1136if(write_locked_index(&the_index, lock_file, COMMIT_LOCK))1137die(_("unable to write index file"));1138}11391140/**1141 * Returns 1 if the index differs from HEAD, 0 otherwise. When on an unborn1142 * branch, returns 1 if there are entries in the index, 0 otherwise. If an1143 * strbuf is provided, the space-separated list of files that differ will be1144 * appended to it.1145 */1146static intindex_has_changes(struct strbuf *sb)1147{1148unsigned char head[GIT_SHA1_RAWSZ];1149int i;11501151if(!get_sha1_tree("HEAD", head)) {1152struct diff_options opt;11531154diff_setup(&opt);1155DIFF_OPT_SET(&opt, EXIT_WITH_STATUS);1156if(!sb)1157DIFF_OPT_SET(&opt, QUICK);1158do_diff_cache(head, &opt);1159diffcore_std(&opt);1160for(i =0; sb && i < diff_queued_diff.nr; i++) {1161if(i)1162strbuf_addch(sb,' ');1163strbuf_addstr(sb, diff_queued_diff.queue[i]->two->path);1164}1165diff_flush(&opt);1166returnDIFF_OPT_TST(&opt, HAS_CHANGES) !=0;1167}else{1168for(i =0; sb && i < active_nr; i++) {1169if(i)1170strbuf_addch(sb,' ');1171strbuf_addstr(sb, active_cache[i]->name);1172}1173return!!active_nr;1174}1175}11761177/**1178 * Dies with a user-friendly message on how to proceed after resolving the1179 * problem. This message can be overridden with state->resolvemsg.1180 */1181static void NORETURN die_user_resolve(const struct am_state *state)1182{1183if(state->resolvemsg) {1184printf_ln("%s", state->resolvemsg);1185}else{1186const char*cmdline = state->interactive ?"git am -i":"git am";11871188printf_ln(_("When you have resolved this problem, run\"%s--continue\"."), cmdline);1189printf_ln(_("If you prefer to skip this patch, run\"%s--skip\"instead."), cmdline);1190printf_ln(_("To restore the original branch and stop patching, run\"%s--abort\"."), cmdline);1191}11921193exit(128);1194}11951196static voidam_signoff(struct strbuf *sb)1197{1198char*cp;1199struct strbuf mine = STRBUF_INIT;12001201/* Does it end with our own sign-off? */1202strbuf_addf(&mine,"\n%s%s\n",1203 sign_off_header,1204fmt_name(getenv("GIT_COMMITTER_NAME"),1205getenv("GIT_COMMITTER_EMAIL")));1206if(mine.len < sb->len &&1207!strcmp(mine.buf, sb->buf + sb->len - mine.len))1208goto exit;/* no need to duplicate */12091210/* Does it have any Signed-off-by: in the text */1211for(cp = sb->buf;1212 cp && *cp && (cp =strstr(cp, sign_off_header)) != NULL;1213 cp =strchr(cp,'\n')) {1214if(sb->buf == cp || cp[-1] =='\n')1215break;1216}12171218strbuf_addstr(sb, mine.buf + !!cp);1219exit:1220strbuf_release(&mine);1221}12221223/**1224 * Appends signoff to the "msg" field of the am_state.1225 */1226static voidam_append_signoff(struct am_state *state)1227{1228struct strbuf sb = STRBUF_INIT;12291230strbuf_attach(&sb, state->msg, state->msg_len, state->msg_len);1231am_signoff(&sb);1232 state->msg =strbuf_detach(&sb, &state->msg_len);1233}12341235/**1236 * Parses `mail` using git-mailinfo, extracting its patch and authorship info.1237 * state->msg will be set to the patch message. state->author_name,1238 * state->author_email and state->author_date will be set to the patch author's1239 * name, email and date respectively. The patch body will be written to the1240 * state directory's "patch" file.1241 *1242 * Returns 1 if the patch should be skipped, 0 otherwise.1243 */1244static intparse_mail(struct am_state *state,const char*mail)1245{1246FILE*fp;1247struct strbuf sb = STRBUF_INIT;1248struct strbuf msg = STRBUF_INIT;1249struct strbuf author_name = STRBUF_INIT;1250struct strbuf author_date = STRBUF_INIT;1251struct strbuf author_email = STRBUF_INIT;1252int ret =0;1253struct mailinfo mi;12541255setup_mailinfo(&mi);12561257if(state->utf8)1258 mi.metainfo_charset =get_commit_output_encoding();1259else1260 mi.metainfo_charset = NULL;12611262switch(state->keep) {1263case KEEP_FALSE:1264break;1265case KEEP_TRUE:1266 mi.keep_subject =1;1267break;1268case KEEP_NON_PATCH:1269 mi.keep_non_patch_brackets_in_subject =1;1270break;1271default:1272die("BUG: invalid value for state->keep");1273}12741275if(state->message_id)1276 mi.add_message_id =1;12771278switch(state->scissors) {1279case SCISSORS_UNSET:1280break;1281case SCISSORS_FALSE:1282 mi.use_scissors =0;1283break;1284case SCISSORS_TRUE:1285 mi.use_scissors =1;1286break;1287default:1288die("BUG: invalid value for state->scissors");1289}12901291 mi.input =fopen(mail,"r");1292if(!mi.input)1293die("could not open input");1294 mi.output =fopen(am_path(state,"info"),"w");1295if(!mi.output)1296die("could not open output 'info'");1297if(mailinfo(&mi,am_path(state,"msg"),am_path(state,"patch")))1298die("could not parse patch");12991300fclose(mi.input);1301fclose(mi.output);13021303/* Extract message and author information */1304 fp =xfopen(am_path(state,"info"),"r");1305while(!strbuf_getline_lf(&sb, fp)) {1306const char*x;13071308if(skip_prefix(sb.buf,"Subject: ", &x)) {1309if(msg.len)1310strbuf_addch(&msg,'\n');1311strbuf_addstr(&msg, x);1312}else if(skip_prefix(sb.buf,"Author: ", &x))1313strbuf_addstr(&author_name, x);1314else if(skip_prefix(sb.buf,"Email: ", &x))1315strbuf_addstr(&author_email, x);1316else if(skip_prefix(sb.buf,"Date: ", &x))1317strbuf_addstr(&author_date, x);1318}1319fclose(fp);13201321/* Skip pine's internal folder data */1322if(!strcmp(author_name.buf,"Mail System Internal Data")) {1323 ret =1;1324goto finish;1325}13261327if(is_empty_file(am_path(state,"patch"))) {1328printf_ln(_("Patch is empty. Was it split wrong?"));1329die_user_resolve(state);1330}13311332strbuf_addstr(&msg,"\n\n");1333strbuf_addbuf(&msg, &mi.log_message);1334strbuf_stripspace(&msg,0);13351336if(state->signoff)1337am_signoff(&msg);13381339assert(!state->author_name);1340 state->author_name =strbuf_detach(&author_name, NULL);13411342assert(!state->author_email);1343 state->author_email =strbuf_detach(&author_email, NULL);13441345assert(!state->author_date);1346 state->author_date =strbuf_detach(&author_date, NULL);13471348assert(!state->msg);1349 state->msg =strbuf_detach(&msg, &state->msg_len);13501351finish:1352strbuf_release(&msg);1353strbuf_release(&author_date);1354strbuf_release(&author_email);1355strbuf_release(&author_name);1356strbuf_release(&sb);1357clear_mailinfo(&mi);1358return ret;1359}13601361/**1362 * Sets commit_id to the commit hash where the mail was generated from.1363 * Returns 0 on success, -1 on failure.1364 */1365static intget_mail_commit_sha1(unsigned char*commit_id,const char*mail)1366{1367struct strbuf sb = STRBUF_INIT;1368FILE*fp =xfopen(mail,"r");1369const char*x;13701371if(strbuf_getline_lf(&sb, fp))1372return-1;13731374if(!skip_prefix(sb.buf,"From ", &x))1375return-1;13761377if(get_sha1_hex(x, commit_id) <0)1378return-1;13791380strbuf_release(&sb);1381fclose(fp);1382return0;1383}13841385/**1386 * Sets state->msg, state->author_name, state->author_email, state->author_date1387 * to the commit's respective info.1388 */1389static voidget_commit_info(struct am_state *state,struct commit *commit)1390{1391const char*buffer, *ident_line, *author_date, *msg;1392size_t ident_len;1393struct ident_split ident_split;1394struct strbuf sb = STRBUF_INIT;13951396 buffer =logmsg_reencode(commit, NULL,get_commit_output_encoding());13971398 ident_line =find_commit_header(buffer,"author", &ident_len);13991400if(split_ident_line(&ident_split, ident_line, ident_len) <0) {1401strbuf_add(&sb, ident_line, ident_len);1402die(_("invalid ident line:%s"), sb.buf);1403}14041405assert(!state->author_name);1406if(ident_split.name_begin) {1407strbuf_add(&sb, ident_split.name_begin,1408 ident_split.name_end - ident_split.name_begin);1409 state->author_name =strbuf_detach(&sb, NULL);1410}else1411 state->author_name =xstrdup("");14121413assert(!state->author_email);1414if(ident_split.mail_begin) {1415strbuf_add(&sb, ident_split.mail_begin,1416 ident_split.mail_end - ident_split.mail_begin);1417 state->author_email =strbuf_detach(&sb, NULL);1418}else1419 state->author_email =xstrdup("");14201421 author_date =show_ident_date(&ident_split,DATE_MODE(NORMAL));1422strbuf_addstr(&sb, author_date);1423assert(!state->author_date);1424 state->author_date =strbuf_detach(&sb, NULL);14251426assert(!state->msg);1427 msg =strstr(buffer,"\n\n");1428if(!msg)1429die(_("unable to parse commit%s"),oid_to_hex(&commit->object.oid));1430 state->msg =xstrdup(msg +2);1431 state->msg_len =strlen(state->msg);1432}14331434/**1435 * Writes `commit` as a patch to the state directory's "patch" file.1436 */1437static voidwrite_commit_patch(const struct am_state *state,struct commit *commit)1438{1439struct rev_info rev_info;1440FILE*fp;14411442 fp =xfopen(am_path(state,"patch"),"w");1443init_revisions(&rev_info, NULL);1444 rev_info.diff =1;1445 rev_info.abbrev =0;1446 rev_info.disable_stdin =1;1447 rev_info.show_root_diff =1;1448 rev_info.diffopt.output_format = DIFF_FORMAT_PATCH;1449 rev_info.no_commit_id =1;1450DIFF_OPT_SET(&rev_info.diffopt, BINARY);1451DIFF_OPT_SET(&rev_info.diffopt, FULL_INDEX);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, &commit->object,"");1456diff_setup_done(&rev_info.diffopt);1457log_tree_commit(&rev_info, commit);1458}14591460/**1461 * Writes the diff of the index against HEAD as a patch to the state1462 * directory's "patch" file.1463 */1464static voidwrite_index_patch(const struct am_state *state)1465{1466struct tree *tree;1467unsigned char head[GIT_SHA1_RAWSZ];1468struct rev_info rev_info;1469FILE*fp;14701471if(!get_sha1_tree("HEAD", head))1472 tree =lookup_tree(head);1473else1474 tree =lookup_tree(EMPTY_TREE_SHA1_BIN);14751476 fp =xfopen(am_path(state,"patch"),"w");1477init_revisions(&rev_info, NULL);1478 rev_info.diff =1;1479 rev_info.disable_stdin =1;1480 rev_info.no_commit_id =1;1481 rev_info.diffopt.output_format = DIFF_FORMAT_PATCH;1482 rev_info.diffopt.use_color =0;1483 rev_info.diffopt.file = fp;1484 rev_info.diffopt.close_file =1;1485add_pending_object(&rev_info, &tree->object,"");1486diff_setup_done(&rev_info.diffopt);1487run_diff_index(&rev_info,1);1488}14891490/**1491 * Like parse_mail(), but parses the mail by looking up its commit ID1492 * directly. This is used in --rebasing mode to bypass git-mailinfo's munging1493 * of patches.1494 *1495 * state->orig_commit will be set to the original commit ID.1496 *1497 * Will always return 0 as the patch should never be skipped.1498 */1499static intparse_mail_rebase(struct am_state *state,const char*mail)1500{1501struct commit *commit;1502unsigned char commit_sha1[GIT_SHA1_RAWSZ];15031504if(get_mail_commit_sha1(commit_sha1, mail) <0)1505die(_("could not parse%s"), mail);15061507 commit =lookup_commit_or_die(commit_sha1, mail);15081509get_commit_info(state, commit);15101511write_commit_patch(state, commit);15121513hashcpy(state->orig_commit, commit_sha1);1514write_state_text(state,"original-commit",sha1_to_hex(commit_sha1));15151516return0;1517}15181519/**1520 * Applies current patch with git-apply. Returns 0 on success, -1 otherwise. If1521 * `index_file` is not NULL, the patch will be applied to that index.1522 */1523static intrun_apply(const struct am_state *state,const char*index_file)1524{1525struct child_process cp = CHILD_PROCESS_INIT;15261527 cp.git_cmd =1;15281529if(index_file)1530argv_array_pushf(&cp.env_array,"GIT_INDEX_FILE=%s", index_file);15311532/*1533 * If we are allowed to fall back on 3-way merge, don't give false1534 * errors during the initial attempt.1535 */1536if(state->threeway && !index_file) {1537 cp.no_stdout =1;1538 cp.no_stderr =1;1539}15401541argv_array_push(&cp.args,"apply");15421543argv_array_pushv(&cp.args, state->git_apply_opts.argv);15441545if(index_file)1546argv_array_push(&cp.args,"--cached");1547else1548argv_array_push(&cp.args,"--index");15491550argv_array_push(&cp.args,am_path(state,"patch"));15511552if(run_command(&cp))1553return-1;15541555/* Reload index as git-apply will have modified it. */1556discard_cache();1557read_cache_from(index_file ? index_file :get_index_file());15581559return0;1560}15611562/**1563 * Builds an index that contains just the blobs needed for a 3way merge.1564 */1565static intbuild_fake_ancestor(const struct am_state *state,const char*index_file)1566{1567struct child_process cp = CHILD_PROCESS_INIT;15681569 cp.git_cmd =1;1570argv_array_push(&cp.args,"apply");1571argv_array_pushv(&cp.args, state->git_apply_opts.argv);1572argv_array_pushf(&cp.args,"--build-fake-ancestor=%s", index_file);1573argv_array_push(&cp.args,am_path(state,"patch"));15741575if(run_command(&cp))1576return-1;15771578return0;1579}15801581/**1582 * Attempt a threeway merge, using index_path as the temporary index.1583 */1584static intfall_back_threeway(const struct am_state *state,const char*index_path)1585{1586struct object_id orig_tree, their_tree, our_tree;1587const struct object_id *bases[1] = { &orig_tree };1588struct merge_options o;1589struct commit *result;1590char*their_tree_name;15911592if(get_oid("HEAD", &our_tree) <0)1593hashcpy(our_tree.hash, EMPTY_TREE_SHA1_BIN);15941595if(build_fake_ancestor(state, index_path))1596returnerror("could not build fake ancestor");15971598discard_cache();1599read_cache_from(index_path);16001601if(write_index_as_tree(orig_tree.hash, &the_index, index_path,0, NULL))1602returnerror(_("Repository lacks necessary blobs to fall back on 3-way merge."));16031604say(state, stdout,_("Using index info to reconstruct a base tree..."));16051606if(!state->quiet) {1607/*1608 * List paths that needed 3-way fallback, so that the user can1609 * review them with extra care to spot mismerges.1610 */1611struct rev_info rev_info;1612const char*diff_filter_str ="--diff-filter=AM";16131614init_revisions(&rev_info, NULL);1615 rev_info.diffopt.output_format = DIFF_FORMAT_NAME_STATUS;1616diff_opt_parse(&rev_info.diffopt, &diff_filter_str,1, rev_info.prefix);1617add_pending_sha1(&rev_info,"HEAD", our_tree.hash,0);1618diff_setup_done(&rev_info.diffopt);1619run_diff_index(&rev_info,1);1620}16211622if(run_apply(state, index_path))1623returnerror(_("Did you hand edit your patch?\n"1624"It does not apply to blobs recorded in its index."));16251626if(write_index_as_tree(their_tree.hash, &the_index, index_path,0, NULL))1627returnerror("could not write tree");16281629say(state, stdout,_("Falling back to patching base and 3-way merge..."));16301631discard_cache();1632read_cache();16331634/*1635 * This is not so wrong. Depending on which base we picked, orig_tree1636 * may be wildly different from ours, but their_tree has the same set of1637 * wildly different changes in parts the patch did not touch, so1638 * recursive ends up canceling them, saying that we reverted all those1639 * changes.1640 */16411642init_merge_options(&o);16431644 o.branch1 ="HEAD";1645 their_tree_name =xstrfmt("%.*s",linelen(state->msg), state->msg);1646 o.branch2 = their_tree_name;16471648if(state->quiet)1649 o.verbosity =0;16501651if(merge_recursive_generic(&o, &our_tree, &their_tree,1, bases, &result)) {1652rerere(state->allow_rerere_autoupdate);1653free(their_tree_name);1654returnerror(_("Failed to merge in the changes."));1655}16561657free(their_tree_name);1658return0;1659}16601661/**1662 * Commits the current index with state->msg as the commit message and1663 * state->author_name, state->author_email and state->author_date as the author1664 * information.1665 */1666static voiddo_commit(const struct am_state *state)1667{1668unsigned char tree[GIT_SHA1_RAWSZ], parent[GIT_SHA1_RAWSZ],1669 commit[GIT_SHA1_RAWSZ];1670unsigned char*ptr;1671struct commit_list *parents = NULL;1672const char*reflog_msg, *author;1673struct strbuf sb = STRBUF_INIT;16741675if(run_hook_le(NULL,"pre-applypatch", NULL))1676exit(1);16771678if(write_cache_as_tree(tree,0, NULL))1679die(_("git write-tree failed to write a tree"));16801681if(!get_sha1_commit("HEAD", parent)) {1682 ptr = parent;1683commit_list_insert(lookup_commit(parent), &parents);1684}else{1685 ptr = NULL;1686say(state, stderr,_("applying to an empty history"));1687}16881689 author =fmt_ident(state->author_name, state->author_email,1690 state->ignore_date ? NULL : state->author_date,1691 IDENT_STRICT);16921693if(state->committer_date_is_author_date)1694setenv("GIT_COMMITTER_DATE",1695 state->ignore_date ?"": state->author_date,1);16961697if(commit_tree(state->msg, state->msg_len, tree, parents, commit,1698 author, state->sign_commit))1699die(_("failed to write commit object"));17001701 reflog_msg =getenv("GIT_REFLOG_ACTION");1702if(!reflog_msg)1703 reflog_msg ="am";17041705strbuf_addf(&sb,"%s: %.*s", reflog_msg,linelen(state->msg),1706 state->msg);17071708update_ref(sb.buf,"HEAD", commit, ptr,0, UPDATE_REFS_DIE_ON_ERR);17091710if(state->rebasing) {1711FILE*fp =xfopen(am_path(state,"rewritten"),"a");17121713assert(!is_null_sha1(state->orig_commit));1714fprintf(fp,"%s",sha1_to_hex(state->orig_commit));1715fprintf(fp,"%s\n",sha1_to_hex(commit));1716fclose(fp);1717}17181719run_hook_le(NULL,"post-applypatch", NULL);17201721strbuf_release(&sb);1722}17231724/**1725 * Validates the am_state for resuming -- the "msg" and authorship fields must1726 * be filled up.1727 */1728static voidvalidate_resume_state(const struct am_state *state)1729{1730if(!state->msg)1731die(_("cannot resume:%sdoes not exist."),1732am_path(state,"final-commit"));17331734if(!state->author_name || !state->author_email || !state->author_date)1735die(_("cannot resume:%sdoes not exist."),1736am_path(state,"author-script"));1737}17381739/**1740 * Interactively prompt the user on whether the current patch should be1741 * applied.1742 *1743 * Returns 0 if the user chooses to apply the patch, 1 if the user chooses to1744 * skip it.1745 */1746static intdo_interactive(struct am_state *state)1747{1748assert(state->msg);17491750if(!isatty(0))1751die(_("cannot be interactive without stdin connected to a terminal."));17521753for(;;) {1754const char*reply;17551756puts(_("Commit Body is:"));1757puts("--------------------------");1758printf("%s", state->msg);1759puts("--------------------------");17601761/*1762 * TRANSLATORS: Make sure to include [y], [n], [e], [v] and [a]1763 * in your translation. The program will only accept English1764 * input at this point.1765 */1766 reply =git_prompt(_("Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all: "), PROMPT_ECHO);17671768if(!reply) {1769continue;1770}else if(*reply =='y'|| *reply =='Y') {1771return0;1772}else if(*reply =='a'|| *reply =='A') {1773 state->interactive =0;1774return0;1775}else if(*reply =='n'|| *reply =='N') {1776return1;1777}else if(*reply =='e'|| *reply =='E') {1778struct strbuf msg = STRBUF_INIT;17791780if(!launch_editor(am_path(state,"final-commit"), &msg, NULL)) {1781free(state->msg);1782 state->msg =strbuf_detach(&msg, &state->msg_len);1783}1784strbuf_release(&msg);1785}else if(*reply =='v'|| *reply =='V') {1786const char*pager =git_pager(1);1787struct child_process cp = CHILD_PROCESS_INIT;17881789if(!pager)1790 pager ="cat";1791prepare_pager_args(&cp, pager);1792argv_array_push(&cp.args,am_path(state,"patch"));1793run_command(&cp);1794}1795}1796}17971798/**1799 * Applies all queued mail.1800 *1801 * If `resume` is true, we are "resuming". The "msg" and authorship fields, as1802 * well as the state directory's "patch" file is used as-is for applying the1803 * patch and committing it.1804 */1805static voidam_run(struct am_state *state,int resume)1806{1807const char*argv_gc_auto[] = {"gc","--auto", NULL};1808struct strbuf sb = STRBUF_INIT;18091810unlink(am_path(state,"dirtyindex"));18111812refresh_and_write_cache();18131814if(index_has_changes(&sb)) {1815write_state_bool(state,"dirtyindex",1);1816die(_("Dirty index: cannot apply patches (dirty:%s)"), sb.buf);1817}18181819strbuf_release(&sb);18201821while(state->cur <= state->last) {1822const char*mail =am_path(state,msgnum(state));1823int apply_status;18241825reset_ident_date();18261827if(!file_exists(mail))1828goto next;18291830if(resume) {1831validate_resume_state(state);1832}else{1833int skip;18341835if(state->rebasing)1836 skip =parse_mail_rebase(state, mail);1837else1838 skip =parse_mail(state, mail);18391840if(skip)1841goto next;/* mail should be skipped */18421843write_author_script(state);1844write_commit_msg(state);1845}18461847if(state->interactive &&do_interactive(state))1848goto next;18491850if(run_applypatch_msg_hook(state))1851exit(1);18521853say(state, stdout,_("Applying: %.*s"),linelen(state->msg), state->msg);18541855 apply_status =run_apply(state, NULL);18561857if(apply_status && state->threeway) {1858struct strbuf sb = STRBUF_INIT;18591860strbuf_addstr(&sb,am_path(state,"patch-merge-index"));1861 apply_status =fall_back_threeway(state, sb.buf);1862strbuf_release(&sb);18631864/*1865 * Applying the patch to an earlier tree and merging1866 * the result may have produced the same tree as ours.1867 */1868if(!apply_status && !index_has_changes(NULL)) {1869say(state, stdout,_("No changes -- Patch already applied."));1870goto next;1871}1872}18731874if(apply_status) {1875int advice_amworkdir =1;18761877printf_ln(_("Patch failed at%s%.*s"),msgnum(state),1878linelen(state->msg), state->msg);18791880git_config_get_bool("advice.amworkdir", &advice_amworkdir);18811882if(advice_amworkdir)1883printf_ln(_("The copy of the patch that failed is found in:%s"),1884am_path(state,"patch"));18851886die_user_resolve(state);1887}18881889do_commit(state);18901891next:1892am_next(state);18931894if(resume)1895am_load(state);1896 resume =0;1897}18981899if(!is_empty_file(am_path(state,"rewritten"))) {1900assert(state->rebasing);1901copy_notes_for_rebase(state);1902run_post_rewrite_hook(state);1903}19041905/*1906 * In rebasing mode, it's up to the caller to take care of1907 * housekeeping.1908 */1909if(!state->rebasing) {1910am_destroy(state);1911close_all_packs();1912run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);1913}1914}19151916/**1917 * Resume the current am session after patch application failure. The user did1918 * all the hard work, and we do not have to do any patch application. Just1919 * trust and commit what the user has in the index and working tree.1920 */1921static voidam_resolve(struct am_state *state)1922{1923validate_resume_state(state);19241925say(state, stdout,_("Applying: %.*s"),linelen(state->msg), state->msg);19261927if(!index_has_changes(NULL)) {1928printf_ln(_("No changes - did you forget to use 'git add'?\n"1929"If there is nothing left to stage, chances are that something else\n"1930"already introduced the same changes; you might want to skip this patch."));1931die_user_resolve(state);1932}19331934if(unmerged_cache()) {1935printf_ln(_("You still have unmerged paths in your index.\n"1936"Did you forget to use 'git add'?"));1937die_user_resolve(state);1938}19391940if(state->interactive) {1941write_index_patch(state);1942if(do_interactive(state))1943goto next;1944}19451946rerere(0);19471948do_commit(state);19491950next:1951am_next(state);1952am_load(state);1953am_run(state,0);1954}19551956/**1957 * Performs a checkout fast-forward from `head` to `remote`. If `reset` is1958 * true, any unmerged entries will be discarded. Returns 0 on success, -1 on1959 * failure.1960 */1961static intfast_forward_to(struct tree *head,struct tree *remote,int reset)1962{1963struct lock_file *lock_file;1964struct unpack_trees_options opts;1965struct tree_desc t[2];19661967if(parse_tree(head) ||parse_tree(remote))1968return-1;19691970 lock_file =xcalloc(1,sizeof(struct lock_file));1971hold_locked_index(lock_file,1);19721973refresh_cache(REFRESH_QUIET);19741975memset(&opts,0,sizeof(opts));1976 opts.head_idx =1;1977 opts.src_index = &the_index;1978 opts.dst_index = &the_index;1979 opts.update =1;1980 opts.merge =1;1981 opts.reset = reset;1982 opts.fn = twoway_merge;1983init_tree_desc(&t[0], head->buffer, head->size);1984init_tree_desc(&t[1], remote->buffer, remote->size);19851986if(unpack_trees(2, t, &opts)) {1987rollback_lock_file(lock_file);1988return-1;1989}19901991if(write_locked_index(&the_index, lock_file, COMMIT_LOCK))1992die(_("unable to write new index file"));19931994return0;1995}19961997/**1998 * Merges a tree into the index. The index's stat info will take precedence1999 * over the merged tree's. Returns 0 on success, -1 on failure.2000 */2001static intmerge_tree(struct tree *tree)2002{2003struct lock_file *lock_file;2004struct unpack_trees_options opts;2005struct tree_desc t[1];20062007if(parse_tree(tree))2008return-1;20092010 lock_file =xcalloc(1,sizeof(struct lock_file));2011hold_locked_index(lock_file,1);20122013memset(&opts,0,sizeof(opts));2014 opts.head_idx =1;2015 opts.src_index = &the_index;2016 opts.dst_index = &the_index;2017 opts.merge =1;2018 opts.fn = oneway_merge;2019init_tree_desc(&t[0], tree->buffer, tree->size);20202021if(unpack_trees(1, t, &opts)) {2022rollback_lock_file(lock_file);2023return-1;2024}20252026if(write_locked_index(&the_index, lock_file, COMMIT_LOCK))2027die(_("unable to write new index file"));20282029return0;2030}20312032/**2033 * Clean the index without touching entries that are not modified between2034 * `head` and `remote`.2035 */2036static intclean_index(const unsigned char*head,const unsigned char*remote)2037{2038struct tree *head_tree, *remote_tree, *index_tree;2039unsigned char index[GIT_SHA1_RAWSZ];20402041 head_tree =parse_tree_indirect(head);2042if(!head_tree)2043returnerror(_("Could not parse object '%s'."),sha1_to_hex(head));20442045 remote_tree =parse_tree_indirect(remote);2046if(!remote_tree)2047returnerror(_("Could not parse object '%s'."),sha1_to_hex(remote));20482049read_cache_unmerged();20502051if(fast_forward_to(head_tree, head_tree,1))2052return-1;20532054if(write_cache_as_tree(index,0, NULL))2055return-1;20562057 index_tree =parse_tree_indirect(index);2058if(!index_tree)2059returnerror(_("Could not parse object '%s'."),sha1_to_hex(index));20602061if(fast_forward_to(index_tree, remote_tree,0))2062return-1;20632064if(merge_tree(remote_tree))2065return-1;20662067remove_branch_state();20682069return0;2070}20712072/**2073 * Resets rerere's merge resolution metadata.2074 */2075static voidam_rerere_clear(void)2076{2077struct string_list merge_rr = STRING_LIST_INIT_DUP;2078rerere_clear(&merge_rr);2079string_list_clear(&merge_rr,1);2080}20812082/**2083 * Resume the current am session by skipping the current patch.2084 */2085static voidam_skip(struct am_state *state)2086{2087unsigned char head[GIT_SHA1_RAWSZ];20882089am_rerere_clear();20902091if(get_sha1("HEAD", head))2092hashcpy(head, EMPTY_TREE_SHA1_BIN);20932094if(clean_index(head, head))2095die(_("failed to clean index"));20962097am_next(state);2098am_load(state);2099am_run(state,0);2100}21012102/**2103 * Returns true if it is safe to reset HEAD to the ORIG_HEAD, false otherwise.2104 *2105 * It is not safe to reset HEAD when:2106 * 1. git-am previously failed because the index was dirty.2107 * 2. HEAD has moved since git-am previously failed.2108 */2109static intsafe_to_abort(const struct am_state *state)2110{2111struct strbuf sb = STRBUF_INIT;2112unsigned char abort_safety[GIT_SHA1_RAWSZ], head[GIT_SHA1_RAWSZ];21132114if(file_exists(am_path(state,"dirtyindex")))2115return0;21162117if(read_state_file(&sb, state,"abort-safety",1) >0) {2118if(get_sha1_hex(sb.buf, abort_safety))2119die(_("could not parse%s"),am_path(state,"abort_safety"));2120}else2121hashclr(abort_safety);21222123if(get_sha1("HEAD", head))2124hashclr(head);21252126if(!hashcmp(head, abort_safety))2127return1;21282129error(_("You seem to have moved HEAD since the last 'am' failure.\n"2130"Not rewinding to ORIG_HEAD"));21312132return0;2133}21342135/**2136 * Aborts the current am session if it is safe to do so.2137 */2138static voidam_abort(struct am_state *state)2139{2140unsigned char curr_head[GIT_SHA1_RAWSZ], orig_head[GIT_SHA1_RAWSZ];2141int has_curr_head, has_orig_head;2142char*curr_branch;21432144if(!safe_to_abort(state)) {2145am_destroy(state);2146return;2147}21482149am_rerere_clear();21502151 curr_branch =resolve_refdup("HEAD",0, curr_head, NULL);2152 has_curr_head = !is_null_sha1(curr_head);2153if(!has_curr_head)2154hashcpy(curr_head, EMPTY_TREE_SHA1_BIN);21552156 has_orig_head = !get_sha1("ORIG_HEAD", orig_head);2157if(!has_orig_head)2158hashcpy(orig_head, EMPTY_TREE_SHA1_BIN);21592160clean_index(curr_head, orig_head);21612162if(has_orig_head)2163update_ref("am --abort","HEAD", orig_head,2164 has_curr_head ? curr_head : NULL,0,2165 UPDATE_REFS_DIE_ON_ERR);2166else if(curr_branch)2167delete_ref(curr_branch, NULL, REF_NODEREF);21682169free(curr_branch);2170am_destroy(state);2171}21722173/**2174 * parse_options() callback that validates and sets opt->value to the2175 * PATCH_FORMAT_* enum value corresponding to `arg`.2176 */2177static intparse_opt_patchformat(const struct option *opt,const char*arg,int unset)2178{2179int*opt_value = opt->value;21802181if(!strcmp(arg,"mbox"))2182*opt_value = PATCH_FORMAT_MBOX;2183else if(!strcmp(arg,"stgit"))2184*opt_value = PATCH_FORMAT_STGIT;2185else if(!strcmp(arg,"stgit-series"))2186*opt_value = PATCH_FORMAT_STGIT_SERIES;2187else if(!strcmp(arg,"hg"))2188*opt_value = PATCH_FORMAT_HG;2189else if(!strcmp(arg,"mboxrd"))2190*opt_value = PATCH_FORMAT_MBOXRD;2191else2192returnerror(_("Invalid value for --patch-format:%s"), arg);2193return0;2194}21952196enum resume_mode {2197 RESUME_FALSE =0,2198 RESUME_APPLY,2199 RESUME_RESOLVED,2200 RESUME_SKIP,2201 RESUME_ABORT2202};22032204static intgit_am_config(const char*k,const char*v,void*cb)2205{2206int status;22072208 status =git_gpg_config(k, v, NULL);2209if(status)2210return status;22112212returngit_default_config(k, v, NULL);2213}22142215intcmd_am(int argc,const char**argv,const char*prefix)2216{2217struct am_state state;2218int binary = -1;2219int keep_cr = -1;2220int patch_format = PATCH_FORMAT_UNKNOWN;2221enum resume_mode resume = RESUME_FALSE;2222int in_progress;22232224const char*const usage[] = {2225N_("git am [<options>] [(<mbox>|<Maildir>)...]"),2226N_("git am [<options>] (--continue | --skip | --abort)"),2227 NULL2228};22292230struct option options[] = {2231OPT_BOOL('i',"interactive", &state.interactive,2232N_("run interactively")),2233OPT_HIDDEN_BOOL('b',"binary", &binary,2234N_("historical option -- no-op")),2235OPT_BOOL('3',"3way", &state.threeway,2236N_("allow fall back on 3way merging if needed")),2237OPT__QUIET(&state.quiet,N_("be quiet")),2238OPT_SET_INT('s',"signoff", &state.signoff,2239N_("add a Signed-off-by line to the commit message"),2240 SIGNOFF_EXPLICIT),2241OPT_BOOL('u',"utf8", &state.utf8,2242N_("recode into utf8 (default)")),2243OPT_SET_INT('k',"keep", &state.keep,2244N_("pass -k flag to git-mailinfo"), KEEP_TRUE),2245OPT_SET_INT(0,"keep-non-patch", &state.keep,2246N_("pass -b flag to git-mailinfo"), KEEP_NON_PATCH),2247OPT_BOOL('m',"message-id", &state.message_id,2248N_("pass -m flag to git-mailinfo")),2249{ OPTION_SET_INT,0,"keep-cr", &keep_cr, NULL,2250N_("pass --keep-cr flag to git-mailsplit for mbox format"),2251 PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL,1},2252{ OPTION_SET_INT,0,"no-keep-cr", &keep_cr, NULL,2253N_("do not pass --keep-cr flag to git-mailsplit independent of am.keepcr"),2254 PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL,0},2255OPT_BOOL('c',"scissors", &state.scissors,2256N_("strip everything before a scissors line")),2257OPT_PASSTHRU_ARGV(0,"whitespace", &state.git_apply_opts,N_("action"),2258N_("pass it through git-apply"),22590),2260OPT_PASSTHRU_ARGV(0,"ignore-space-change", &state.git_apply_opts, NULL,2261N_("pass it through git-apply"),2262 PARSE_OPT_NOARG),2263OPT_PASSTHRU_ARGV(0,"ignore-whitespace", &state.git_apply_opts, NULL,2264N_("pass it through git-apply"),2265 PARSE_OPT_NOARG),2266OPT_PASSTHRU_ARGV(0,"directory", &state.git_apply_opts,N_("root"),2267N_("pass it through git-apply"),22680),2269OPT_PASSTHRU_ARGV(0,"exclude", &state.git_apply_opts,N_("path"),2270N_("pass it through git-apply"),22710),2272OPT_PASSTHRU_ARGV(0,"include", &state.git_apply_opts,N_("path"),2273N_("pass it through git-apply"),22740),2275OPT_PASSTHRU_ARGV('C', NULL, &state.git_apply_opts,N_("n"),2276N_("pass it through git-apply"),22770),2278OPT_PASSTHRU_ARGV('p', NULL, &state.git_apply_opts,N_("num"),2279N_("pass it through git-apply"),22800),2281OPT_CALLBACK(0,"patch-format", &patch_format,N_("format"),2282N_("format the patch(es) are in"),2283 parse_opt_patchformat),2284OPT_PASSTHRU_ARGV(0,"reject", &state.git_apply_opts, NULL,2285N_("pass it through git-apply"),2286 PARSE_OPT_NOARG),2287OPT_STRING(0,"resolvemsg", &state.resolvemsg, NULL,2288N_("override error message when patch failure occurs")),2289OPT_CMDMODE(0,"continue", &resume,2290N_("continue applying patches after resolving a conflict"),2291 RESUME_RESOLVED),2292OPT_CMDMODE('r',"resolved", &resume,2293N_("synonyms for --continue"),2294 RESUME_RESOLVED),2295OPT_CMDMODE(0,"skip", &resume,2296N_("skip the current patch"),2297 RESUME_SKIP),2298OPT_CMDMODE(0,"abort", &resume,2299N_("restore the original branch and abort the patching operation."),2300 RESUME_ABORT),2301OPT_BOOL(0,"committer-date-is-author-date",2302&state.committer_date_is_author_date,2303N_("lie about committer date")),2304OPT_BOOL(0,"ignore-date", &state.ignore_date,2305N_("use current timestamp for author date")),2306OPT_RERERE_AUTOUPDATE(&state.allow_rerere_autoupdate),2307{ OPTION_STRING,'S',"gpg-sign", &state.sign_commit,N_("key-id"),2308N_("GPG-sign commits"),2309 PARSE_OPT_OPTARG, NULL, (intptr_t)""},2310OPT_HIDDEN_BOOL(0,"rebasing", &state.rebasing,2311N_("(internal use for git-rebase)")),2312OPT_END()2313};23142315git_config(git_am_config, NULL);23162317am_state_init(&state,git_path("rebase-apply"));23182319 in_progress =am_in_progress(&state);2320if(in_progress)2321am_load(&state);23222323 argc =parse_options(argc, argv, prefix, options, usage,0);23242325if(binary >=0)2326fprintf_ln(stderr,_("The -b/--binary option has been a no-op for long time, and\n"2327"it will be removed. Please do not use it anymore."));23282329/* Ensure a valid committer ident can be constructed */2330git_committer_info(IDENT_STRICT);23312332if(read_index_preload(&the_index, NULL) <0)2333die(_("failed to read the index"));23342335if(in_progress) {2336/*2337 * Catch user error to feed us patches when there is a session2338 * in progress:2339 *2340 * 1. mbox path(s) are provided on the command-line.2341 * 2. stdin is not a tty: the user is trying to feed us a patch2342 * from standard input. This is somewhat unreliable -- stdin2343 * could be /dev/null for example and the caller did not2344 * intend to feed us a patch but wanted to continue2345 * unattended.2346 */2347if(argc || (resume == RESUME_FALSE && !isatty(0)))2348die(_("previous rebase directory%sstill exists but mbox given."),2349 state.dir);23502351if(resume == RESUME_FALSE)2352 resume = RESUME_APPLY;23532354if(state.signoff == SIGNOFF_EXPLICIT)2355am_append_signoff(&state);2356}else{2357struct argv_array paths = ARGV_ARRAY_INIT;2358int i;23592360/*2361 * Handle stray state directory in the independent-run case. In2362 * the --rebasing case, it is up to the caller to take care of2363 * stray directories.2364 */2365if(file_exists(state.dir) && !state.rebasing) {2366if(resume == RESUME_ABORT) {2367am_destroy(&state);2368am_state_release(&state);2369return0;2370}23712372die(_("Stray%sdirectory found.\n"2373"Use\"git am --abort\"to remove it."),2374 state.dir);2375}23762377if(resume)2378die(_("Resolve operation not in progress, we are not resuming."));23792380for(i =0; i < argc; i++) {2381if(is_absolute_path(argv[i]) || !prefix)2382argv_array_push(&paths, argv[i]);2383else2384argv_array_push(&paths,mkpath("%s/%s", prefix, argv[i]));2385}23862387am_setup(&state, patch_format, paths.argv, keep_cr);23882389argv_array_clear(&paths);2390}23912392switch(resume) {2393case RESUME_FALSE:2394am_run(&state,0);2395break;2396case RESUME_APPLY:2397am_run(&state,1);2398break;2399case RESUME_RESOLVED:2400am_resolve(&state);2401break;2402case RESUME_SKIP:2403am_skip(&state);2404break;2405case RESUME_ABORT:2406am_abort(&state);2407break;2408default:2409die("BUG: invalid resume value");2410}24112412am_state_release(&state);24132414return0;2415}