| | @@ -698,10 +698,26 @@ |
| 698 | 698 | fossil_fatal("cannot change to directory \"%s\"", zDir); |
| 699 | 699 | } |
| 700 | 700 | fossil_free(zToFree); |
| 701 | 701 | return zPatchFile; |
| 702 | 702 | } |
| 703 | + |
| 704 | +/* |
| 705 | +** Resolves a patch-command remote system name, accounting for patch |
| 706 | +** aliases. |
| 707 | +** |
| 708 | +** If a CONFIG table entry matching name='patch-alias:$zKey' is found, |
| 709 | +** the corresponding value is returned, else a fossil_strdup() of zKey |
| 710 | +** is returned. The caller is responsible for passing the resulting |
| 711 | +** string to fossil_free(). |
| 712 | +*/ |
| 713 | +static char *patch_resolve_remote(const char *zKey){ |
| 714 | + char *zAlias = db_text(0, "SELECT value FROM config " |
| 715 | + "WHERE name = 'patch-alias:%q'", |
| 716 | + zKey); |
| 717 | + return zAlias ? zAlias : fossil_strdup(zKey); |
| 718 | +} |
| 703 | 719 | |
| 704 | 720 | /* |
| 705 | 721 | ** Create a FILE* that will execute the remote side of a push or pull |
| 706 | 722 | ** using ssh (probably) or fossil for local pushes and pulls. Return |
| 707 | 723 | ** a FILE* obtained from popen() into which we write the patch, or from |
| | @@ -729,11 +745,11 @@ |
| 729 | 745 | if( mFlags & PATCH_DRYRUN ) blob_appendf(&flgs, " -n"); |
| 730 | 746 | zForce = blob_size(&flgs)>0 ? blob_str(&flgs) : ""; |
| 731 | 747 | if( g.argc!=4 ){ |
| 732 | 748 | usage(mprintf("%s [USER@]HOST:DIRECTORY", zThisCmd)); |
| 733 | 749 | } |
| 734 | | - zRemote = fossil_strdup(g.argv[3]); |
| 750 | + zRemote = patch_resolve_remote(g.argv[3]); |
| 735 | 751 | zDir = (char*)file_skip_userhost(zRemote); |
| 736 | 752 | if( zDir==0 ){ |
| 737 | 753 | if( isRetry ) goto remote_command_error; |
| 738 | 754 | zDir = zRemote; |
| 739 | 755 | blob_append_escaped_arg(&cmd, g.nameOfExe, 1); |
| | @@ -778,11 +794,11 @@ |
| 778 | 794 | /* |
| 779 | 795 | ** Toggle the use-path-for-ssh setting for the remote host defined |
| 780 | 796 | ** by g.argv[3]. |
| 781 | 797 | */ |
| 782 | 798 | static void patch_toggle_ssh_needs_path(void){ |
| 783 | | - char *zRemote = fossil_strdup(g.argv[3]); |
| 799 | + char *zRemote = patch_resolve_remote(g.argv[3]); |
| 784 | 800 | char *zDir = (char*)file_skip_userhost(zRemote); |
| 785 | 801 | if( zDir ){ |
| 786 | 802 | *(char*)(zDir - 1) = 0; |
| 787 | 803 | ssh_needs_path_argument(zRemote, 99); |
| 788 | 804 | } |
| | @@ -905,11 +921,10 @@ |
| 905 | 921 | db_finalize(&q); |
| 906 | 922 | diff_end(pCfg, nErr); |
| 907 | 923 | if( nErr ) fossil_fatal("abort due to prior errors"); |
| 908 | 924 | } |
| 909 | 925 | |
| 910 | | - |
| 911 | 926 | /* |
| 912 | 927 | ** COMMAND: patch |
| 913 | 928 | ** |
| 914 | 929 | ** Usage: %fossil patch SUBCOMMAND ?ARGS ..? |
| 915 | 930 | ** |
| | @@ -916,10 +931,22 @@ |
| 916 | 931 | ** This command is used to create, view, and apply Fossil binary patches. |
| 917 | 932 | ** A Fossil binary patch is a single (binary) file that captures all of the |
| 918 | 933 | ** uncommitted changes of a check-out. Use Fossil binary patches to transfer |
| 919 | 934 | ** proposed or incomplete changes between machines for testing or analysis. |
| 920 | 935 | ** |
| 936 | +** > fossil patch alias add|rm|ls|list ?ARGS? |
| 937 | +** |
| 938 | +** Manage remote-name aliases, which act as short-form |
| 939 | +** equivalents to REMOTE-CHECKOUT strings. Aliases are local to |
| 940 | +** a given repository and do not sync. Subcommands: |
| 941 | +** |
| 942 | +** ... add ALIAS REMOTE-CHECKOUT Add ALIAS as an alias |
| 943 | +** for REMOTE-CHECKOUT. |
| 944 | +** ... ls|list List all local aliases. |
| 945 | +** ... rm ALIAS [ALIAS...] Remove named aliases |
| 946 | +** ... rm --all Remove all aliases |
| 947 | +** |
| 921 | 948 | ** > fossil patch create [DIRECTORY] PATCHFILE |
| 922 | 949 | ** |
| 923 | 950 | ** Create a new binary patch in PATCHFILE that captures all uncommitted |
| 924 | 951 | ** changes in the check-out at DIRECTORY, or the current directory if |
| 925 | 952 | ** DIRECTORY is omitted. If PATCHFILE is "-" then the binary patch |
| | @@ -996,14 +1023,76 @@ |
| 996 | 1023 | void patch_cmd(void){ |
| 997 | 1024 | const char *zCmd; |
| 998 | 1025 | size_t n; |
| 999 | 1026 | if( g.argc<3 ){ |
| 1000 | 1027 | patch_usage: |
| 1001 | | - usage("apply|create|diff|gdiff|pull|push|view"); |
| 1028 | + usage("alias|apply|create|diff|gdiff|pull|push|view"); |
| 1002 | 1029 | } |
| 1003 | 1030 | zCmd = g.argv[2]; |
| 1004 | 1031 | n = strlen(zCmd); |
| 1032 | + if( strncmp(zCmd, "alias", n)==0 ){ |
| 1033 | + const char * zArg = g.argc>3 ? g.argv[3] : 0; |
| 1034 | + db_must_be_within_tree(); |
| 1035 | + if( 0==zArg ){ |
| 1036 | + goto usage_patch_alias; |
| 1037 | + }else if( 0==strcmp("ls",zArg) || 0==strcmp("list",zArg) ){ |
| 1038 | + /* alias ls|list */ |
| 1039 | + Stmt q; |
| 1040 | + int nAlias = 0; |
| 1041 | + |
| 1042 | + verify_all_options(); |
| 1043 | + db_prepare(&q, "SELECT substr(name,13), value FROM config " |
| 1044 | + "WHERE name GLOB 'patch-alias:*' ORDER BY name"); |
| 1045 | + while( SQLITE_ROW==db_step(&q) ){ |
| 1046 | + const char *zName = db_column_text(&q, 0); |
| 1047 | + const char *zVal = db_column_text(&q, 1); |
| 1048 | + ++nAlias; |
| 1049 | + fossil_print("%s = %s\n", zName, zVal); |
| 1050 | + } |
| 1051 | + db_finalize(&q); |
| 1052 | + if( 0==nAlias ){ |
| 1053 | + fossil_print("No patch aliases defined\n"); |
| 1054 | + } |
| 1055 | + }else if( 0==strcmp("add", zArg) ){ |
| 1056 | + /* alias add localName remote */ |
| 1057 | + verify_all_options(); |
| 1058 | + if( 6!=g.argc ){ |
| 1059 | + usage("alias add localName remote"); |
| 1060 | + } |
| 1061 | + db_unprotect(PROTECT_CONFIG); |
| 1062 | + db_multi_exec("REPLACE INTO config (name, value, mtime) " |
| 1063 | + "VALUES ('patch-alias:%q', %Q, unixepoch())", |
| 1064 | + g.argv[4], g.argv[5]); |
| 1065 | + db_protect_pop(); |
| 1066 | + }else if( 0==strcmp("rm", zArg) ){ |
| 1067 | + /* alias rm */ |
| 1068 | + const int fAll = 0!=find_option("all", 0, 0); |
| 1069 | + if( fAll ? g.argc<4 : g.argc<5 ){ |
| 1070 | + usage("alias rm [-all] [aliasGlob [...aliasGlobN]]"); |
| 1071 | + } |
| 1072 | + verify_all_options(); |
| 1073 | + db_unprotect(PROTECT_CONFIG); |
| 1074 | + if( 0!=fAll ){ |
| 1075 | + db_multi_exec("DELETE FROM config WHERE name GLOB 'patch-alias:*'"); |
| 1076 | + }else{ |
| 1077 | + Stmt q; |
| 1078 | + int i; |
| 1079 | + db_prepare(&q, "DELETE FROM config WHERE name " |
| 1080 | + "GLOB 'patch-alias:' || :pattern"); |
| 1081 | + for(i = 4; i < g.argc; ++i){ |
| 1082 | + db_bind_text(&q, ":pattern", g.argv[i]); |
| 1083 | + db_step(&q); |
| 1084 | + db_reset(&q); |
| 1085 | + } |
| 1086 | + db_finalize(&q); |
| 1087 | + } |
| 1088 | + db_protect_pop(); |
| 1089 | + }else{ |
| 1090 | + usage_patch_alias: |
| 1091 | + usage("alias ls|list|add|rm ..."); |
| 1092 | + } |
| 1093 | + }else |
| 1005 | 1094 | if( strncmp(zCmd, "apply", n)==0 ){ |
| 1006 | 1095 | char *zIn; |
| 1007 | 1096 | unsigned flags = 0; |
| 1008 | 1097 | if( find_option("dry-run","n",0) ) flags |= PATCH_DRYRUN; |
| 1009 | 1098 | if( find_option("verbose","v",0) ) flags |= PATCH_VERBOSE; |
| 1010 | 1099 | |