| | @@ -45,10 +45,11 @@ |
| 45 | 45 | ** to implement the various subcommands. |
| 46 | 46 | */ |
| 47 | 47 | #define PATCH_DRYRUN 0x0001 |
| 48 | 48 | #define PATCH_VERBOSE 0x0002 |
| 49 | 49 | #define PATCH_FORCE 0x0004 |
| 50 | +#define PATCH_RETRY 0x0008 /* Second attempt */ |
| 50 | 51 | |
| 51 | 52 | /* |
| 52 | 53 | ** Implementation of the "readfile(X)" SQL function. The entire content |
| 53 | 54 | ** of the check-out file named X is read and returned as a BLOB. |
| 54 | 55 | */ |
| | @@ -132,11 +133,13 @@ |
| 132 | 133 | } |
| 133 | 134 | |
| 134 | 135 | |
| 135 | 136 | /* |
| 136 | 137 | ** Generate a binary patch file and store it into the file |
| 137 | | -** named zOut. |
| 138 | +** named zOut. Or if zOut is NULL, write it into out. |
| 139 | +** |
| 140 | +** Return the number of errors. |
| 138 | 141 | */ |
| 139 | 142 | void patch_create(unsigned mFlags, const char *zOut, FILE *out){ |
| 140 | 143 | int vid; |
| 141 | 144 | char *z; |
| 142 | 145 | |
| | @@ -248,21 +251,22 @@ |
| 248 | 251 | } |
| 249 | 252 | #ifdef _WIN32 |
| 250 | 253 | fflush(out); |
| 251 | 254 | _setmode(_fileno(out), _O_BINARY); |
| 252 | 255 | #endif |
| 253 | | - fwrite(pData, sz, 1, out); |
| 254 | | - sqlite3_free(pData); |
| 256 | + fwrite(pData, 1, sz, out); |
| 255 | 257 | fflush(out); |
| 258 | + sqlite3_free(pData); |
| 256 | 259 | } |
| 260 | + db_multi_exec("DETACH patch;"); |
| 257 | 261 | } |
| 258 | 262 | |
| 259 | 263 | /* |
| 260 | 264 | ** Attempt to load and validate a patchfile identified by the first |
| 261 | 265 | ** argument. |
| 262 | 266 | */ |
| 263 | | -void patch_attach(const char *zIn, FILE *in){ |
| 267 | +void patch_attach(const char *zIn, FILE *in, int bIgnoreEmptyPatch){ |
| 264 | 268 | Stmt q; |
| 265 | 269 | if( g.db==0 ){ |
| 266 | 270 | sqlite3_open(":memory:", &g.db); |
| 267 | 271 | } |
| 268 | 272 | if( zIn==0 ){ |
| | @@ -274,10 +278,15 @@ |
| 274 | 278 | #ifdef _WIN32 |
| 275 | 279 | _setmode(_fileno(in), _O_BINARY); |
| 276 | 280 | #endif |
| 277 | 281 | sz = blob_read_from_channel(&buf, in, -1); |
| 278 | 282 | pData = (unsigned char*)blob_buffer(&buf); |
| 283 | + if( sz<512 ){ |
| 284 | + blob_reset(&buf); |
| 285 | + if( bIgnoreEmptyPatch ) return; |
| 286 | + fossil_fatal("input is too small to be a patch file"); |
| 287 | + } |
| 279 | 288 | db_multi_exec("ATTACH ':memory:' AS patch"); |
| 280 | 289 | if( g.fSqlTrace ){ |
| 281 | 290 | fossil_trace("-- deserialize(\"patch\", pData, %lld);\n", sz); |
| 282 | 291 | } |
| 283 | 292 | rc = sqlite3_deserialize(g.db, "patch", pData, sz, sz, 0); |
| | @@ -664,18 +673,20 @@ |
| 664 | 673 | const char *zThisCmd, /* "push" or "pull" */ |
| 665 | 674 | const char *zRemoteCmd, /* "apply" or "create" */ |
| 666 | 675 | const char *zFossilCmd, /* Name of "fossil" on remote system */ |
| 667 | 676 | const char *zRW /* "w" or "r" */ |
| 668 | 677 | ){ |
| 669 | | - char *zRemote; |
| 670 | | - char *zDir; |
| 678 | + char *zRemote = 0; |
| 679 | + char *zDir = 0; |
| 671 | 680 | Blob cmd; |
| 672 | | - FILE *f; |
| 681 | + FILE *f = 0; |
| 673 | 682 | Blob flgs; |
| 674 | | - char *zForce; |
| 683 | + char *zForce = 0; |
| 684 | + int isRetry = (mFlags & PATCH_RETRY)!=0; |
| 675 | 685 | |
| 676 | 686 | blob_init(&flgs, 0, 0); |
| 687 | + blob_init(&cmd, 0, 0); |
| 677 | 688 | if( mFlags & PATCH_FORCE ) blob_appendf(&flgs, " -f"); |
| 678 | 689 | if( mFlags & PATCH_VERBOSE ) blob_appendf(&flgs, " -v"); |
| 679 | 690 | if( mFlags & PATCH_DRYRUN ) blob_appendf(&flgs, " -n"); |
| 680 | 691 | zForce = blob_size(&flgs)>0 ? blob_str(&flgs) : ""; |
| 681 | 692 | if( g.argc!=4 ){ |
| | @@ -682,12 +693,12 @@ |
| 682 | 693 | usage(mprintf("%s [USER@]HOST:DIRECTORY", zThisCmd)); |
| 683 | 694 | } |
| 684 | 695 | zRemote = fossil_strdup(g.argv[3]); |
| 685 | 696 | zDir = (char*)file_skip_userhost(zRemote); |
| 686 | 697 | if( zDir==0 ){ |
| 698 | + if( isRetry ) goto remote_command_error; |
| 687 | 699 | zDir = zRemote; |
| 688 | | - blob_init(&cmd, 0, 0); |
| 689 | 700 | blob_append_escaped_arg(&cmd, g.nameOfExe, 1); |
| 690 | 701 | blob_appendf(&cmd, " patch %s%s %$ -", zRemoteCmd, zForce, zDir); |
| 691 | 702 | }else{ |
| 692 | 703 | Blob remote; |
| 693 | 704 | *(char*)(zDir-1) = 0; |
| | @@ -694,28 +705,52 @@ |
| 694 | 705 | transport_ssh_command(&cmd); |
| 695 | 706 | blob_appendf(&cmd, " -T"); |
| 696 | 707 | blob_append_escaped_arg(&cmd, zRemote, 0); |
| 697 | 708 | blob_init(&remote, 0, 0); |
| 698 | 709 | if( zFossilCmd==0 ){ |
| 699 | | - blob_append_escaped_arg(&cmd, "PATH=$HOME/bin:$PATH", 0); |
| 710 | + if( ssh_needs_path_argument(zRemote,-1) ^ isRetry ){ |
| 711 | + ssh_add_path_argument(&cmd); |
| 712 | + } |
| 700 | 713 | zFossilCmd = "fossil"; |
| 714 | + }else if( mFlags & PATCH_RETRY ){ |
| 715 | + goto remote_command_error; |
| 701 | 716 | } |
| 702 | 717 | blob_appendf(&remote, "%$ patch %s%s --dir64 %z -", |
| 703 | 718 | zFossilCmd, zRemoteCmd, zForce, encode64(zDir, -1)); |
| 704 | 719 | blob_append_escaped_arg(&cmd, blob_str(&remote), 0); |
| 705 | 720 | blob_reset(&remote); |
| 706 | 721 | } |
| 722 | + if( isRetry ){ |
| 723 | + fossil_print("First attempt to run \"fossil\" on %s failed\n" |
| 724 | + "Retry: ", zRemote); |
| 725 | + } |
| 707 | 726 | fossil_print("%s\n", blob_str(&cmd)); |
| 708 | 727 | fflush(stdout); |
| 709 | 728 | f = popen(blob_str(&cmd), zRW); |
| 710 | 729 | if( f==0 ){ |
| 711 | 730 | fossil_fatal("cannot run command: %s", blob_str(&cmd)); |
| 712 | 731 | } |
| 732 | +remote_command_error: |
| 733 | + fossil_free(zRemote); |
| 713 | 734 | blob_reset(&cmd); |
| 714 | 735 | blob_reset(&flgs); |
| 715 | 736 | return f; |
| 716 | 737 | } |
| 738 | + |
| 739 | +/* |
| 740 | +** Toggle the use-path-for-ssh setting for the remote host defined |
| 741 | +** by g.argv[3]. |
| 742 | +*/ |
| 743 | +static void patch_toggle_ssh_needs_path(void){ |
| 744 | + char *zRemote = fossil_strdup(g.argv[3]); |
| 745 | + char *zDir = (char*)file_skip_userhost(zRemote); |
| 746 | + if( zDir ){ |
| 747 | + *(char*)(zDir - 1) = 0; |
| 748 | + ssh_needs_path_argument(zRemote, 99); |
| 749 | + } |
| 750 | + fossil_free(zRemote); |
| 751 | +} |
| 717 | 752 | |
| 718 | 753 | /* |
| 719 | 754 | ** Show a diff for the patch currently loaded into database "patch". |
| 720 | 755 | */ |
| 721 | 756 | static void patch_diff( |
| | @@ -934,11 +969,11 @@ |
| 934 | 969 | if( find_option("dry-run","n",0) ) flags |= PATCH_DRYRUN; |
| 935 | 970 | if( find_option("verbose","v",0) ) flags |= PATCH_VERBOSE; |
| 936 | 971 | if( find_option("force","f",0) ) flags |= PATCH_FORCE; |
| 937 | 972 | zIn = patch_find_patch_filename("apply"); |
| 938 | 973 | db_must_be_within_tree(); |
| 939 | | - patch_attach(zIn, stdin); |
| 974 | + patch_attach(zIn, stdin, 0); |
| 940 | 975 | patch_apply(flags); |
| 941 | 976 | fossil_free(zIn); |
| 942 | 977 | }else |
| 943 | 978 | if( strncmp(zCmd, "create", n)==0 ){ |
| 944 | 979 | char *zOut; |
| | @@ -963,11 +998,11 @@ |
| 963 | 998 | db_find_and_open_repository(0, 0); |
| 964 | 999 | if( find_option("force","f",0) ) flags |= PATCH_FORCE; |
| 965 | 1000 | diff_options(&DCfg, zCmd[0]=='g', 0); |
| 966 | 1001 | verify_all_options(); |
| 967 | 1002 | zIn = patch_find_patch_filename("apply"); |
| 968 | | - patch_attach(zIn, stdin); |
| 1003 | + patch_attach(zIn, stdin, 0); |
| 969 | 1004 | patch_diff(flags, &DCfg); |
| 970 | 1005 | fossil_free(zIn); |
| 971 | 1006 | }else |
| 972 | 1007 | if( strncmp(zCmd, "pull", n)==0 ){ |
| 973 | 1008 | FILE *pIn = 0; |
| | @@ -979,12 +1014,22 @@ |
| 979 | 1014 | db_must_be_within_tree(); |
| 980 | 1015 | verify_all_options(); |
| 981 | 1016 | pIn = patch_remote_command(flags & (~PATCH_FORCE), |
| 982 | 1017 | "pull", "create", zFossilCmd, "r"); |
| 983 | 1018 | if( pIn ){ |
| 984 | | - patch_attach(0, pIn); |
| 985 | | - pclose(pIn); |
| 1019 | + patch_attach(0, pIn, 1); |
| 1020 | + if( pclose(pIn) ){ |
| 1021 | + flags |= PATCH_RETRY; |
| 1022 | + pIn = patch_remote_command(flags & (~PATCH_FORCE), |
| 1023 | + "pull", "create", zFossilCmd, "r"); |
| 1024 | + if( pIn ){ |
| 1025 | + patch_attach(0, pIn, 0); |
| 1026 | + if( pclose(pIn)==0 ){ |
| 1027 | + patch_toggle_ssh_needs_path(); |
| 1028 | + } |
| 1029 | + } |
| 1030 | + } |
| 986 | 1031 | patch_apply(flags); |
| 987 | 1032 | } |
| 988 | 1033 | }else |
| 989 | 1034 | if( strncmp(zCmd, "push", n)==0 ){ |
| 990 | 1035 | FILE *pOut = 0; |
| | @@ -996,11 +1041,20 @@ |
| 996 | 1041 | db_must_be_within_tree(); |
| 997 | 1042 | verify_all_options(); |
| 998 | 1043 | pOut = patch_remote_command(flags, "push", "apply", zFossilCmd, "w"); |
| 999 | 1044 | if( pOut ){ |
| 1000 | 1045 | patch_create(0, 0, pOut); |
| 1001 | | - pclose(pOut); |
| 1046 | + if( pclose(pOut)!=0 ){ |
| 1047 | + flags |= PATCH_RETRY; |
| 1048 | + pOut = patch_remote_command(flags, "push", "apply", zFossilCmd, "w"); |
| 1049 | + if( pOut ){ |
| 1050 | + patch_create(0, 0, pOut); |
| 1051 | + if( pclose(pOut)==0 ){ |
| 1052 | + patch_toggle_ssh_needs_path(); |
| 1053 | + } |
| 1054 | + } |
| 1055 | + } |
| 1002 | 1056 | } |
| 1003 | 1057 | }else |
| 1004 | 1058 | if( strncmp(zCmd, "view", n)==0 ){ |
| 1005 | 1059 | const char *zIn; |
| 1006 | 1060 | unsigned int flags = 0; |
| | @@ -1009,12 +1063,12 @@ |
| 1009 | 1063 | if( g.argc!=4 ){ |
| 1010 | 1064 | usage("view FILENAME"); |
| 1011 | 1065 | } |
| 1012 | 1066 | zIn = g.argv[3]; |
| 1013 | 1067 | if( fossil_strcmp(zIn, "-")==0 ) zIn = 0; |
| 1014 | | - patch_attach(zIn, stdin); |
| 1068 | + patch_attach(zIn, stdin, 0); |
| 1015 | 1069 | patch_view(flags); |
| 1016 | 1070 | }else |
| 1017 | 1071 | { |
| 1018 | 1072 | goto patch_usage; |
| 1019 | 1073 | } |
| 1020 | 1074 | } |
| 1021 | 1075 | |