Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Fix the "fossil patch push" and "fossil patch pull" commands so that, like "fossil sync", they initial try to run ssh without the PATH= argument, but add in the PATH= argument if the initial attempt does not work. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA3-256: |
eb135ef204f467963fe293ffa14f88aa |
| User & Date: | drh 2024-02-06 23:18:34.253 |
Context
|
2024-02-06
| ||
| 23:45 | Detailed header comment on the ssh_add_path_argument() function explaining what this PATH= business is all about, for future reference. ... (check-in: ac52d12e66 user: drh tags: trunk) | |
| 23:18 | Fix the "fossil patch push" and "fossil patch pull" commands so that, like "fossil sync", they initial try to run ssh without the PATH= argument, but add in the PATH= argument if the initial attempt does not work. ... (check-in: eb135ef204 user: drh tags: trunk) | |
| 15:32 | Merge commonly used operations associated with the PATH= of a remote fossil run using ssh into subroutines, so that they do not get out of sync with each other. ... (check-in: efd3a5ec07 user: drh tags: trunk) | |
Changes
Changes to src/http.c.
| ︙ | ︙ | |||
273 274 275 276 277 278 279 280 281 282 283 284 285 |
}
/* If iTruth<0 then guess as to whether or not a PATH= argument is required
** when using ssh to run fossil on a remote machine name zHostname.
**
** If iTruth is 1 or 0 then that means that the PATH= is or is not required,
** respectively. Record this fact for future reference.
*/
int ssh_needs_path_argument(const char *zHostname, int iTruth){
int ans = 0; /* Default to "no" */
char *z = mprintf("use-path-for-ssh:%s", zHostname);
if( iTruth<0 ){
if( db_get_boolean(z/*works-like:"x"*/, 0) ) ans = 1;
| > > > > > > | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 |
}
/* If iTruth<0 then guess as to whether or not a PATH= argument is required
** when using ssh to run fossil on a remote machine name zHostname.
**
** If iTruth is 1 or 0 then that means that the PATH= is or is not required,
** respectively. Record this fact for future reference.
**
** If iTruth is 99 or more, then toggle the truth value.
*/
int ssh_needs_path_argument(const char *zHostname, int iTruth){
int ans = 0; /* Default to "no" */
char *z = mprintf("use-path-for-ssh:%s", zHostname);
if( iTruth<0 ){
if( db_get_boolean(z/*works-like:"x"*/, 0) ) ans = 1;
}else{
if( iTruth>=99 ){
iTruth = !db_get_boolean(z/*works-like:"x"*/, 0);
}
if( iTruth ){
ans = 1;
db_set(z/*works-like:"x"*/, "1", 0);
}else{
db_unset(z/*works-like:"x"*/, 0);
}
}
fossil_free(z);
return ans;
}
/*
** COMMAND: test-ssh-needs-path
**
** Usage: fossil test-ssh-needs-path HOSTNAME ?BOOLEAN?
**
** With one argument, show whether or not the PATH= argument is included
** by default for HOSTNAME. If the second argument is a boolean, then
** change the value.
**
** With no arguments, show all hosts for which ssh-needs-path is true.
*/
void test_ssh_needs_path(void){
db_find_and_open_repository(0,0);
if( g.argc>=3 ){
const char *zHost = g.argv[2];
int a = -1;
int rc;
if( g.argc>=4 ) a = is_truth(g.argv[3]);
rc = ssh_needs_path_argument(zHost, a);
fossil_print("%-20s %s\n", zHost, rc ? "yes" : "no");
}else{
Stmt s;
db_prepare(&s, "SELECT substr(name,18) FROM config"
" WHERE name GLOB 'use-path-for-ssh:*'");
while( db_step(&s)==SQLITE_ROW ){
const char *zHost = db_column_text(&s,0);
fossil_print("%-20s yes\n", zHost);
}
db_finalize(&s);
}
}
/* Add an approprate PATH= argument to the SSH command under construction
** in pCmd.
*/
void ssh_add_path_argument(Blob *pCmd){
blob_append_escaped_arg(pCmd,
"PATH=$HOME/bin:/usr/local/bin:/opt/homebrew/bin:$PATH", 1);
|
| ︙ | ︙ |
Changes to src/patch.c.
| ︙ | ︙ | |||
43 44 45 46 47 48 49 50 51 52 53 54 55 56 | /* ** Flags passed from the main patch_cmd() routine into subfunctions used ** to implement the various subcommands. */ #define PATCH_DRYRUN 0x0001 #define PATCH_VERBOSE 0x0002 #define PATCH_FORCE 0x0004 /* ** Implementation of the "readfile(X)" SQL function. The entire content ** of the check-out file named X is read and returned as a BLOB. */ static void readfileFunc( sqlite3_context *context, | > | 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | /* ** Flags passed from the main patch_cmd() routine into subfunctions used ** to implement the various subcommands. */ #define PATCH_DRYRUN 0x0001 #define PATCH_VERBOSE 0x0002 #define PATCH_FORCE 0x0004 #define PATCH_RETRY 0x0008 /* Second attempt */ /* ** Implementation of the "readfile(X)" SQL function. The entire content ** of the check-out file named X is read and returned as a BLOB. */ static void readfileFunc( sqlite3_context *context, |
| ︙ | ︙ | |||
130 131 132 133 134 135 136 |
SQLITE_TRANSIENT);
blob_reset(&x);
}
/*
** Generate a binary patch file and store it into the file
| | > > | 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
SQLITE_TRANSIENT);
blob_reset(&x);
}
/*
** Generate a binary patch file and store it into the file
** named zOut. Or if zOut is NULL, write it into out.
**
** Return the number of errors.
*/
void patch_create(unsigned mFlags, const char *zOut, FILE *out){
int vid;
char *z;
if( zOut && file_isdir(zOut, ExtFILE)!=0 ){
if( mFlags & PATCH_FORCE ){
|
| ︙ | ︙ | |||
246 247 248 249 250 251 252 |
if( pData==0 ){
fossil_fatal("out of memory");
}
#ifdef _WIN32
fflush(out);
_setmode(_fileno(out), _O_BINARY);
#endif
| | < > > | > > > > > | 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 |
if( pData==0 ){
fossil_fatal("out of memory");
}
#ifdef _WIN32
fflush(out);
_setmode(_fileno(out), _O_BINARY);
#endif
fwrite(pData, 1, sz, out);
fflush(out);
sqlite3_free(pData);
}
db_multi_exec("DETACH patch;");
}
/*
** Attempt to load and validate a patchfile identified by the first
** argument.
*/
void patch_attach(const char *zIn, FILE *in, int bIgnoreEmptyPatch){
Stmt q;
if( g.db==0 ){
sqlite3_open(":memory:", &g.db);
}
if( zIn==0 ){
Blob buf;
int rc;
int sz;
unsigned char *pData;
blob_init(&buf, 0, 0);
#ifdef _WIN32
_setmode(_fileno(in), _O_BINARY);
#endif
sz = blob_read_from_channel(&buf, in, -1);
pData = (unsigned char*)blob_buffer(&buf);
if( sz<512 ){
blob_reset(&buf);
if( bIgnoreEmptyPatch ) return;
fossil_fatal("input is too small to be a patch file");
}
db_multi_exec("ATTACH ':memory:' AS patch");
if( g.fSqlTrace ){
fossil_trace("-- deserialize(\"patch\", pData, %lld);\n", sz);
}
rc = sqlite3_deserialize(g.db, "patch", pData, sz, sz, 0);
if( rc ){
fossil_fatal("cannot open patch database: %s", sqlite3_errmsg(g.db));
|
| ︙ | ︙ | |||
662 663 664 665 666 667 668 |
static FILE *patch_remote_command(
unsigned mFlags, /* flags */
const char *zThisCmd, /* "push" or "pull" */
const char *zRemoteCmd, /* "apply" or "create" */
const char *zFossilCmd, /* Name of "fossil" on remote system */
const char *zRW /* "w" or "r" */
){
| | | | | > > > < > | > > > > > > > > > > > > > > > > > > > > > > > | 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 |
static FILE *patch_remote_command(
unsigned mFlags, /* flags */
const char *zThisCmd, /* "push" or "pull" */
const char *zRemoteCmd, /* "apply" or "create" */
const char *zFossilCmd, /* Name of "fossil" on remote system */
const char *zRW /* "w" or "r" */
){
char *zRemote = 0;
char *zDir = 0;
Blob cmd;
FILE *f = 0;
Blob flgs;
char *zForce = 0;
int isRetry = (mFlags & PATCH_RETRY)!=0;
blob_init(&flgs, 0, 0);
blob_init(&cmd, 0, 0);
if( mFlags & PATCH_FORCE ) blob_appendf(&flgs, " -f");
if( mFlags & PATCH_VERBOSE ) blob_appendf(&flgs, " -v");
if( mFlags & PATCH_DRYRUN ) blob_appendf(&flgs, " -n");
zForce = blob_size(&flgs)>0 ? blob_str(&flgs) : "";
if( g.argc!=4 ){
usage(mprintf("%s [USER@]HOST:DIRECTORY", zThisCmd));
}
zRemote = fossil_strdup(g.argv[3]);
zDir = (char*)file_skip_userhost(zRemote);
if( zDir==0 ){
if( isRetry ) goto remote_command_error;
zDir = zRemote;
blob_append_escaped_arg(&cmd, g.nameOfExe, 1);
blob_appendf(&cmd, " patch %s%s %$ -", zRemoteCmd, zForce, zDir);
}else{
Blob remote;
*(char*)(zDir-1) = 0;
transport_ssh_command(&cmd);
blob_appendf(&cmd, " -T");
blob_append_escaped_arg(&cmd, zRemote, 0);
blob_init(&remote, 0, 0);
if( zFossilCmd==0 ){
if( ssh_needs_path_argument(zRemote,-1) ^ isRetry ){
ssh_add_path_argument(&cmd);
}
zFossilCmd = "fossil";
}else if( mFlags & PATCH_RETRY ){
goto remote_command_error;
}
blob_appendf(&remote, "%$ patch %s%s --dir64 %z -",
zFossilCmd, zRemoteCmd, zForce, encode64(zDir, -1));
blob_append_escaped_arg(&cmd, blob_str(&remote), 0);
blob_reset(&remote);
}
if( isRetry ){
fossil_print("First attempt to run \"fossil\" on %s failed\n"
"Retry: ", zRemote);
}
fossil_print("%s\n", blob_str(&cmd));
fflush(stdout);
f = popen(blob_str(&cmd), zRW);
if( f==0 ){
fossil_fatal("cannot run command: %s", blob_str(&cmd));
}
remote_command_error:
fossil_free(zRemote);
blob_reset(&cmd);
blob_reset(&flgs);
return f;
}
/*
** Toggle the use-path-for-ssh setting for the remote host defined
** by g.argv[3].
*/
static void patch_toggle_ssh_needs_path(void){
char *zRemote = fossil_strdup(g.argv[3]);
char *zDir = (char*)file_skip_userhost(zRemote);
if( zDir ){
*(char*)(zDir - 1) = 0;
ssh_needs_path_argument(zRemote, 99);
}
fossil_free(zRemote);
}
/*
** Show a diff for the patch currently loaded into database "patch".
*/
static void patch_diff(
unsigned mFlags, /* Patch flags. only -f is allowed */
DiffConfig *pCfg /* Diff options */
|
| ︙ | ︙ | |||
932 933 934 935 936 937 938 |
char *zIn;
unsigned flags = 0;
if( find_option("dry-run","n",0) ) flags |= PATCH_DRYRUN;
if( find_option("verbose","v",0) ) flags |= PATCH_VERBOSE;
if( find_option("force","f",0) ) flags |= PATCH_FORCE;
zIn = patch_find_patch_filename("apply");
db_must_be_within_tree();
| | | 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 |
char *zIn;
unsigned flags = 0;
if( find_option("dry-run","n",0) ) flags |= PATCH_DRYRUN;
if( find_option("verbose","v",0) ) flags |= PATCH_VERBOSE;
if( find_option("force","f",0) ) flags |= PATCH_FORCE;
zIn = patch_find_patch_filename("apply");
db_must_be_within_tree();
patch_attach(zIn, stdin, 0);
patch_apply(flags);
fossil_free(zIn);
}else
if( strncmp(zCmd, "create", n)==0 ){
char *zOut;
unsigned flags = 0;
if( find_option("force","f",0) ) flags |= PATCH_FORCE;
|
| ︙ | ︙ | |||
961 962 963 964 965 966 967 |
return;
}
db_find_and_open_repository(0, 0);
if( find_option("force","f",0) ) flags |= PATCH_FORCE;
diff_options(&DCfg, zCmd[0]=='g', 0);
verify_all_options();
zIn = patch_find_patch_filename("apply");
| | | | > > > > > > > > > > | > > > > > > > > > | | 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 |
return;
}
db_find_and_open_repository(0, 0);
if( find_option("force","f",0) ) flags |= PATCH_FORCE;
diff_options(&DCfg, zCmd[0]=='g', 0);
verify_all_options();
zIn = patch_find_patch_filename("apply");
patch_attach(zIn, stdin, 0);
patch_diff(flags, &DCfg);
fossil_free(zIn);
}else
if( strncmp(zCmd, "pull", n)==0 ){
FILE *pIn = 0;
unsigned flags = 0;
const char *zFossilCmd = find_option("fossilcmd",0,1);
if( find_option("dry-run","n",0) ) flags |= PATCH_DRYRUN;
if( find_option("verbose","v",0) ) flags |= PATCH_VERBOSE;
if( find_option("force","f",0) ) flags |= PATCH_FORCE;
db_must_be_within_tree();
verify_all_options();
pIn = patch_remote_command(flags & (~PATCH_FORCE),
"pull", "create", zFossilCmd, "r");
if( pIn ){
patch_attach(0, pIn, 1);
if( pclose(pIn) ){
flags |= PATCH_RETRY;
pIn = patch_remote_command(flags & (~PATCH_FORCE),
"pull", "create", zFossilCmd, "r");
if( pIn ){
patch_attach(0, pIn, 0);
if( pclose(pIn)==0 ){
patch_toggle_ssh_needs_path();
}
}
}
patch_apply(flags);
}
}else
if( strncmp(zCmd, "push", n)==0 ){
FILE *pOut = 0;
unsigned flags = 0;
const char *zFossilCmd = find_option("fossilcmd",0,1);
if( find_option("dry-run","n",0) ) flags |= PATCH_DRYRUN;
if( find_option("verbose","v",0) ) flags |= PATCH_VERBOSE;
if( find_option("force","f",0) ) flags |= PATCH_FORCE;
db_must_be_within_tree();
verify_all_options();
pOut = patch_remote_command(flags, "push", "apply", zFossilCmd, "w");
if( pOut ){
patch_create(0, 0, pOut);
if( pclose(pOut)!=0 ){
flags |= PATCH_RETRY;
pOut = patch_remote_command(flags, "push", "apply", zFossilCmd, "w");
if( pOut ){
patch_create(0, 0, pOut);
if( pclose(pOut)==0 ){
patch_toggle_ssh_needs_path();
}
}
}
}
}else
if( strncmp(zCmd, "view", n)==0 ){
const char *zIn;
unsigned int flags = 0;
if( find_option("verbose","v",0) ) flags |= PATCH_VERBOSE;
verify_all_options();
if( g.argc!=4 ){
usage("view FILENAME");
}
zIn = g.argv[3];
if( fossil_strcmp(zIn, "-")==0 ) zIn = 0;
patch_attach(zIn, stdin, 0);
patch_view(flags);
}else
{
goto patch_usage;
}
}
|