Fossil SCM

Add the ability to remember multiple remote repositories. Enhance the "fossil remote" command to configure and control the list.

drh 2020-07-15 18:02 trunk
Commit f11c863d91c251d01461baed0804a7f32ef693900a07598eb8a1e74c6e4644e1
3 files changed +3 -1 +146 -36 +27 -4
+3 -1
--- src/rebuild.c
+++ src/rebuild.c
@@ -758,11 +758,12 @@
758758
*/
759759
void test_detach_cmd(void){
760760
db_find_and_open_repository(0, 2);
761761
db_begin_transaction();
762762
db_multi_exec(
763
- "DELETE FROM config WHERE name='last-sync-url';"
763
+ "DELETE FROM config WHERE name GLOB 'last-sync-*';"
764
+ "DELETE FROM config WHERE name GLOB 'sync-*:*';"
764765
"UPDATE config SET value=lower(hex(randomblob(20)))"
765766
" WHERE name='project-code';"
766767
"UPDATE config SET value='detached-' || value"
767768
" WHERE name='project-name' AND value NOT GLOB 'detached-*';"
768769
);
@@ -914,10 +915,11 @@
914915
}
915916
if( !privateOnly ){
916917
db_multi_exec(
917918
"UPDATE user SET pw='';"
918919
"DELETE FROM config WHERE name GLOB 'last-sync-*';"
920
+ "DELETE FROM config WHERE name GLOB 'sync-*:*';"
919921
"DELETE FROM config WHERE name GLOB 'peer-*';"
920922
"DELETE FROM config WHERE name GLOB 'login-group-*';"
921923
"DELETE FROM config WHERE name GLOB 'skin:*';"
922924
"DELETE FROM config WHERE name GLOB 'subrepo:*';"
923925
"DELETE FROM config WHERE name GLOB 'http-auth:*';"
924926
--- src/rebuild.c
+++ src/rebuild.c
@@ -758,11 +758,12 @@
758 */
759 void test_detach_cmd(void){
760 db_find_and_open_repository(0, 2);
761 db_begin_transaction();
762 db_multi_exec(
763 "DELETE FROM config WHERE name='last-sync-url';"
 
764 "UPDATE config SET value=lower(hex(randomblob(20)))"
765 " WHERE name='project-code';"
766 "UPDATE config SET value='detached-' || value"
767 " WHERE name='project-name' AND value NOT GLOB 'detached-*';"
768 );
@@ -914,10 +915,11 @@
914 }
915 if( !privateOnly ){
916 db_multi_exec(
917 "UPDATE user SET pw='';"
918 "DELETE FROM config WHERE name GLOB 'last-sync-*';"
 
919 "DELETE FROM config WHERE name GLOB 'peer-*';"
920 "DELETE FROM config WHERE name GLOB 'login-group-*';"
921 "DELETE FROM config WHERE name GLOB 'skin:*';"
922 "DELETE FROM config WHERE name GLOB 'subrepo:*';"
923 "DELETE FROM config WHERE name GLOB 'http-auth:*';"
924
--- src/rebuild.c
+++ src/rebuild.c
@@ -758,11 +758,12 @@
758 */
759 void test_detach_cmd(void){
760 db_find_and_open_repository(0, 2);
761 db_begin_transaction();
762 db_multi_exec(
763 "DELETE FROM config WHERE name GLOB 'last-sync-*';"
764 "DELETE FROM config WHERE name GLOB 'sync-*:*';"
765 "UPDATE config SET value=lower(hex(randomblob(20)))"
766 " WHERE name='project-code';"
767 "UPDATE config SET value='detached-' || value"
768 " WHERE name='project-name' AND value NOT GLOB 'detached-*';"
769 );
@@ -914,10 +915,11 @@
915 }
916 if( !privateOnly ){
917 db_multi_exec(
918 "UPDATE user SET pw='';"
919 "DELETE FROM config WHERE name GLOB 'last-sync-*';"
920 "DELETE FROM config WHERE name GLOB 'sync-*:*';"
921 "DELETE FROM config WHERE name GLOB 'peer-*';"
922 "DELETE FROM config WHERE name GLOB 'login-group-*';"
923 "DELETE FROM config WHERE name GLOB 'skin:*';"
924 "DELETE FROM config WHERE name GLOB 'subrepo:*';"
925 "DELETE FROM config WHERE name GLOB 'http-auth:*';"
926
+146 -36
--- src/sync.c
+++ src/sync.c
@@ -172,11 +172,11 @@
172172
if( g.url.protocol==0 ){
173173
if( urlOptional ) fossil_exit(0);
174174
usage("URL");
175175
}
176176
user_select();
177
- if( g.argc==2 ){
177
+ if( g.url.isAlias ){
178178
if( ((*pSyncFlags) & (SYNC_PUSH|SYNC_PULL))==(SYNC_PUSH|SYNC_PULL) ){
179179
fossil_print("Sync with %s\n", g.url.canonical);
180180
}else if( (*pSyncFlags) & SYNC_PUSH ){
181181
fossil_print("Push to %s\n", g.url.canonical);
182182
}else if( (*pSyncFlags) & SYNC_PULL ){
@@ -197,11 +197,11 @@
197197
** wiki pages, tickets, and tech-notes, as well as forum content. Add
198198
** the --private option to pull private branches. Use the
199199
** "configuration pull" command to pull website configuration details.
200200
**
201201
** If URL is not specified, then the URL from the most recent clone, push,
202
-** pull, remote-url, or sync command is used. See "fossil help clone" for
202
+** pull, remote, or sync command is used. See "fossil help clone" for
203203
** details on the URL formats.
204204
**
205205
** Options:
206206
**
207207
** -B|--httpauth USER:PASS Credentials for the simple HTTP auth protocol,
@@ -217,11 +217,11 @@
217217
** --ssh-command SSH Use SSH as the "ssh" command
218218
** -v|--verbose Additional (debugging) output
219219
** --verily Exchange extra information with the remote
220220
** to ensure no content is overlooked
221221
**
222
-** See also: clone, config pull, push, remote-url, sync
222
+** See also: clone, config pull, push, remote, sync
223223
*/
224224
void pull_cmd(void){
225225
unsigned configFlags = 0;
226226
unsigned syncFlags = SYNC_PULL;
227227
unsigned urlOmitFlags = 0;
@@ -248,11 +248,11 @@
248248
** wiki pages, tickets, and tech-notes, as well as forum content. Use
249249
** --private to also push private branches. Use the "configuration
250250
** push" command to push website configuration details.
251251
**
252252
** If URL is not specified, then the URL from the most recent clone, push,
253
-** pull, remote-url, or sync command is used. See "fossil help clone" for
253
+** pull, remote, or sync command is used. See "fossil help clone" for
254254
** details on the URL formats.
255255
**
256256
** Options:
257257
**
258258
** -B|--httpauth USER:PASS Credentials for the simple HTTP auth protocol,
@@ -266,11 +266,11 @@
266266
** --ssh-command SSH Use SSH as the "ssh" command
267267
** -v|--verbose Additional (debugging) output
268268
** --verily Exchange extra information with the remote
269269
** to ensure no content is overlooked
270270
**
271
-** See also: clone, config push, pull, remote-url, sync
271
+** See also: clone, config push, pull, remote, sync
272272
*/
273273
void push_cmd(void){
274274
unsigned configFlags = 0;
275275
unsigned syncFlags = SYNC_PUSH;
276276
process_sync_args(&configFlags, &syncFlags, 0, 0);
@@ -293,11 +293,11 @@
293293
** Synchronize all sharable changes between the local repository and a
294294
** remote repository. Sharable changes include public check-ins and
295295
** edits to wiki pages, tickets, and technical notes.
296296
**
297297
** If URL is not specified, then the URL from the most recent clone, push,
298
-** pull, remote-url, or sync command is used. See "fossil help clone" for
298
+** pull, remote, or sync command is used. See "fossil help clone" for
299299
** details on the URL formats.
300300
**
301301
** Options:
302302
**
303303
** -B|--httpauth USER:PASS Credentials for the simple HTTP auth protocol,
@@ -312,11 +312,11 @@
312312
** -u|--unversioned Also sync unversioned content
313313
** -v|--verbose Additional (debugging) output
314314
** --verily Exchange extra information with the remote
315315
** to ensure no content is overlooked
316316
**
317
-** See also: clone, pull, push, remote-url
317
+** See also: clone, pull, push, remote
318318
*/
319319
void sync_cmd(void){
320320
unsigned configFlags = 0;
321321
unsigned syncFlags = SYNC_PUSH|SYNC_PULL;
322322
if( find_option("unversioned","u",0)!=0 ){
@@ -347,49 +347,159 @@
347347
}
348348
349349
/*
350350
** COMMAND: remote-url
351351
**
352
-** Usage: %fossil remote-url ?URL|off?
353
-**
354
-** Query and/or change the default server URL used by the "pull", "push",
355
-** and "sync" commands.
356
-**
357
-** The remote-url is set automatically by a "clone" command or by any
358
-** "sync", "push", or "pull" command that specifies an explicit URL.
359
-** The default remote-url is used by auto-syncing and by "sync", "push",
360
-** "pull" that omit the server URL.
361
-**
362
-** See "fossil help clone" for further information about URL formats
363
-**
364
-** See also: clone, push, pull, sync
352
+** Usage: %fossil remote ?SUBCOMMAND ...?
353
+**
354
+** Use this command to view or modify that set of remote repositories
355
+** used for sync, push, and pull.
356
+**
357
+** The default remote is set automatically by a "clone" command or by any
358
+** "sync", "push", or "pull" command that specifies an explicit URL
359
+** and omits the --once flag. The default remote is used by
360
+** auto-syncing and by "sync", "push", and "pull" that omit the server URL.
361
+** Additional remotes can be added using the "add" command or deleted
362
+** using the "delete" command. The name of additional remotes can be
363
+** used as an argument to the "sync", "push", and "pull" commands where
364
+** one would normally put a URL argument.
365
+**
366
+** See "fossil help clone" for further information about URL formats.
367
+**
368
+** The official name of this command is "remote-url" but most people
369
+** use the shortened name "remote".
370
+**
371
+** Subcommands:
372
+**
373
+** > %fossil remote
374
+**
375
+** With no arguments, this command show the current default remote.
376
+** Or if there is no default, it shows "off". The default remote is
377
+** used by autosync. The default remote is whatever URL was specified
378
+** for the most recent "sync", "push", or "pull" command that omitted
379
+** the --once option.
380
+**
381
+** > %fossil remote add NAME URL
382
+**
383
+** Add a new URL to the set of remotes. The new URL is assigned the
384
+** symbolic identifier "NAME". Subsequently, NAME can be used in place
385
+** of the full URL on commands like "push" and "pull".
386
+**
387
+** > %fossil remote delete NAME
388
+**
389
+** Delete a URL previously added by the "add" subcommand.
390
+**
391
+** > %fossil remote list
392
+**
393
+** Show all remote URLs
394
+**
395
+** > %fossil remote off
396
+**
397
+** Disable the default URL. Use this as a shorthand to prevent
398
+** autosync while in airplane mode, for example.
399
+**
400
+** > %fossil remote URL
401
+**
402
+** Make URL the new default URL. The prior default URL is replaced.
365403
*/
366404
void remote_url_cmd(void){
367
- char *zUrl;
405
+ char *zUrl, *zArg;
406
+ int nArg;
368407
db_find_and_open_repository(0, 0);
369408
370409
/* We should be done with options.. */
371410
verify_all_options();
372411
373
- if( g.argc!=2 && g.argc!=3 ){
374
- usage("?URL|off?");
412
+ if( g.argc==2 ){
413
+ /* "fossil remote" with no arguments: Show the last sync URL. */
414
+ zUrl = db_get("last-sync-url", 0);
415
+ if( zUrl==0 ){
416
+ fossil_print("off\n");
417
+ }else{
418
+ url_parse(zUrl, 0);
419
+ fossil_print("%s\n", g.url.canonical);
420
+ }
421
+ return;
422
+ }
423
+ zArg = g.argv[2];
424
+ nArg = (int)strlen(zArg);
425
+ if( strcmp(zArg,"off")==0 ){
426
+ /* fossil remote off
427
+ ** Forget the last-sync-URL and its password
428
+ */
429
+ if( g.argc!=3 ) usage("off");
430
+remote_delete_default:
431
+ db_multi_exec(
432
+ "DELETE FROM config WHERE name GLOB 'last-sync-*';"
433
+ );
434
+ return;
435
+ }
436
+ if( strncmp(zArg, "list", nArg)==0 || strcmp(zArg,"ls")==0 ){
437
+ Stmt q;
438
+ if( g.argc!=3 ) usage("list");
439
+ db_prepare(&q,
440
+ "SELECT 'default', value FROM config WHERE name='last-sync-url'"
441
+ " UNION ALL "
442
+ "SELECT substr(name,10), value FROM config"
443
+ " WHERE name GLOB 'sync-url:*'"
444
+ " ORDER BY 1"
445
+ );
446
+ while( db_step(&q)==SQLITE_ROW ){
447
+ fossil_print("%-18s %s\n", db_column_text(&q,0), db_column_text(&q,1));
448
+ }
449
+ db_finalize(&q);
450
+ return;
451
+ }
452
+ if( strcmp(zArg, "add")==0 ){
453
+ char *zName;
454
+ char *zUrl;
455
+ UrlData x;
456
+ if( g.argc!=5 ) usage("add NAME URL");
457
+ memset(&x, 0, sizeof(x));
458
+ zName = g.argv[3];
459
+ zUrl = g.argv[4];
460
+ if( strcmp(zName,"default")==0 ) goto remote_add_default;
461
+ url_parse_local(zUrl, URL_PROMPT_PW, &x);
462
+ db_begin_write();
463
+ db_multi_exec(
464
+ "REPLACE INTO config(name, value, mtime)"
465
+ " VALUES('sync-url:%q',%Q,now())",
466
+ zName, x.canonical
467
+ );
468
+ db_multi_exec(
469
+ "REPLACE INTO config(name, value, mtime)"
470
+ " VALUES('sync-pw:%q',obscure(%Q),now())",
471
+ zName, x.passwd
472
+ );
473
+ db_commit_transaction();
474
+ return;
475
+ }
476
+ if( strncmp(zArg, "delete", nArg)==0 ){
477
+ char *zName;
478
+ if( g.argc!=4 ) usage("delete NAME");
479
+ zName = g.argv[3];
480
+ db_begin_write();
481
+ db_multi_exec("DELETE FROM config WHERE name glob 'sync-url:%q'", zName);
482
+ db_multi_exec("DELETE FROM config WHERE name glob 'sync-pw:%q'", zName);
483
+ db_commit_transaction();
484
+ return;
375485
}
376
- if( g.argc==3 ){
486
+ if( sqlite3_strlike("http://%",zArg,0)==0
487
+ || sqlite3_strlike("https://%",zArg,0)==0
488
+ || sqlite3_strlike("ssh:%",zArg,0)==0
489
+ || sqlite3_strlike("file:%",zArg,0)==0
490
+ || db_exists("SELECT 1 FROM config WHERE name='sync-url:%q'",zArg)
491
+ ){
492
+remote_add_default:
377493
db_unset("last-sync-url", 0);
378494
db_unset("last-sync-pw", 0);
379
- if( is_false(g.argv[2]) ) return;
380
- url_parse(g.argv[2], URL_REMEMBER|URL_PROMPT_PW|URL_ASK_REMEMBER_PW);
381
- }
382
- url_remember();
383
- zUrl = db_get("last-sync-url", 0);
384
- if( zUrl==0 ){
385
- fossil_print("off\n");
386
- return;
387
- }else{
388
- url_parse(zUrl, 0);
389
- fossil_print("%s\n", g.url.canonical);
390
- }
495
+ url_parse(g.argv[2], URL_REMEMBER|URL_PROMPT_PW|URL_ASK_REMEMBER_PW);
496
+ url_remember();
497
+ return;
498
+ }
499
+ fossil_fatal("unknown command \"%s\" - should be a URL or one of: "
500
+ "add delete list off", zArg);
391501
}
392502
393503
/*
394504
** COMMAND: backup*
395505
**
396506
--- src/sync.c
+++ src/sync.c
@@ -172,11 +172,11 @@
172 if( g.url.protocol==0 ){
173 if( urlOptional ) fossil_exit(0);
174 usage("URL");
175 }
176 user_select();
177 if( g.argc==2 ){
178 if( ((*pSyncFlags) & (SYNC_PUSH|SYNC_PULL))==(SYNC_PUSH|SYNC_PULL) ){
179 fossil_print("Sync with %s\n", g.url.canonical);
180 }else if( (*pSyncFlags) & SYNC_PUSH ){
181 fossil_print("Push to %s\n", g.url.canonical);
182 }else if( (*pSyncFlags) & SYNC_PULL ){
@@ -197,11 +197,11 @@
197 ** wiki pages, tickets, and tech-notes, as well as forum content. Add
198 ** the --private option to pull private branches. Use the
199 ** "configuration pull" command to pull website configuration details.
200 **
201 ** If URL is not specified, then the URL from the most recent clone, push,
202 ** pull, remote-url, or sync command is used. See "fossil help clone" for
203 ** details on the URL formats.
204 **
205 ** Options:
206 **
207 ** -B|--httpauth USER:PASS Credentials for the simple HTTP auth protocol,
@@ -217,11 +217,11 @@
217 ** --ssh-command SSH Use SSH as the "ssh" command
218 ** -v|--verbose Additional (debugging) output
219 ** --verily Exchange extra information with the remote
220 ** to ensure no content is overlooked
221 **
222 ** See also: clone, config pull, push, remote-url, sync
223 */
224 void pull_cmd(void){
225 unsigned configFlags = 0;
226 unsigned syncFlags = SYNC_PULL;
227 unsigned urlOmitFlags = 0;
@@ -248,11 +248,11 @@
248 ** wiki pages, tickets, and tech-notes, as well as forum content. Use
249 ** --private to also push private branches. Use the "configuration
250 ** push" command to push website configuration details.
251 **
252 ** If URL is not specified, then the URL from the most recent clone, push,
253 ** pull, remote-url, or sync command is used. See "fossil help clone" for
254 ** details on the URL formats.
255 **
256 ** Options:
257 **
258 ** -B|--httpauth USER:PASS Credentials for the simple HTTP auth protocol,
@@ -266,11 +266,11 @@
266 ** --ssh-command SSH Use SSH as the "ssh" command
267 ** -v|--verbose Additional (debugging) output
268 ** --verily Exchange extra information with the remote
269 ** to ensure no content is overlooked
270 **
271 ** See also: clone, config push, pull, remote-url, sync
272 */
273 void push_cmd(void){
274 unsigned configFlags = 0;
275 unsigned syncFlags = SYNC_PUSH;
276 process_sync_args(&configFlags, &syncFlags, 0, 0);
@@ -293,11 +293,11 @@
293 ** Synchronize all sharable changes between the local repository and a
294 ** remote repository. Sharable changes include public check-ins and
295 ** edits to wiki pages, tickets, and technical notes.
296 **
297 ** If URL is not specified, then the URL from the most recent clone, push,
298 ** pull, remote-url, or sync command is used. See "fossil help clone" for
299 ** details on the URL formats.
300 **
301 ** Options:
302 **
303 ** -B|--httpauth USER:PASS Credentials for the simple HTTP auth protocol,
@@ -312,11 +312,11 @@
312 ** -u|--unversioned Also sync unversioned content
313 ** -v|--verbose Additional (debugging) output
314 ** --verily Exchange extra information with the remote
315 ** to ensure no content is overlooked
316 **
317 ** See also: clone, pull, push, remote-url
318 */
319 void sync_cmd(void){
320 unsigned configFlags = 0;
321 unsigned syncFlags = SYNC_PUSH|SYNC_PULL;
322 if( find_option("unversioned","u",0)!=0 ){
@@ -347,49 +347,159 @@
347 }
348
349 /*
350 ** COMMAND: remote-url
351 **
352 ** Usage: %fossil remote-url ?URL|off?
353 **
354 ** Query and/or change the default server URL used by the "pull", "push",
355 ** and "sync" commands.
356 **
357 ** The remote-url is set automatically by a "clone" command or by any
358 ** "sync", "push", or "pull" command that specifies an explicit URL.
359 ** The default remote-url is used by auto-syncing and by "sync", "push",
360 ** "pull" that omit the server URL.
361 **
362 ** See "fossil help clone" for further information about URL formats
363 **
364 ** See also: clone, push, pull, sync
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
365 */
366 void remote_url_cmd(void){
367 char *zUrl;
 
368 db_find_and_open_repository(0, 0);
369
370 /* We should be done with options.. */
371 verify_all_options();
372
373 if( g.argc!=2 && g.argc!=3 ){
374 usage("?URL|off?");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
375 }
376 if( g.argc==3 ){
 
 
 
 
 
 
377 db_unset("last-sync-url", 0);
378 db_unset("last-sync-pw", 0);
379 if( is_false(g.argv[2]) ) return;
380 url_parse(g.argv[2], URL_REMEMBER|URL_PROMPT_PW|URL_ASK_REMEMBER_PW);
381 }
382 url_remember();
383 zUrl = db_get("last-sync-url", 0);
384 if( zUrl==0 ){
385 fossil_print("off\n");
386 return;
387 }else{
388 url_parse(zUrl, 0);
389 fossil_print("%s\n", g.url.canonical);
390 }
391 }
392
393 /*
394 ** COMMAND: backup*
395 **
396
--- src/sync.c
+++ src/sync.c
@@ -172,11 +172,11 @@
172 if( g.url.protocol==0 ){
173 if( urlOptional ) fossil_exit(0);
174 usage("URL");
175 }
176 user_select();
177 if( g.url.isAlias ){
178 if( ((*pSyncFlags) & (SYNC_PUSH|SYNC_PULL))==(SYNC_PUSH|SYNC_PULL) ){
179 fossil_print("Sync with %s\n", g.url.canonical);
180 }else if( (*pSyncFlags) & SYNC_PUSH ){
181 fossil_print("Push to %s\n", g.url.canonical);
182 }else if( (*pSyncFlags) & SYNC_PULL ){
@@ -197,11 +197,11 @@
197 ** wiki pages, tickets, and tech-notes, as well as forum content. Add
198 ** the --private option to pull private branches. Use the
199 ** "configuration pull" command to pull website configuration details.
200 **
201 ** If URL is not specified, then the URL from the most recent clone, push,
202 ** pull, remote, or sync command is used. See "fossil help clone" for
203 ** details on the URL formats.
204 **
205 ** Options:
206 **
207 ** -B|--httpauth USER:PASS Credentials for the simple HTTP auth protocol,
@@ -217,11 +217,11 @@
217 ** --ssh-command SSH Use SSH as the "ssh" command
218 ** -v|--verbose Additional (debugging) output
219 ** --verily Exchange extra information with the remote
220 ** to ensure no content is overlooked
221 **
222 ** See also: clone, config pull, push, remote, sync
223 */
224 void pull_cmd(void){
225 unsigned configFlags = 0;
226 unsigned syncFlags = SYNC_PULL;
227 unsigned urlOmitFlags = 0;
@@ -248,11 +248,11 @@
248 ** wiki pages, tickets, and tech-notes, as well as forum content. Use
249 ** --private to also push private branches. Use the "configuration
250 ** push" command to push website configuration details.
251 **
252 ** If URL is not specified, then the URL from the most recent clone, push,
253 ** pull, remote, or sync command is used. See "fossil help clone" for
254 ** details on the URL formats.
255 **
256 ** Options:
257 **
258 ** -B|--httpauth USER:PASS Credentials for the simple HTTP auth protocol,
@@ -266,11 +266,11 @@
266 ** --ssh-command SSH Use SSH as the "ssh" command
267 ** -v|--verbose Additional (debugging) output
268 ** --verily Exchange extra information with the remote
269 ** to ensure no content is overlooked
270 **
271 ** See also: clone, config push, pull, remote, sync
272 */
273 void push_cmd(void){
274 unsigned configFlags = 0;
275 unsigned syncFlags = SYNC_PUSH;
276 process_sync_args(&configFlags, &syncFlags, 0, 0);
@@ -293,11 +293,11 @@
293 ** Synchronize all sharable changes between the local repository and a
294 ** remote repository. Sharable changes include public check-ins and
295 ** edits to wiki pages, tickets, and technical notes.
296 **
297 ** If URL is not specified, then the URL from the most recent clone, push,
298 ** pull, remote, or sync command is used. See "fossil help clone" for
299 ** details on the URL formats.
300 **
301 ** Options:
302 **
303 ** -B|--httpauth USER:PASS Credentials for the simple HTTP auth protocol,
@@ -312,11 +312,11 @@
312 ** -u|--unversioned Also sync unversioned content
313 ** -v|--verbose Additional (debugging) output
314 ** --verily Exchange extra information with the remote
315 ** to ensure no content is overlooked
316 **
317 ** See also: clone, pull, push, remote
318 */
319 void sync_cmd(void){
320 unsigned configFlags = 0;
321 unsigned syncFlags = SYNC_PUSH|SYNC_PULL;
322 if( find_option("unversioned","u",0)!=0 ){
@@ -347,49 +347,159 @@
347 }
348
349 /*
350 ** COMMAND: remote-url
351 **
352 ** Usage: %fossil remote ?SUBCOMMAND ...?
353 **
354 ** Use this command to view or modify that set of remote repositories
355 ** used for sync, push, and pull.
356 **
357 ** The default remote is set automatically by a "clone" command or by any
358 ** "sync", "push", or "pull" command that specifies an explicit URL
359 ** and omits the --once flag. The default remote is used by
360 ** auto-syncing and by "sync", "push", and "pull" that omit the server URL.
361 ** Additional remotes can be added using the "add" command or deleted
362 ** using the "delete" command. The name of additional remotes can be
363 ** used as an argument to the "sync", "push", and "pull" commands where
364 ** one would normally put a URL argument.
365 **
366 ** See "fossil help clone" for further information about URL formats.
367 **
368 ** The official name of this command is "remote-url" but most people
369 ** use the shortened name "remote".
370 **
371 ** Subcommands:
372 **
373 ** > %fossil remote
374 **
375 ** With no arguments, this command show the current default remote.
376 ** Or if there is no default, it shows "off". The default remote is
377 ** used by autosync. The default remote is whatever URL was specified
378 ** for the most recent "sync", "push", or "pull" command that omitted
379 ** the --once option.
380 **
381 ** > %fossil remote add NAME URL
382 **
383 ** Add a new URL to the set of remotes. The new URL is assigned the
384 ** symbolic identifier "NAME". Subsequently, NAME can be used in place
385 ** of the full URL on commands like "push" and "pull".
386 **
387 ** > %fossil remote delete NAME
388 **
389 ** Delete a URL previously added by the "add" subcommand.
390 **
391 ** > %fossil remote list
392 **
393 ** Show all remote URLs
394 **
395 ** > %fossil remote off
396 **
397 ** Disable the default URL. Use this as a shorthand to prevent
398 ** autosync while in airplane mode, for example.
399 **
400 ** > %fossil remote URL
401 **
402 ** Make URL the new default URL. The prior default URL is replaced.
403 */
404 void remote_url_cmd(void){
405 char *zUrl, *zArg;
406 int nArg;
407 db_find_and_open_repository(0, 0);
408
409 /* We should be done with options.. */
410 verify_all_options();
411
412 if( g.argc==2 ){
413 /* "fossil remote" with no arguments: Show the last sync URL. */
414 zUrl = db_get("last-sync-url", 0);
415 if( zUrl==0 ){
416 fossil_print("off\n");
417 }else{
418 url_parse(zUrl, 0);
419 fossil_print("%s\n", g.url.canonical);
420 }
421 return;
422 }
423 zArg = g.argv[2];
424 nArg = (int)strlen(zArg);
425 if( strcmp(zArg,"off")==0 ){
426 /* fossil remote off
427 ** Forget the last-sync-URL and its password
428 */
429 if( g.argc!=3 ) usage("off");
430 remote_delete_default:
431 db_multi_exec(
432 "DELETE FROM config WHERE name GLOB 'last-sync-*';"
433 );
434 return;
435 }
436 if( strncmp(zArg, "list", nArg)==0 || strcmp(zArg,"ls")==0 ){
437 Stmt q;
438 if( g.argc!=3 ) usage("list");
439 db_prepare(&q,
440 "SELECT 'default', value FROM config WHERE name='last-sync-url'"
441 " UNION ALL "
442 "SELECT substr(name,10), value FROM config"
443 " WHERE name GLOB 'sync-url:*'"
444 " ORDER BY 1"
445 );
446 while( db_step(&q)==SQLITE_ROW ){
447 fossil_print("%-18s %s\n", db_column_text(&q,0), db_column_text(&q,1));
448 }
449 db_finalize(&q);
450 return;
451 }
452 if( strcmp(zArg, "add")==0 ){
453 char *zName;
454 char *zUrl;
455 UrlData x;
456 if( g.argc!=5 ) usage("add NAME URL");
457 memset(&x, 0, sizeof(x));
458 zName = g.argv[3];
459 zUrl = g.argv[4];
460 if( strcmp(zName,"default")==0 ) goto remote_add_default;
461 url_parse_local(zUrl, URL_PROMPT_PW, &x);
462 db_begin_write();
463 db_multi_exec(
464 "REPLACE INTO config(name, value, mtime)"
465 " VALUES('sync-url:%q',%Q,now())",
466 zName, x.canonical
467 );
468 db_multi_exec(
469 "REPLACE INTO config(name, value, mtime)"
470 " VALUES('sync-pw:%q',obscure(%Q),now())",
471 zName, x.passwd
472 );
473 db_commit_transaction();
474 return;
475 }
476 if( strncmp(zArg, "delete", nArg)==0 ){
477 char *zName;
478 if( g.argc!=4 ) usage("delete NAME");
479 zName = g.argv[3];
480 db_begin_write();
481 db_multi_exec("DELETE FROM config WHERE name glob 'sync-url:%q'", zName);
482 db_multi_exec("DELETE FROM config WHERE name glob 'sync-pw:%q'", zName);
483 db_commit_transaction();
484 return;
485 }
486 if( sqlite3_strlike("http://%",zArg,0)==0
487 || sqlite3_strlike("https://%",zArg,0)==0
488 || sqlite3_strlike("ssh:%",zArg,0)==0
489 || sqlite3_strlike("file:%",zArg,0)==0
490 || db_exists("SELECT 1 FROM config WHERE name='sync-url:%q'",zArg)
491 ){
492 remote_add_default:
493 db_unset("last-sync-url", 0);
494 db_unset("last-sync-pw", 0);
495 url_parse(g.argv[2], URL_REMEMBER|URL_PROMPT_PW|URL_ASK_REMEMBER_PW);
496 url_remember();
497 return;
498 }
499 fossil_fatal("unknown command \"%s\" - should be a URL or one of: "
500 "add delete list off", zArg);
 
 
 
 
 
 
501 }
502
503 /*
504 ** COMMAND: backup*
505 **
506
+27 -4
--- src/url.c
+++ src/url.c
@@ -47,10 +47,11 @@
4747
*/
4848
struct UrlData {
4949
int isFile; /* True if a "file:" url */
5050
int isHttps; /* True if a "https:" url */
5151
int isSsh; /* True if an "ssh:" url */
52
+ int isAlias; /* Input URL was an alias */
5253
char *name; /* Hostname for http: or filename for file: */
5354
char *hostname; /* The HOST: parameter on http headers */
5455
const char *protocol; /* "http" or "https" or "ssh" */
5556
int port; /* TCP port number for http: or https: */
5657
int dfltPort; /* The default port for the given protocol */
@@ -67,11 +68,13 @@
6768
};
6869
#endif /* INTERFACE */
6970
7071
7172
/*
72
-** Parse the given URL. Populate members of the provided UrlData structure
73
+** Parse the given URL. Or if zUrl is NULL, parse the URL in the
74
+** last-sync-url setting using last-sync-pw as the password. Store
75
+** the parser results in the pUrlData object. Populate members of pUrlData
7376
** as follows:
7477
**
7578
** isFile True if FILE:
7679
** isHttps True if HTTPS:
7780
** isSsh True if SSH:
@@ -83,25 +86,42 @@
8386
** user Userid.
8487
** passwd Password.
8588
** hostname HOST:PORT or just HOST if port is the default.
8689
** canonical The URL in canonical form, omitting the password
8790
**
91
+** This routine differs from url_parse() in that this routine stores the
92
+** results in pUrlData and does not change the values of global variables.
93
+** The url_parse() routine puts its result in g.url.
8894
*/
8995
void url_parse_local(
9096
const char *zUrl,
9197
unsigned int urlFlags,
9298
UrlData *pUrlData
9399
){
94100
int i, j, c;
95101
char *zFile = 0;
96102
97
- if( zUrl==0 ){
103
+ if( zUrl==0 || strcmp(zUrl,"default")==0 ){
98104
zUrl = db_get("last-sync-url", 0);
99105
if( zUrl==0 ) return;
100106
if( pUrlData->passwd==0 ){
101107
pUrlData->passwd = unobscure(db_get("last-sync-pw", 0));
102108
}
109
+ pUrlData->isAlias = 1;
110
+ }else{
111
+ char *zAlt;
112
+ zAlt = db_text(0, "SELECT value FROM config WHERE name='sync-url:%q'",zUrl);
113
+ if( zAlt ){
114
+ pUrlData->passwd = unobscure(
115
+ db_text(0, "SELECT value FROM config WHERE name='sync-pw:%q'",zUrl)
116
+ );
117
+ zUrl = zAlt;
118
+ urlFlags |= URL_REMEMBER_PW;
119
+ pUrlData->isAlias = 1;
120
+ }else{
121
+ pUrlData->isAlias = 0;
122
+ }
103123
}
104124
105125
if( strncmp(zUrl, "http://", 7)==0
106126
|| strncmp(zUrl, "https://", 8)==0
107127
|| strncmp(zUrl, "ssh://", 6)==0
@@ -261,11 +281,12 @@
261281
pUrlData->protocol = "file";
262282
pUrlData->path = "";
263283
pUrlData->name = mprintf("%b", &cfile);
264284
pUrlData->canonical = mprintf("file://%T", pUrlData->name);
265285
blob_reset(&cfile);
266
- }else if( pUrlData->user!=0 && pUrlData->passwd==0 && (urlFlags & URL_PROMPT_PW) ){
286
+ }else if( pUrlData->user!=0 && pUrlData->passwd==0
287
+ && (urlFlags & URL_PROMPT_PW)!=0 ){
267288
url_prompt_for_password_local(pUrlData);
268289
}else if( pUrlData->user!=0 && ( urlFlags & URL_ASK_REMEMBER_PW ) ){
269290
if( isatty(fileno(stdin)) && ( urlFlags & URL_REMEMBER_PW )==0 ){
270291
if( save_password_prompt(pUrlData->passwd) ){
271292
pUrlData->flags = urlFlags |= URL_REMEMBER_PW;
@@ -276,11 +297,13 @@
276297
}
277298
}
278299
279300
/*
280301
** Parse the given URL, which describes a sync server. Populate variables
281
-** in the global "g" structure as follows:
302
+** in the global "g.url" structure as shown below. If zUrl is NULL, then
303
+** parse the URL given in the last-sync-url setting, taking the password
304
+** form last-sync-pw.
282305
**
283306
** g.url.isFile True if FILE:
284307
** g.url.isHttps True if HTTPS:
285308
** g.url.isSsh True if SSH:
286309
** g.url.protocol "http" or "https" or "file"
287310
--- src/url.c
+++ src/url.c
@@ -47,10 +47,11 @@
47 */
48 struct UrlData {
49 int isFile; /* True if a "file:" url */
50 int isHttps; /* True if a "https:" url */
51 int isSsh; /* True if an "ssh:" url */
 
52 char *name; /* Hostname for http: or filename for file: */
53 char *hostname; /* The HOST: parameter on http headers */
54 const char *protocol; /* "http" or "https" or "ssh" */
55 int port; /* TCP port number for http: or https: */
56 int dfltPort; /* The default port for the given protocol */
@@ -67,11 +68,13 @@
67 };
68 #endif /* INTERFACE */
69
70
71 /*
72 ** Parse the given URL. Populate members of the provided UrlData structure
 
 
73 ** as follows:
74 **
75 ** isFile True if FILE:
76 ** isHttps True if HTTPS:
77 ** isSsh True if SSH:
@@ -83,25 +86,42 @@
83 ** user Userid.
84 ** passwd Password.
85 ** hostname HOST:PORT or just HOST if port is the default.
86 ** canonical The URL in canonical form, omitting the password
87 **
 
 
 
88 */
89 void url_parse_local(
90 const char *zUrl,
91 unsigned int urlFlags,
92 UrlData *pUrlData
93 ){
94 int i, j, c;
95 char *zFile = 0;
96
97 if( zUrl==0 ){
98 zUrl = db_get("last-sync-url", 0);
99 if( zUrl==0 ) return;
100 if( pUrlData->passwd==0 ){
101 pUrlData->passwd = unobscure(db_get("last-sync-pw", 0));
102 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103 }
104
105 if( strncmp(zUrl, "http://", 7)==0
106 || strncmp(zUrl, "https://", 8)==0
107 || strncmp(zUrl, "ssh://", 6)==0
@@ -261,11 +281,12 @@
261 pUrlData->protocol = "file";
262 pUrlData->path = "";
263 pUrlData->name = mprintf("%b", &cfile);
264 pUrlData->canonical = mprintf("file://%T", pUrlData->name);
265 blob_reset(&cfile);
266 }else if( pUrlData->user!=0 && pUrlData->passwd==0 && (urlFlags & URL_PROMPT_PW) ){
 
267 url_prompt_for_password_local(pUrlData);
268 }else if( pUrlData->user!=0 && ( urlFlags & URL_ASK_REMEMBER_PW ) ){
269 if( isatty(fileno(stdin)) && ( urlFlags & URL_REMEMBER_PW )==0 ){
270 if( save_password_prompt(pUrlData->passwd) ){
271 pUrlData->flags = urlFlags |= URL_REMEMBER_PW;
@@ -276,11 +297,13 @@
276 }
277 }
278
279 /*
280 ** Parse the given URL, which describes a sync server. Populate variables
281 ** in the global "g" structure as follows:
 
 
282 **
283 ** g.url.isFile True if FILE:
284 ** g.url.isHttps True if HTTPS:
285 ** g.url.isSsh True if SSH:
286 ** g.url.protocol "http" or "https" or "file"
287
--- src/url.c
+++ src/url.c
@@ -47,10 +47,11 @@
47 */
48 struct UrlData {
49 int isFile; /* True if a "file:" url */
50 int isHttps; /* True if a "https:" url */
51 int isSsh; /* True if an "ssh:" url */
52 int isAlias; /* Input URL was an alias */
53 char *name; /* Hostname for http: or filename for file: */
54 char *hostname; /* The HOST: parameter on http headers */
55 const char *protocol; /* "http" or "https" or "ssh" */
56 int port; /* TCP port number for http: or https: */
57 int dfltPort; /* The default port for the given protocol */
@@ -67,11 +68,13 @@
68 };
69 #endif /* INTERFACE */
70
71
72 /*
73 ** Parse the given URL. Or if zUrl is NULL, parse the URL in the
74 ** last-sync-url setting using last-sync-pw as the password. Store
75 ** the parser results in the pUrlData object. Populate members of pUrlData
76 ** as follows:
77 **
78 ** isFile True if FILE:
79 ** isHttps True if HTTPS:
80 ** isSsh True if SSH:
@@ -83,25 +86,42 @@
86 ** user Userid.
87 ** passwd Password.
88 ** hostname HOST:PORT or just HOST if port is the default.
89 ** canonical The URL in canonical form, omitting the password
90 **
91 ** This routine differs from url_parse() in that this routine stores the
92 ** results in pUrlData and does not change the values of global variables.
93 ** The url_parse() routine puts its result in g.url.
94 */
95 void url_parse_local(
96 const char *zUrl,
97 unsigned int urlFlags,
98 UrlData *pUrlData
99 ){
100 int i, j, c;
101 char *zFile = 0;
102
103 if( zUrl==0 || strcmp(zUrl,"default")==0 ){
104 zUrl = db_get("last-sync-url", 0);
105 if( zUrl==0 ) return;
106 if( pUrlData->passwd==0 ){
107 pUrlData->passwd = unobscure(db_get("last-sync-pw", 0));
108 }
109 pUrlData->isAlias = 1;
110 }else{
111 char *zAlt;
112 zAlt = db_text(0, "SELECT value FROM config WHERE name='sync-url:%q'",zUrl);
113 if( zAlt ){
114 pUrlData->passwd = unobscure(
115 db_text(0, "SELECT value FROM config WHERE name='sync-pw:%q'",zUrl)
116 );
117 zUrl = zAlt;
118 urlFlags |= URL_REMEMBER_PW;
119 pUrlData->isAlias = 1;
120 }else{
121 pUrlData->isAlias = 0;
122 }
123 }
124
125 if( strncmp(zUrl, "http://", 7)==0
126 || strncmp(zUrl, "https://", 8)==0
127 || strncmp(zUrl, "ssh://", 6)==0
@@ -261,11 +281,12 @@
281 pUrlData->protocol = "file";
282 pUrlData->path = "";
283 pUrlData->name = mprintf("%b", &cfile);
284 pUrlData->canonical = mprintf("file://%T", pUrlData->name);
285 blob_reset(&cfile);
286 }else if( pUrlData->user!=0 && pUrlData->passwd==0
287 && (urlFlags & URL_PROMPT_PW)!=0 ){
288 url_prompt_for_password_local(pUrlData);
289 }else if( pUrlData->user!=0 && ( urlFlags & URL_ASK_REMEMBER_PW ) ){
290 if( isatty(fileno(stdin)) && ( urlFlags & URL_REMEMBER_PW )==0 ){
291 if( save_password_prompt(pUrlData->passwd) ){
292 pUrlData->flags = urlFlags |= URL_REMEMBER_PW;
@@ -276,11 +297,13 @@
297 }
298 }
299
300 /*
301 ** Parse the given URL, which describes a sync server. Populate variables
302 ** in the global "g.url" structure as shown below. If zUrl is NULL, then
303 ** parse the URL given in the last-sync-url setting, taking the password
304 ** form last-sync-pw.
305 **
306 ** g.url.isFile True if FILE:
307 ** g.url.isHttps True if HTTPS:
308 ** g.url.isSsh True if SSH:
309 ** g.url.protocol "http" or "https" or "file"
310

Keyboard Shortcuts

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