Fossil SCM

Enhance the "fossil checkout" command to that it too cleans up directories that it makes empty.

drh 2019-02-26 20:35 rmdir-on-update
Commit 95b700c2abb99371a9d916cabc6bff36ab27c3bb2b35a88cc3041279ae8b22e5
+41 -3
--- src/checkout.c
+++ src/checkout.c
@@ -39,15 +39,53 @@
3939
}
4040
4141
/*
4242
** Undo the current check-out. Unlink all files from the disk.
4343
** Clear the VFILE table.
44
+**
45
+** Also delete any directory that becomes empty as a result of deleting
46
+** files due to this operation, as long as that directory is not the
47
+** current working directory and is not on the empty-dirs list.
4448
*/
4549
void uncheckout(int vid){
46
- if( vid>0 ){
47
- vfile_unlink(vid);
48
- }
50
+ char *zPwd;
51
+ if( vid<=0 ) return;
52
+ sqlite3_create_function(g.db, "dirname",1,SQLITE_UTF8,0,
53
+ file_dirname_sql_function, 0, 0);
54
+ sqlite3_create_function(g.db, "unlink",1,SQLITE_UTF8,0,
55
+ file_delete_sql_function, 0, 0);
56
+ sqlite3_create_function(g.db, "rmdir", 1, SQLITE_UTF8, 0,
57
+ file_rmdir_sql_function, 0, 0);
58
+ db_multi_exec(
59
+ "CREATE TEMP TABLE dir_to_delete(name TEXT %s PRIMARY KEY)WITHOUT ROWID",
60
+ filename_collation()
61
+ );
62
+ db_multi_exec(
63
+ "INSERT OR IGNORE INTO dir_to_delete(name)"
64
+ " SELECT dirname(pathname) FROM vfile"
65
+ " WHERE vid=%d AND mrid>0",
66
+ vid
67
+ );
68
+ do{
69
+ db_multi_exec(
70
+ "INSERT OR IGNORE INTO dir_to_delete(name)"
71
+ " SELECT dirname(name) FROM dir_to_delete;"
72
+ );
73
+ }while( db_changes() );
74
+ db_multi_exec(
75
+ "SELECT unlink(%Q||pathname) FROM vfile"
76
+ " WHERE vid=%d AND mrid>0;",
77
+ g.zLocalRoot, vid
78
+ );
79
+ ensure_empty_dirs_created(1);
80
+ zPwd = file_getcwd(0,0);
81
+ db_multi_exec(
82
+ "SELECT rmdir(%Q||name) FROM dir_to_delete"
83
+ " WHERE (%Q||name)<>%Q ORDER BY name DESC",
84
+ g.zLocalRoot, g.zLocalRoot, zPwd
85
+ );
86
+ fossil_free(zPwd);
4987
db_multi_exec("DELETE FROM vfile WHERE vid=%d", vid);
5088
}
5189
5290
5391
/*
5492
--- src/checkout.c
+++ src/checkout.c
@@ -39,15 +39,53 @@
39 }
40
41 /*
42 ** Undo the current check-out. Unlink all files from the disk.
43 ** Clear the VFILE table.
 
 
 
 
44 */
45 void uncheckout(int vid){
46 if( vid>0 ){
47 vfile_unlink(vid);
48 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49 db_multi_exec("DELETE FROM vfile WHERE vid=%d", vid);
50 }
51
52
53 /*
54
--- src/checkout.c
+++ src/checkout.c
@@ -39,15 +39,53 @@
39 }
40
41 /*
42 ** Undo the current check-out. Unlink all files from the disk.
43 ** Clear the VFILE table.
44 **
45 ** Also delete any directory that becomes empty as a result of deleting
46 ** files due to this operation, as long as that directory is not the
47 ** current working directory and is not on the empty-dirs list.
48 */
49 void uncheckout(int vid){
50 char *zPwd;
51 if( vid<=0 ) return;
52 sqlite3_create_function(g.db, "dirname",1,SQLITE_UTF8,0,
53 file_dirname_sql_function, 0, 0);
54 sqlite3_create_function(g.db, "unlink",1,SQLITE_UTF8,0,
55 file_delete_sql_function, 0, 0);
56 sqlite3_create_function(g.db, "rmdir", 1, SQLITE_UTF8, 0,
57 file_rmdir_sql_function, 0, 0);
58 db_multi_exec(
59 "CREATE TEMP TABLE dir_to_delete(name TEXT %s PRIMARY KEY)WITHOUT ROWID",
60 filename_collation()
61 );
62 db_multi_exec(
63 "INSERT OR IGNORE INTO dir_to_delete(name)"
64 " SELECT dirname(pathname) FROM vfile"
65 " WHERE vid=%d AND mrid>0",
66 vid
67 );
68 do{
69 db_multi_exec(
70 "INSERT OR IGNORE INTO dir_to_delete(name)"
71 " SELECT dirname(name) FROM dir_to_delete;"
72 );
73 }while( db_changes() );
74 db_multi_exec(
75 "SELECT unlink(%Q||pathname) FROM vfile"
76 " WHERE vid=%d AND mrid>0;",
77 g.zLocalRoot, vid
78 );
79 ensure_empty_dirs_created(1);
80 zPwd = file_getcwd(0,0);
81 db_multi_exec(
82 "SELECT rmdir(%Q||name) FROM dir_to_delete"
83 " WHERE (%Q||name)<>%Q ORDER BY name DESC",
84 g.zLocalRoot, g.zLocalRoot, zPwd
85 );
86 fossil_free(zPwd);
87 db_multi_exec("DELETE FROM vfile WHERE vid=%d", vid);
88 }
89
90
91 /*
92
+49 -1
--- src/file.c
+++ src/file.c
@@ -437,10 +437,29 @@
437437
return mprintf("%.*s", (int)(zTail-z-1), z);
438438
}else{
439439
return 0;
440440
}
441441
}
442
+
443
+/* SQL Function: file_dirname(NAME)
444
+**
445
+** Return the directory for NAME
446
+*/
447
+void file_dirname_sql_function(
448
+ sqlite3_context *context,
449
+ int argc,
450
+ sqlite3_value **argv
451
+){
452
+ const char *zName = (const char*)sqlite3_value_text(argv[0]);
453
+ char *zDir;
454
+ if( zName==0 ) return;
455
+ zDir = file_dirname(zName);
456
+ if( zDir ){
457
+ sqlite3_result_text(context,zDir,-1,fossil_free);
458
+ }
459
+}
460
+
442461
443462
/*
444463
** Rename a file or directory.
445464
** Returns zero upon success.
446465
*/
@@ -594,10 +613,30 @@
594613
rc = unlink(zFilename);
595614
#endif
596615
fossil_path_free(z);
597616
return rc;
598617
}
618
+
619
+/* SQL Function: file_delete(NAME)
620
+**
621
+** Remove file NAME. Return zero on success and non-zero if anything goes
622
+** wrong.
623
+*/
624
+void file_delete_sql_function(
625
+ sqlite3_context *context,
626
+ int argc,
627
+ sqlite3_value **argv
628
+){
629
+ const char *zName = (const char*)sqlite3_value_text(argv[0]);
630
+ int rc;
631
+ if( zName==0 ){
632
+ rc = 1;
633
+ }else{
634
+ rc = file_delete(zName);
635
+ }
636
+ sqlite3_result_int(context, rc);
637
+}
599638
600639
/*
601640
** Create a directory called zName, if it does not already exist.
602641
** If forceFlag is 1, delete any prior non-directory object
603642
** with the same name.
@@ -910,12 +949,20 @@
910949
** Get the current working directory.
911950
**
912951
** On windows, the name is converted from unicode to UTF8 and all '\\'
913952
** characters are converted to '/'. No conversions are needed on
914953
** unix.
954
+**
955
+** Store the value of the CWD in zBuf which is nBuf bytes in size.
956
+** or if zBuf==0, allocate space to hold the result using fossil_malloc().
915957
*/
916
-void file_getcwd(char *zBuf, int nBuf){
958
+char *file_getcwd(char *zBuf, int nBuf){
959
+ char zTemp[2000];
960
+ if( zBuf==0 ){
961
+ zBuf = zTemp;
962
+ nBuf = sizeof(zTemp);
963
+ }
917964
#ifdef _WIN32
918965
win32_getcwd(zBuf, nBuf);
919966
#else
920967
if( getcwd(zBuf, nBuf-1)==0 ){
921968
if( errno==ERANGE ){
@@ -924,10 +971,11 @@
924971
fossil_panic("cannot find current working directory; %s",
925972
strerror(errno));
926973
}
927974
}
928975
#endif
976
+ return zBuf==zTemp ? fossil_strdup(zBuf) : zBuf;
929977
}
930978
931979
/*
932980
** Return true if zPath is an absolute pathname. Return false
933981
** if it is relative.
934982
--- src/file.c
+++ src/file.c
@@ -437,10 +437,29 @@
437 return mprintf("%.*s", (int)(zTail-z-1), z);
438 }else{
439 return 0;
440 }
441 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
442
443 /*
444 ** Rename a file or directory.
445 ** Returns zero upon success.
446 */
@@ -594,10 +613,30 @@
594 rc = unlink(zFilename);
595 #endif
596 fossil_path_free(z);
597 return rc;
598 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
599
600 /*
601 ** Create a directory called zName, if it does not already exist.
602 ** If forceFlag is 1, delete any prior non-directory object
603 ** with the same name.
@@ -910,12 +949,20 @@
910 ** Get the current working directory.
911 **
912 ** On windows, the name is converted from unicode to UTF8 and all '\\'
913 ** characters are converted to '/'. No conversions are needed on
914 ** unix.
 
 
 
915 */
916 void file_getcwd(char *zBuf, int nBuf){
 
 
 
 
 
917 #ifdef _WIN32
918 win32_getcwd(zBuf, nBuf);
919 #else
920 if( getcwd(zBuf, nBuf-1)==0 ){
921 if( errno==ERANGE ){
@@ -924,10 +971,11 @@
924 fossil_panic("cannot find current working directory; %s",
925 strerror(errno));
926 }
927 }
928 #endif
 
929 }
930
931 /*
932 ** Return true if zPath is an absolute pathname. Return false
933 ** if it is relative.
934
--- src/file.c
+++ src/file.c
@@ -437,10 +437,29 @@
437 return mprintf("%.*s", (int)(zTail-z-1), z);
438 }else{
439 return 0;
440 }
441 }
442
443 /* SQL Function: file_dirname(NAME)
444 **
445 ** Return the directory for NAME
446 */
447 void file_dirname_sql_function(
448 sqlite3_context *context,
449 int argc,
450 sqlite3_value **argv
451 ){
452 const char *zName = (const char*)sqlite3_value_text(argv[0]);
453 char *zDir;
454 if( zName==0 ) return;
455 zDir = file_dirname(zName);
456 if( zDir ){
457 sqlite3_result_text(context,zDir,-1,fossil_free);
458 }
459 }
460
461
462 /*
463 ** Rename a file or directory.
464 ** Returns zero upon success.
465 */
@@ -594,10 +613,30 @@
613 rc = unlink(zFilename);
614 #endif
615 fossil_path_free(z);
616 return rc;
617 }
618
619 /* SQL Function: file_delete(NAME)
620 **
621 ** Remove file NAME. Return zero on success and non-zero if anything goes
622 ** wrong.
623 */
624 void file_delete_sql_function(
625 sqlite3_context *context,
626 int argc,
627 sqlite3_value **argv
628 ){
629 const char *zName = (const char*)sqlite3_value_text(argv[0]);
630 int rc;
631 if( zName==0 ){
632 rc = 1;
633 }else{
634 rc = file_delete(zName);
635 }
636 sqlite3_result_int(context, rc);
637 }
638
639 /*
640 ** Create a directory called zName, if it does not already exist.
641 ** If forceFlag is 1, delete any prior non-directory object
642 ** with the same name.
@@ -910,12 +949,20 @@
949 ** Get the current working directory.
950 **
951 ** On windows, the name is converted from unicode to UTF8 and all '\\'
952 ** characters are converted to '/'. No conversions are needed on
953 ** unix.
954 **
955 ** Store the value of the CWD in zBuf which is nBuf bytes in size.
956 ** or if zBuf==0, allocate space to hold the result using fossil_malloc().
957 */
958 char *file_getcwd(char *zBuf, int nBuf){
959 char zTemp[2000];
960 if( zBuf==0 ){
961 zBuf = zTemp;
962 nBuf = sizeof(zTemp);
963 }
964 #ifdef _WIN32
965 win32_getcwd(zBuf, nBuf);
966 #else
967 if( getcwd(zBuf, nBuf-1)==0 ){
968 if( errno==ERANGE ){
@@ -924,10 +971,11 @@
971 fossil_panic("cannot find current working directory; %s",
972 strerror(errno));
973 }
974 }
975 #endif
976 return zBuf==zTemp ? fossil_strdup(zBuf) : zBuf;
977 }
978
979 /*
980 ** Return true if zPath is an absolute pathname. Return false
981 ** if it is relative.
982
+3 -3
--- src/update.c
+++ src/update.c
@@ -582,21 +582,21 @@
582582
** Clean up the mid and pid VFILE entries. Then commit the changes.
583583
*/
584584
if( dryRunFlag ){
585585
db_end_transaction(1); /* With --dry-run, rollback changes */
586586
}else{
587
- char zPwd[2000];
587
+ char *zPwd;
588588
ensure_empty_dirs_created(1);
589589
sqlite3_create_function(g.db, "rmdir", 1, SQLITE_UTF8, 0,
590590
file_rmdir_sql_function, 0, 0);
591
- zPwd[0] = 0;
592
- file_getcwd(zPwd, sizeof(zPwd));
591
+ zPwd = file_getcwd(0,0);
593592
db_multi_exec(
594593
"SELECT rmdir(%Q||name) FROM dir_to_delete"
595594
" WHERE (%Q||name)<>%Q ORDER BY name DESC",
596595
g.zLocalRoot, g.zLocalRoot, zPwd
597596
);
597
+ fossil_free(zPwd);
598598
if( g.argc<=3 ){
599599
/* All files updated. Shift the current checkout to the target. */
600600
db_multi_exec("DELETE FROM vfile WHERE vid!=%d", tid);
601601
checkout_set_all_exe(tid);
602602
manifest_to_disk(tid);
603603
--- src/update.c
+++ src/update.c
@@ -582,21 +582,21 @@
582 ** Clean up the mid and pid VFILE entries. Then commit the changes.
583 */
584 if( dryRunFlag ){
585 db_end_transaction(1); /* With --dry-run, rollback changes */
586 }else{
587 char zPwd[2000];
588 ensure_empty_dirs_created(1);
589 sqlite3_create_function(g.db, "rmdir", 1, SQLITE_UTF8, 0,
590 file_rmdir_sql_function, 0, 0);
591 zPwd[0] = 0;
592 file_getcwd(zPwd, sizeof(zPwd));
593 db_multi_exec(
594 "SELECT rmdir(%Q||name) FROM dir_to_delete"
595 " WHERE (%Q||name)<>%Q ORDER BY name DESC",
596 g.zLocalRoot, g.zLocalRoot, zPwd
597 );
 
598 if( g.argc<=3 ){
599 /* All files updated. Shift the current checkout to the target. */
600 db_multi_exec("DELETE FROM vfile WHERE vid!=%d", tid);
601 checkout_set_all_exe(tid);
602 manifest_to_disk(tid);
603
--- src/update.c
+++ src/update.c
@@ -582,21 +582,21 @@
582 ** Clean up the mid and pid VFILE entries. Then commit the changes.
583 */
584 if( dryRunFlag ){
585 db_end_transaction(1); /* With --dry-run, rollback changes */
586 }else{
587 char *zPwd;
588 ensure_empty_dirs_created(1);
589 sqlite3_create_function(g.db, "rmdir", 1, SQLITE_UTF8, 0,
590 file_rmdir_sql_function, 0, 0);
591 zPwd = file_getcwd(0,0);
 
592 db_multi_exec(
593 "SELECT rmdir(%Q||name) FROM dir_to_delete"
594 " WHERE (%Q||name)<>%Q ORDER BY name DESC",
595 g.zLocalRoot, g.zLocalRoot, zPwd
596 );
597 fossil_free(zPwd);
598 if( g.argc<=3 ){
599 /* All files updated. Shift the current checkout to the target. */
600 db_multi_exec("DELETE FROM vfile WHERE vid!=%d", tid);
601 checkout_set_all_exe(tid);
602 manifest_to_disk(tid);
603
-18
--- src/vfile.c
+++ src/vfile.c
@@ -359,28 +359,10 @@
359359
file_mtime(zName, RepoFILE), id);
360360
}
361361
db_finalize(&q);
362362
}
363363
364
-
365
-/*
366
-** Delete from the disk every file in VFILE vid.
367
-*/
368
-void vfile_unlink(int vid){
369
- Stmt q;
370
- db_prepare(&q, "SELECT %Q || pathname FROM vfile"
371
- " WHERE vid=%d AND mrid>0", g.zLocalRoot, vid);
372
- while( db_step(&q)==SQLITE_ROW ){
373
- const char *zName;
374
-
375
- zName = db_column_text(&q, 0);
376
- file_delete(zName);
377
- }
378
- db_finalize(&q);
379
- db_multi_exec("UPDATE vfile SET mtime=NULL WHERE vid=%d AND mrid>0", vid);
380
-}
381
-
382364
/*
383365
** Check to see if the directory named in zPath is the top of a checkout.
384366
** In other words, check to see if directory pPath contains a file named
385367
** "_FOSSIL_" or ".fslckout". Return true or false.
386368
*/
387369
--- src/vfile.c
+++ src/vfile.c
@@ -359,28 +359,10 @@
359 file_mtime(zName, RepoFILE), id);
360 }
361 db_finalize(&q);
362 }
363
364
365 /*
366 ** Delete from the disk every file in VFILE vid.
367 */
368 void vfile_unlink(int vid){
369 Stmt q;
370 db_prepare(&q, "SELECT %Q || pathname FROM vfile"
371 " WHERE vid=%d AND mrid>0", g.zLocalRoot, vid);
372 while( db_step(&q)==SQLITE_ROW ){
373 const char *zName;
374
375 zName = db_column_text(&q, 0);
376 file_delete(zName);
377 }
378 db_finalize(&q);
379 db_multi_exec("UPDATE vfile SET mtime=NULL WHERE vid=%d AND mrid>0", vid);
380 }
381
382 /*
383 ** Check to see if the directory named in zPath is the top of a checkout.
384 ** In other words, check to see if directory pPath contains a file named
385 ** "_FOSSIL_" or ".fslckout". Return true or false.
386 */
387
--- src/vfile.c
+++ src/vfile.c
@@ -359,28 +359,10 @@
359 file_mtime(zName, RepoFILE), id);
360 }
361 db_finalize(&q);
362 }
363
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
364 /*
365 ** Check to see if the directory named in zPath is the top of a checkout.
366 ** In other words, check to see if directory pPath contains a file named
367 ** "_FOSSIL_" or ".fslckout". Return true or false.
368 */
369

Keyboard Shortcuts

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