Fossil SCM

Add the "fossil backup" command to safely make a backup copy of a repository.

drh 2020-07-12 19:11 trunk
Commit aadbe015dfa56542f9338634623dbca1abb91c68c5570d2c9c871bb3bfd3a099
2 files changed +13 +44
--- src/allrepo.c
+++ src/allrepo.c
@@ -62,10 +62,13 @@
6262
** On Win32 systems, the file is named "_fossil" and is located in
6363
** %LOCALAPPDATA%, %APPDATA% or %HOMEPATH%.
6464
**
6565
** Available operations are:
6666
**
67
+** backup Backup all repositories. The argument must the name of
68
+** a directory into which all backup repositories are written.
69
+**
6770
** cache Manages the cache used for potentially expensive web
6871
** pages. Any additional arguments are passed on verbatim
6972
** to the cache command.
7073
**
7174
** changes Shows all local checkouts that have uncommitted changes.
@@ -174,10 +177,20 @@
174177
return;
175178
}
176179
if( strncmp(zCmd, "list", n)==0 || strncmp(zCmd,"ls",n)==0 ){
177180
zCmd = "list";
178181
useCheckouts = find_option("ckout","c",0)!=0;
182
+ }else if( strncmp(zCmd, "backup", n)==0 ){
183
+ char *zDest;
184
+ zCmd = "backup -R";
185
+ collect_argument(&extra, "overwrite",0);
186
+ if( g.argc!=4 ) usage("backup DIRECTORY");
187
+ zDest = g.argv[3];
188
+ if( file_isdir(zDest, ExtFILE)!=1 ){
189
+ fossil_fatal("argument to \"fossil all backup\" must be a directory");
190
+ }
191
+ blob_appendf(&extra, " %$", zDest);
179192
}else if( strncmp(zCmd, "clean", n)==0 ){
180193
zCmd = "clean --chdir";
181194
collect_argument(&extra, "allckouts",0);
182195
collect_argument_value(&extra, "case-sensitive");
183196
collect_argument_value(&extra, "clean");
184197
--- src/allrepo.c
+++ src/allrepo.c
@@ -62,10 +62,13 @@
62 ** On Win32 systems, the file is named "_fossil" and is located in
63 ** %LOCALAPPDATA%, %APPDATA% or %HOMEPATH%.
64 **
65 ** Available operations are:
66 **
 
 
 
67 ** cache Manages the cache used for potentially expensive web
68 ** pages. Any additional arguments are passed on verbatim
69 ** to the cache command.
70 **
71 ** changes Shows all local checkouts that have uncommitted changes.
@@ -174,10 +177,20 @@
174 return;
175 }
176 if( strncmp(zCmd, "list", n)==0 || strncmp(zCmd,"ls",n)==0 ){
177 zCmd = "list";
178 useCheckouts = find_option("ckout","c",0)!=0;
 
 
 
 
 
 
 
 
 
 
179 }else if( strncmp(zCmd, "clean", n)==0 ){
180 zCmd = "clean --chdir";
181 collect_argument(&extra, "allckouts",0);
182 collect_argument_value(&extra, "case-sensitive");
183 collect_argument_value(&extra, "clean");
184
--- src/allrepo.c
+++ src/allrepo.c
@@ -62,10 +62,13 @@
62 ** On Win32 systems, the file is named "_fossil" and is located in
63 ** %LOCALAPPDATA%, %APPDATA% or %HOMEPATH%.
64 **
65 ** Available operations are:
66 **
67 ** backup Backup all repositories. The argument must the name of
68 ** a directory into which all backup repositories are written.
69 **
70 ** cache Manages the cache used for potentially expensive web
71 ** pages. Any additional arguments are passed on verbatim
72 ** to the cache command.
73 **
74 ** changes Shows all local checkouts that have uncommitted changes.
@@ -174,10 +177,20 @@
177 return;
178 }
179 if( strncmp(zCmd, "list", n)==0 || strncmp(zCmd,"ls",n)==0 ){
180 zCmd = "list";
181 useCheckouts = find_option("ckout","c",0)!=0;
182 }else if( strncmp(zCmd, "backup", n)==0 ){
183 char *zDest;
184 zCmd = "backup -R";
185 collect_argument(&extra, "overwrite",0);
186 if( g.argc!=4 ) usage("backup DIRECTORY");
187 zDest = g.argv[3];
188 if( file_isdir(zDest, ExtFILE)!=1 ){
189 fossil_fatal("argument to \"fossil all backup\" must be a directory");
190 }
191 blob_appendf(&extra, " %$", zDest);
192 }else if( strncmp(zCmd, "clean", n)==0 ){
193 zCmd = "clean --chdir";
194 collect_argument(&extra, "allckouts",0);
195 collect_argument_value(&extra, "case-sensitive");
196 collect_argument_value(&extra, "clean");
197
+44
--- src/sync.c
+++ src/sync.c
@@ -387,5 +387,49 @@
387387
}else{
388388
url_parse(zUrl, 0);
389389
fossil_print("%s\n", g.url.canonical);
390390
}
391391
}
392
+
393
+/*
394
+** COMMAND: backup*
395
+**
396
+** Usage: %fossil backup ?OPTIONS? FILE|DIRECTORY
397
+**
398
+** Make a backup of the repository into the named file or into the named
399
+** directory. This backup is guaranteed to be consistent even if there are
400
+** concurrent chnages taking place on the repository. In other words, it
401
+** is safe to run "fossil backup" on a repository that is in active use.
402
+**
403
+** Only the main repository database is backed up by this command. The
404
+** open checkout file (if any) is not saved. Nor is the global configuration
405
+** database.
406
+**
407
+** Options:
408
+**
409
+** --overwrite Ok to overwrite an existing file.
410
+** -R NAME Filename of the repository to backup
411
+*/
412
+void backup_cmd(void){
413
+ char *zDest;
414
+ int bOverwrite = 0;
415
+ db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
416
+ bOverwrite = find_option("overwrite",0,0)!=0;
417
+ verify_all_options();
418
+ if( g.argc!=3 ){
419
+ usage("FILE|DIRECTORY");
420
+ }
421
+ zDest = g.argv[2];
422
+ if( file_isdir(zDest, ExtFILE)==1 ){
423
+ zDest = mprintf("%s/%s", zDest, file_tail(g.zRepositoryName));
424
+ }
425
+ if( file_isfile(zDest, ExtFILE) ){
426
+ if( bOverwrite ){
427
+ if( file_delete(zDest) ){
428
+ fossil_fatal("unable to delete old copy of \"%s\"", zDest);
429
+ }
430
+ }else{
431
+ fossil_fatal("backup \"%s\" already exists", zDest);
432
+ }
433
+ }
434
+ db_multi_exec("VACUUM repository INTO %Q", zDest);
435
+}
392436
--- src/sync.c
+++ src/sync.c
@@ -387,5 +387,49 @@
387 }else{
388 url_parse(zUrl, 0);
389 fossil_print("%s\n", g.url.canonical);
390 }
391 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
392
--- src/sync.c
+++ src/sync.c
@@ -387,5 +387,49 @@
387 }else{
388 url_parse(zUrl, 0);
389 fossil_print("%s\n", g.url.canonical);
390 }
391 }
392
393 /*
394 ** COMMAND: backup*
395 **
396 ** Usage: %fossil backup ?OPTIONS? FILE|DIRECTORY
397 **
398 ** Make a backup of the repository into the named file or into the named
399 ** directory. This backup is guaranteed to be consistent even if there are
400 ** concurrent chnages taking place on the repository. In other words, it
401 ** is safe to run "fossil backup" on a repository that is in active use.
402 **
403 ** Only the main repository database is backed up by this command. The
404 ** open checkout file (if any) is not saved. Nor is the global configuration
405 ** database.
406 **
407 ** Options:
408 **
409 ** --overwrite Ok to overwrite an existing file.
410 ** -R NAME Filename of the repository to backup
411 */
412 void backup_cmd(void){
413 char *zDest;
414 int bOverwrite = 0;
415 db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
416 bOverwrite = find_option("overwrite",0,0)!=0;
417 verify_all_options();
418 if( g.argc!=3 ){
419 usage("FILE|DIRECTORY");
420 }
421 zDest = g.argv[2];
422 if( file_isdir(zDest, ExtFILE)==1 ){
423 zDest = mprintf("%s/%s", zDest, file_tail(g.zRepositoryName));
424 }
425 if( file_isfile(zDest, ExtFILE) ){
426 if( bOverwrite ){
427 if( file_delete(zDest) ){
428 fossil_fatal("unable to delete old copy of \"%s\"", zDest);
429 }
430 }else{
431 fossil_fatal("backup \"%s\" already exists", zDest);
432 }
433 }
434 db_multi_exec("VACUUM repository INTO %Q", zDest);
435 }
436

Keyboard Shortcuts

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