Fossil SCM

Add the (patch alias) subcommand.

stephan 2025-02-28 21:32 trunk merge
Commit b4db86af24d7d640f10594bfcacaf91285a2ce3c7fa225d649ee2f63b6bf9197
+93 -4
--- src/patch.c
+++ src/patch.c
@@ -698,10 +698,26 @@
698698
fossil_fatal("cannot change to directory \"%s\"", zDir);
699699
}
700700
fossil_free(zToFree);
701701
return zPatchFile;
702702
}
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
+}
703719
704720
/*
705721
** Create a FILE* that will execute the remote side of a push or pull
706722
** using ssh (probably) or fossil for local pushes and pulls. Return
707723
** a FILE* obtained from popen() into which we write the patch, or from
@@ -729,11 +745,11 @@
729745
if( mFlags & PATCH_DRYRUN ) blob_appendf(&flgs, " -n");
730746
zForce = blob_size(&flgs)>0 ? blob_str(&flgs) : "";
731747
if( g.argc!=4 ){
732748
usage(mprintf("%s [USER@]HOST:DIRECTORY", zThisCmd));
733749
}
734
- zRemote = fossil_strdup(g.argv[3]);
750
+ zRemote = patch_resolve_remote(g.argv[3]);
735751
zDir = (char*)file_skip_userhost(zRemote);
736752
if( zDir==0 ){
737753
if( isRetry ) goto remote_command_error;
738754
zDir = zRemote;
739755
blob_append_escaped_arg(&cmd, g.nameOfExe, 1);
@@ -778,11 +794,11 @@
778794
/*
779795
** Toggle the use-path-for-ssh setting for the remote host defined
780796
** by g.argv[3].
781797
*/
782798
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]);
784800
char *zDir = (char*)file_skip_userhost(zRemote);
785801
if( zDir ){
786802
*(char*)(zDir - 1) = 0;
787803
ssh_needs_path_argument(zRemote, 99);
788804
}
@@ -905,11 +921,10 @@
905921
db_finalize(&q);
906922
diff_end(pCfg, nErr);
907923
if( nErr ) fossil_fatal("abort due to prior errors");
908924
}
909925
910
-
911926
/*
912927
** COMMAND: patch
913928
**
914929
** Usage: %fossil patch SUBCOMMAND ?ARGS ..?
915930
**
@@ -916,10 +931,22 @@
916931
** This command is used to create, view, and apply Fossil binary patches.
917932
** A Fossil binary patch is a single (binary) file that captures all of the
918933
** uncommitted changes of a check-out. Use Fossil binary patches to transfer
919934
** proposed or incomplete changes between machines for testing or analysis.
920935
**
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
+**
921948
** > fossil patch create [DIRECTORY] PATCHFILE
922949
**
923950
** Create a new binary patch in PATCHFILE that captures all uncommitted
924951
** changes in the check-out at DIRECTORY, or the current directory if
925952
** DIRECTORY is omitted. If PATCHFILE is "-" then the binary patch
@@ -996,14 +1023,76 @@
9961023
void patch_cmd(void){
9971024
const char *zCmd;
9981025
size_t n;
9991026
if( g.argc<3 ){
10001027
patch_usage:
1001
- usage("apply|create|diff|gdiff|pull|push|view");
1028
+ usage("alias|apply|create|diff|gdiff|pull|push|view");
10021029
}
10031030
zCmd = g.argv[2];
10041031
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
10051094
if( strncmp(zCmd, "apply", n)==0 ){
10061095
char *zIn;
10071096
unsigned flags = 0;
10081097
if( find_option("dry-run","n",0) ) flags |= PATCH_DRYRUN;
10091098
if( find_option("verbose","v",0) ) flags |= PATCH_VERBOSE;
10101099
--- src/patch.c
+++ src/patch.c
@@ -698,10 +698,26 @@
698 fossil_fatal("cannot change to directory \"%s\"", zDir);
699 }
700 fossil_free(zToFree);
701 return zPatchFile;
702 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
703
704 /*
705 ** Create a FILE* that will execute the remote side of a push or pull
706 ** using ssh (probably) or fossil for local pushes and pulls. Return
707 ** a FILE* obtained from popen() into which we write the patch, or from
@@ -729,11 +745,11 @@
729 if( mFlags & PATCH_DRYRUN ) blob_appendf(&flgs, " -n");
730 zForce = blob_size(&flgs)>0 ? blob_str(&flgs) : "";
731 if( g.argc!=4 ){
732 usage(mprintf("%s [USER@]HOST:DIRECTORY", zThisCmd));
733 }
734 zRemote = fossil_strdup(g.argv[3]);
735 zDir = (char*)file_skip_userhost(zRemote);
736 if( zDir==0 ){
737 if( isRetry ) goto remote_command_error;
738 zDir = zRemote;
739 blob_append_escaped_arg(&cmd, g.nameOfExe, 1);
@@ -778,11 +794,11 @@
778 /*
779 ** Toggle the use-path-for-ssh setting for the remote host defined
780 ** by g.argv[3].
781 */
782 static void patch_toggle_ssh_needs_path(void){
783 char *zRemote = fossil_strdup(g.argv[3]);
784 char *zDir = (char*)file_skip_userhost(zRemote);
785 if( zDir ){
786 *(char*)(zDir - 1) = 0;
787 ssh_needs_path_argument(zRemote, 99);
788 }
@@ -905,11 +921,10 @@
905 db_finalize(&q);
906 diff_end(pCfg, nErr);
907 if( nErr ) fossil_fatal("abort due to prior errors");
908 }
909
910
911 /*
912 ** COMMAND: patch
913 **
914 ** Usage: %fossil patch SUBCOMMAND ?ARGS ..?
915 **
@@ -916,10 +931,22 @@
916 ** This command is used to create, view, and apply Fossil binary patches.
917 ** A Fossil binary patch is a single (binary) file that captures all of the
918 ** uncommitted changes of a check-out. Use Fossil binary patches to transfer
919 ** proposed or incomplete changes between machines for testing or analysis.
920 **
 
 
 
 
 
 
 
 
 
 
 
 
921 ** > fossil patch create [DIRECTORY] PATCHFILE
922 **
923 ** Create a new binary patch in PATCHFILE that captures all uncommitted
924 ** changes in the check-out at DIRECTORY, or the current directory if
925 ** DIRECTORY is omitted. If PATCHFILE is "-" then the binary patch
@@ -996,14 +1023,76 @@
996 void patch_cmd(void){
997 const char *zCmd;
998 size_t n;
999 if( g.argc<3 ){
1000 patch_usage:
1001 usage("apply|create|diff|gdiff|pull|push|view");
1002 }
1003 zCmd = g.argv[2];
1004 n = strlen(zCmd);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1005 if( strncmp(zCmd, "apply", n)==0 ){
1006 char *zIn;
1007 unsigned flags = 0;
1008 if( find_option("dry-run","n",0) ) flags |= PATCH_DRYRUN;
1009 if( find_option("verbose","v",0) ) flags |= PATCH_VERBOSE;
1010
--- src/patch.c
+++ src/patch.c
@@ -698,10 +698,26 @@
698 fossil_fatal("cannot change to directory \"%s\"", zDir);
699 }
700 fossil_free(zToFree);
701 return zPatchFile;
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 }
719
720 /*
721 ** Create a FILE* that will execute the remote side of a push or pull
722 ** using ssh (probably) or fossil for local pushes and pulls. Return
723 ** a FILE* obtained from popen() into which we write the patch, or from
@@ -729,11 +745,11 @@
745 if( mFlags & PATCH_DRYRUN ) blob_appendf(&flgs, " -n");
746 zForce = blob_size(&flgs)>0 ? blob_str(&flgs) : "";
747 if( g.argc!=4 ){
748 usage(mprintf("%s [USER@]HOST:DIRECTORY", zThisCmd));
749 }
750 zRemote = patch_resolve_remote(g.argv[3]);
751 zDir = (char*)file_skip_userhost(zRemote);
752 if( zDir==0 ){
753 if( isRetry ) goto remote_command_error;
754 zDir = zRemote;
755 blob_append_escaped_arg(&cmd, g.nameOfExe, 1);
@@ -778,11 +794,11 @@
794 /*
795 ** Toggle the use-path-for-ssh setting for the remote host defined
796 ** by g.argv[3].
797 */
798 static void patch_toggle_ssh_needs_path(void){
799 char *zRemote = patch_resolve_remote(g.argv[3]);
800 char *zDir = (char*)file_skip_userhost(zRemote);
801 if( zDir ){
802 *(char*)(zDir - 1) = 0;
803 ssh_needs_path_argument(zRemote, 99);
804 }
@@ -905,11 +921,10 @@
921 db_finalize(&q);
922 diff_end(pCfg, nErr);
923 if( nErr ) fossil_fatal("abort due to prior errors");
924 }
925
 
926 /*
927 ** COMMAND: patch
928 **
929 ** Usage: %fossil patch SUBCOMMAND ?ARGS ..?
930 **
@@ -916,10 +931,22 @@
931 ** This command is used to create, view, and apply Fossil binary patches.
932 ** A Fossil binary patch is a single (binary) file that captures all of the
933 ** uncommitted changes of a check-out. Use Fossil binary patches to transfer
934 ** proposed or incomplete changes between machines for testing or analysis.
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 **
948 ** > fossil patch create [DIRECTORY] PATCHFILE
949 **
950 ** Create a new binary patch in PATCHFILE that captures all uncommitted
951 ** changes in the check-out at DIRECTORY, or the current directory if
952 ** DIRECTORY is omitted. If PATCHFILE is "-" then the binary patch
@@ -996,14 +1023,76 @@
1023 void patch_cmd(void){
1024 const char *zCmd;
1025 size_t n;
1026 if( g.argc<3 ){
1027 patch_usage:
1028 usage("alias|apply|create|diff|gdiff|pull|push|view");
1029 }
1030 zCmd = g.argv[2];
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
1094 if( strncmp(zCmd, "apply", n)==0 ){
1095 char *zIn;
1096 unsigned flags = 0;
1097 if( find_option("dry-run","n",0) ) flags |= PATCH_DRYRUN;
1098 if( find_option("verbose","v",0) ) flags |= PATCH_VERBOSE;
1099
--- www/changes.wiki
+++ www/changes.wiki
@@ -53,10 +53,12 @@
5353
and debugging
5454
* Fix a bug in [/help?cmd=patch|fossil patch create] that causes
5555
[/help?cmd=revert|fossil revert] operations that happened on individual
5656
files after a [/help?cmd=merge|fossil merge] to be omitted from the
5757
patch.
58
+ * Added the [/help?cmd=patch|patch alias] command for managing aliases
59
+ for remote checkout names.
5860
5961
<h2 id='v2_25'>Changes for version 2.25 (2024-11-06)</h2>
6062
6163
* The "[/help?cmd=ui|fossil ui /]" command now works even for repositories
6264
that have non-ASCII filenames
6365
--- www/changes.wiki
+++ www/changes.wiki
@@ -53,10 +53,12 @@
53 and debugging
54 * Fix a bug in [/help?cmd=patch|fossil patch create] that causes
55 [/help?cmd=revert|fossil revert] operations that happened on individual
56 files after a [/help?cmd=merge|fossil merge] to be omitted from the
57 patch.
 
 
58
59 <h2 id='v2_25'>Changes for version 2.25 (2024-11-06)</h2>
60
61 * The "[/help?cmd=ui|fossil ui /]" command now works even for repositories
62 that have non-ASCII filenames
63
--- www/changes.wiki
+++ www/changes.wiki
@@ -53,10 +53,12 @@
53 and debugging
54 * Fix a bug in [/help?cmd=patch|fossil patch create] that causes
55 [/help?cmd=revert|fossil revert] operations that happened on individual
56 files after a [/help?cmd=merge|fossil merge] to be omitted from the
57 patch.
58 * Added the [/help?cmd=patch|patch alias] command for managing aliases
59 for remote checkout names.
60
61 <h2 id='v2_25'>Changes for version 2.25 (2024-11-06)</h2>
62
63 * The "[/help?cmd=ui|fossil ui /]" command now works even for repositories
64 that have non-ASCII filenames
65
--- www/changes.wiki
+++ www/changes.wiki
@@ -53,10 +53,12 @@
5353
and debugging
5454
* Fix a bug in [/help?cmd=patch|fossil patch create] that causes
5555
[/help?cmd=revert|fossil revert] operations that happened on individual
5656
files after a [/help?cmd=merge|fossil merge] to be omitted from the
5757
patch.
58
+ * Added the [/help?cmd=patch|patch alias] command for managing aliases
59
+ for remote checkout names.
5860
5961
<h2 id='v2_25'>Changes for version 2.25 (2024-11-06)</h2>
6062
6163
* The "[/help?cmd=ui|fossil ui /]" command now works even for repositories
6264
that have non-ASCII filenames
6365
--- www/changes.wiki
+++ www/changes.wiki
@@ -53,10 +53,12 @@
53 and debugging
54 * Fix a bug in [/help?cmd=patch|fossil patch create] that causes
55 [/help?cmd=revert|fossil revert] operations that happened on individual
56 files after a [/help?cmd=merge|fossil merge] to be omitted from the
57 patch.
 
 
58
59 <h2 id='v2_25'>Changes for version 2.25 (2024-11-06)</h2>
60
61 * The "[/help?cmd=ui|fossil ui /]" command now works even for repositories
62 that have non-ASCII filenames
63
--- www/changes.wiki
+++ www/changes.wiki
@@ -53,10 +53,12 @@
53 and debugging
54 * Fix a bug in [/help?cmd=patch|fossil patch create] that causes
55 [/help?cmd=revert|fossil revert] operations that happened on individual
56 files after a [/help?cmd=merge|fossil merge] to be omitted from the
57 patch.
58 * Added the [/help?cmd=patch|patch alias] command for managing aliases
59 for remote checkout names.
60
61 <h2 id='v2_25'>Changes for version 2.25 (2024-11-06)</h2>
62
63 * The "[/help?cmd=ui|fossil ui /]" command now works even for repositories
64 that have non-ASCII filenames
65

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button