Index: auto.def ================================================================== --- auto.def +++ auto.def @@ -5,10 +5,11 @@ options { with-openssl:path|auto|none => {Look for OpenSSL in the given path, or auto or none} with-miniz=0 => {Use miniz from the source tree} with-zlib:path => {Look for zlib in the given path} + with-legacy-mv-rm=0 => {Enable legacy behavior for mv/rm (skip checkout files)} with-th1-docs=0 => {Enable TH1 for embedded documentation pages} with-th1-hooks=0 => {Enable TH1 hooks for commands and web pages} with-tcl:path => {Enable Tcl integration, with Tcl in the specified path} with-tcl-stubs=0 => {Enable Tcl integration via stubs library mechanism} with-tcl-private-stubs=0 @@ -85,10 +86,16 @@ # reading config.h first. define-append EXTRA_CFLAGS -DFOSSIL_ENABLE_JSON define FOSSIL_ENABLE_JSON msg-result "JSON support enabled" } + +if {[opt-bool with-legacy-mv-rm]} { + define-append EXTRA_CFLAGS -DFOSSIL_ENABLE_LEGACY_MV_RM + define FOSSIL_ENABLE_LEGACY_MV_RM + msg-result "Legacy mv/rm support enabled" +} if {[opt-bool with-th1-docs]} { define-append EXTRA_CFLAGS -DFOSSIL_ENABLE_TH1_DOCS define FOSSIL_ENABLE_TH1_DOCS msg-result "TH1 embedded documentation support enabled" Index: src/add.c ================================================================== --- src/add.c +++ src/add.c @@ -22,10 +22,28 @@ #include "add.h" #include #include #include "cygsup.h" +/* +** WARNING: For Fossil version 1.x this value was always zero. For Fossil +** 2.x, it will probably always be one. When this value is zero, +** files in the checkout will not be moved by the "mv" command and +** files in the checkout will not be removed by the "rm" command. +** +** If the FOSSIL_ENABLE_LEGACY_MV_RM compile-time option is used, +** the "mv-rm-files" setting will be consulted instead of using +** this value. +** +** To retain the Fossil version 1.x behavior when using Fossil 2.x, +** the FOSSIL_ENABLE_LEGACY_MV_RM compile-time option must be used +** -AND- the "mv-rm-files" setting must be set to zero. +*/ +#ifndef FOSSIL_MV_RM_FILE +#define FOSSIL_MV_RM_FILE (0) +#endif + /* ** This routine returns the names of files in a working checkout that ** are created by Fossil itself, and hence should not be added, deleted, ** or merge, and should be omitted from "clean" and "extras" lists. ** @@ -331,10 +349,58 @@ glob_free(pClean); add_files_in_sfile(vid); db_end_transaction(0); } + +/* +** This function adds a file to list of files to delete from disk after +** the other actions required for the parent operation have completed +** successfully. The first time it is called for the current process, +** it creates a temporary table named "fremove", to keep track of these +** files. +*/ +static void add_file_to_remove( + const char *zOldName /* The old name of the file on disk. */ +){ + static int tableCreated = 0; + Blob fullOldName; + if( !tableCreated ){ + db_multi_exec("CREATE TEMP TABLE fremove(x TEXT PRIMARY KEY %s)", + filename_collation()); + tableCreated = 1; + } + file_canonical_name(zOldName, &fullOldName, 0); + db_multi_exec("INSERT INTO fremove VALUES('%q');", blob_str(&fullOldName)); + blob_reset(&fullOldName); +} + +/* +** This function deletes files from the checkout, using the file names +** contained in the temporary table "fremove". The temporary table is +** created on demand by the add_file_to_remove() function. +** +** If dryRunFlag is non-zero, no files will be removed; however, their +** names will still be output. +** +** The temporary table "fremove" is dropped after being processed. +*/ +static void process_files_to_remove( + int dryRunFlag /* Zero to actually operate on the file-system. */ +){ + Stmt remove; + db_prepare(&remove, "SELECT x FROM fremove ORDER BY x;"); + while( db_step(&remove)==SQLITE_ROW ){ + const char *zOldName = db_column_text(&remove, 0); + if( !dryRunFlag ){ + file_delete(zOldName); + } + fossil_print("DELETED_FILE %s\n", zOldName); + } + db_finalize(&remove); + db_multi_exec("DROP TABLE fremove;"); +} /* ** COMMAND: rm ** COMMAND: delete ** COMMAND: forget* @@ -341,28 +407,55 @@ ** ** Usage: %fossil rm|delete|forget FILE1 ?FILE2 ...? ** ** Remove one or more files or directories from the repository. ** -** This command does NOT remove the files from disk. It just marks the -** files as no longer being part of the project. In other words, future -** changes to the named files will not be versioned. +** The 'rm' and 'delete' commands do NOT normally remove the files from +** disk. They just mark the files as no longer being part of the project. +** In other words, future changes to the named files will not be versioned. +** However, the default behavior of this command may be overridden via the +** command line options listed below and/or the 'mv-rm-files' setting. +** +** The 'forget' command never removes files from disk, even when the command +** line options and/or the 'mv-rm-files' setting would otherwise require it +** to do so. +** +** WARNING: If the "--hard" option is specified -OR- the "mv-rm-files" +** setting is non-zero, files WILL BE removed from disk as well. +** This does NOT apply to the 'forget' command. ** ** Options: +** --soft Skip removing files from the checkout. +** This supersedes the --hard option. +** --hard Remove files from the checkout. ** --case-sensitive Override the case-sensitive setting. +** -n|--dry-run If given, display instead of run actions. ** ** See also: addremove, add */ void delete_cmd(void){ int i; + int removeFiles; + int dryRunFlag; Stmt loop; + + dryRunFlag = find_option("dry-run","n",0)!=0; /* We should be done with options.. */ verify_all_options(); db_must_be_within_tree(); db_begin_transaction(); + if( g.argv[1][0]=='f' ){ /* i.e. "forget" */ + removeFiles = 0; + }else{ +#if FOSSIL_ENABLE_LEGACY_MV_RM + removeFiles = db_get_boolean("mv-rm-files",0); +#else + removeFiles = FOSSIL_MV_RM_FILE; +#endif + } db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)", filename_collation()); for(i=2; i=0 ){ if( x==0 ){ @@ -607,14 +705,75 @@ fossil_fatal("cannot rename '%s' to '%s' since the delete of '%s' has " "not yet been committed", zOrig, zNew, zNew); } } fossil_print("RENAME %s %s\n", zOrig, zNew); - db_multi_exec( - "UPDATE vfile SET pathname='%q' WHERE pathname='%q' %s AND vid=%d", - zNew, zOrig, filename_collation(), vid - ); + if( !dryRunFlag ){ + db_multi_exec( + "UPDATE vfile SET pathname='%q' WHERE pathname='%q' %s AND vid=%d", + zNew, zOrig, filename_collation(), vid + ); + } +} + +/* +** This function adds a file to list of files to move on disk after the +** other actions required for the parent operation have completed +** successfully. The first time it is called for the current process, +** it creates a temporary table named "fmove", to keep track of these +** files. +*/ +static void add_file_to_move( + const char *zOldName, /* The old name of the file on disk. */ + const char *zNewName /* The new name of the file on disk. */ +){ + static int tableCreated = 0; + Blob fullOldName; + Blob fullNewName; + if( !tableCreated ){ + db_multi_exec("CREATE TEMP TABLE fmove(x TEXT PRIMARY KEY %s, y TEXT %s)", + filename_collation(), filename_collation()); + tableCreated = 1; + } + file_canonical_name(zOldName, &fullOldName, 0); + file_canonical_name(zNewName, &fullNewName, 0); + db_multi_exec("INSERT INTO fmove VALUES('%q','%q');", + blob_str(&fullOldName), blob_str(&fullNewName)); + blob_reset(&fullNewName); + blob_reset(&fullOldName); +} + +/* +** This function moves files within the checkout, using the file names +** contained in the temporary table "fmove". The temporary table is +** created on demand by the add_file_to_move() function. +** +** If dryRunFlag is non-zero, no files will be moved; however, their +** names will still be output. +** +** The temporary table "fmove" is dropped after being processed. +*/ +static void process_files_to_move( + int dryRunFlag /* Zero to actually operate on the file-system. */ +){ + Stmt move; + db_prepare(&move, "SELECT x, y FROM fmove ORDER BY x;"); + while( db_step(&move)==SQLITE_ROW ){ + const char *zOldName = db_column_text(&move, 0); + const char *zNewName = db_column_text(&move, 1); + if( !dryRunFlag ){ + if( file_wd_islink(zOldName) ){ + symlink_copy(zOldName, zNewName); + }else{ + file_copy(zOldName, zNewName); + } + file_delete(zOldName); + } + fossil_print("MOVED_FILE %s\n", zOldName); + } + db_finalize(&move); + db_multi_exec("DROP TABLE fmove;"); } /* ** COMMAND: mv ** COMMAND: rename* @@ -623,27 +782,44 @@ ** or: %fossil mv|rename OLDNAME... DIR ** ** Move or rename one or more files or directories within the repository tree. ** You can either rename a file or directory or move it to another subdirectory. ** -** This command does NOT rename or move the files on disk. This command merely -** records the fact that filenames have changed so that appropriate notations -** can be made at the next commit/check-in. +** The 'mv' command does NOT normally rename or move the files on disk. +** This command merely records the fact that file names have changed so +** that appropriate notations can be made at the next commit/check-in. +** However, the default behavior of this command may be overridden via +** command line options listed below and/or the 'mv-rm-files' setting. +** +** The 'rename' command never renames or moves files on disk, even when the +** command line options and/or the 'mv-rm-files' setting would otherwise +** require it to do so. +** +** WARNING: If the "--hard" option is specified -OR- the "mv-rm-files" +** setting is non-zero, files WILL BE renamed or moved on disk +** as well. This does NOT apply to the 'rename' command. ** ** Options: +** --soft Skip moving files within the checkout. +** This supersedes the --hard option. +** --hard Move files within the checkout. ** --case-sensitive Override the case-sensitive setting. +** -n|--dry-run If given, display instead of run actions. ** ** See also: changes, status */ void mv_cmd(void){ int i; int vid; + int moveFiles; + int dryRunFlag; char *zDest; Blob dest; Stmt q; db_must_be_within_tree(); + dryRunFlag = find_option("dry-run","n",0)!=0; /* We should be done with options.. */ verify_all_options(); vid = db_lget_int("checkout", 0); @@ -653,10 +829,19 @@ if( g.argc<4 ){ usage("OLDNAME NEWNAME"); } zDest = g.argv[g.argc-1]; db_begin_transaction(); + if( g.argv[1][0]=='r' ){ /* i.e. "rename" */ + moveFiles = 0; + }else{ +#if FOSSIL_ENABLE_LEGACY_MV_RM + moveFiles = db_get_boolean("mv-rm-files",0); +#else + moveFiles = FOSSIL_MV_RM_FILE; +#endif + } file_tree_name(zDest, &dest, 1); db_multi_exec( "UPDATE vfile SET origname=pathname WHERE origname IS NULL;" ); db_multi_exec( @@ -711,18 +896,20 @@ } db_prepare(&q, "SELECT f, t FROM mv ORDER BY f"); while( db_step(&q)==SQLITE_ROW ){ const char *zFrom = db_column_text(&q, 0); const char *zTo = db_column_text(&q, 1); - mv_one_file(vid, zFrom, zTo); + mv_one_file(vid, zFrom, zTo, dryRunFlag); + if( moveFiles ) add_file_to_move(zFrom, zTo); } db_finalize(&q); db_end_transaction(0); + if( moveFiles ) process_files_to_move(dryRunFlag); } /* ** Function for stash_apply to be able to restore a file and indicate ** newly ADDED state. */ int stash_add_files_in_sfile(int vid){ return add_files_in_sfile(vid); } Index: src/configure.c ================================================================== --- src/configure.c +++ src/configure.c @@ -126,10 +126,14 @@ { "crnl-glob", CONFIGSET_PROJ }, { "encoding-glob", CONFIGSET_PROJ }, { "empty-dirs", CONFIGSET_PROJ }, { "allow-symlinks", CONFIGSET_PROJ }, { "dotfiles", CONFIGSET_PROJ }, + +#ifdef FOSSIL_ENABLE_LEGACY_MV_RM + { "mv-rm-files", CONFIGSET_PROJ }, +#endif { "ticket-table", CONFIGSET_TKT }, { "ticket-common", CONFIGSET_TKT }, { "ticket-change", CONFIGSET_TKT }, { "ticket-newpage", CONFIGSET_TKT }, Index: src/db.c ================================================================== --- src/db.c +++ src/db.c @@ -2362,10 +2362,13 @@ { "main-branch", 0, 40, 0, 0, "trunk" }, { "manifest", 0, 0, 1, 0, "off" }, { "max-loadavg", 0, 25, 0, 0, "0.0" }, { "max-upload", 0, 25, 0, 0, "250000" }, { "mtime-changes", 0, 0, 0, 0, "on" }, +#if FOSSIL_ENABLE_LEGACY_MV_RM + { "mv-rm-files", 0, 0, 0, 0, "off" }, +#endif { "pgp-command", 0, 40, 0, 0, "gpg --clearsign -o " }, { "proxy", 0, 32, 0, 0, "off" }, { "relative-paths", 0, 0, 0, 0, "on" }, { "repo-cksum", 0, 0, 0, 0, "on" }, { "self-register", 0, 0, 0, 0, "off" }, @@ -2572,10 +2575,16 @@ ** max-upload A limit on the size of uplink HTTP requests. The ** default is 250000 bytes. ** ** mtime-changes Use file modification times (mtimes) to detect when ** files have been modified. (Default "on".) +** +** mv-rm-files If enabled (and Fossil was compiled with legacy "mv/rm" +** support), the "mv" and "rename" commands will also move +** the associated files within the checkout -AND- the "rm" +** and "delete" commands will also remove the associated +** files from within the checkout. Default: off. ** ** pgp-command Command used to clear-sign manifests at check-in. ** The default is "gpg --clearsign -o ". ** ** proxy URL of the HTTP proxy. If undefined or "off" then Index: src/main.c ================================================================== --- src/main.c +++ src/main.c @@ -1007,10 +1007,13 @@ #else fossil_print("zlib %s, loaded %s\n", ZLIB_VERSION, zlibVersion()); #endif #if defined(FOSSIL_ENABLE_SSL) fossil_print("SSL (%s)\n", SSLeay_version(SSLEAY_VERSION)); +#endif +#if defined(FOSSIL_ENABLE_LEGACY_MV_RM) + fossil_print("LEGACY_MV_RM\n"); #endif #if defined(FOSSIL_ENABLE_TH1_DOCS) fossil_print("TH1_DOCS\n"); #endif #if defined(FOSSIL_ENABLE_TH1_HOOKS) Index: src/makemake.tcl ================================================================== --- src/makemake.tcl +++ src/makemake.tcl @@ -493,10 +493,14 @@ #### Automatically build OpenSSL when building Fossil (causes rebuild # issues when building incrementally). # # FOSSIL_BUILD_SSL = 1 + +#### Enable legacy treatment of mv/rm (skip checkout files) +# +# FOSSIL_ENABLE_LEGACY_MV_RM = 1 #### Enable TH1 scripts in embedded documentation files # # FOSSIL_ENABLE_TH1_DOCS = 1 @@ -692,10 +696,16 @@ # With HTTPS support ifdef FOSSIL_ENABLE_SSL TCC += -DFOSSIL_ENABLE_SSL=1 RCC += -DFOSSIL_ENABLE_SSL=1 endif + +# With legacy treatment of mv/rm +ifdef FOSSIL_ENABLE_LEGACY_MV_RM +TCC += -DFOSSIL_ENABLE_LEGACY_MV_RM=1 +RCC += -DFOSSIL_ENABLE_LEGACY_MV_RM=1 +endif # With TH1 embedded docs support ifdef FOSSIL_ENABLE_TH1_DOCS TCC += -DFOSSIL_ENABLE_TH1_DOCS=1 RCC += -DFOSSIL_ENABLE_TH1_DOCS=1 @@ -1309,10 +1319,13 @@ # Uncomment to enable SSL support # FOSSIL_ENABLE_SSL = 1 # Uncomment to build SSL libraries # FOSSIL_BUILD_SSL = 1 + +# Uncomment to enable legacy treatment of mv/rm +# FOSSIL_ENABLE_LEGACY_MV_RM = 1 # Uncomment to enable TH1 scripts in embedded documentation files # FOSSIL_ENABLE_TH1_DOCS = 1 # Uncomment to enable TH1 hooks @@ -1425,10 +1438,15 @@ TCC = $(TCC) /DFOSSIL_ENABLE_SSL=1 RCC = $(RCC) /DFOSSIL_ENABLE_SSL=1 LIBS = $(LIBS) $(SSLLIB) LIBDIR = $(LIBDIR) /LIBPATH:$(SSLLIBDIR) !endif + +!ifdef FOSSIL_ENABLE_LEGACY_MV_RM +TCC = $(TCC) /DFOSSIL_ENABLE_LEGACY_MV_RM=1 +RCC = $(RCC) /DFOSSIL_ENABLE_LEGACY_MV_RM=1 +!endif !ifdef FOSSIL_ENABLE_TH1_DOCS TCC = $(TCC) /DFOSSIL_ENABLE_TH1_DOCS=1 RCC = $(RCC) /DFOSSIL_ENABLE_TH1_DOCS=1 !endif Index: src/th_main.c ================================================================== --- src/th_main.c +++ src/th_main.c @@ -507,10 +507,11 @@ ** ** Return true if the fossil binary has the given compile-time feature ** enabled. The set of features includes: ** ** "ssl" = FOSSIL_ENABLE_SSL +** "legacyMvRm" = FOSSIL_ENABLE_LEGACY_MV_RM ** "th1Docs" = FOSSIL_ENABLE_TH1_DOCS ** "th1Hooks" = FOSSIL_ENABLE_TH1_HOOKS ** "tcl" = FOSSIL_ENABLE_TCL ** "useTclStubs" = USE_TCL_STUBS ** "tclStubs" = FOSSIL_ENABLE_TCL_STUBS @@ -538,10 +539,15 @@ } #if defined(FOSSIL_ENABLE_SSL) else if( 0 == fossil_strnicmp( zArg, "ssl\0", 4 ) ){ rc = 1; } +#endif +#if defined(FOSSIL_ENABLE_LEGACY_MV_RM) + else if( 0 == fossil_strnicmp( zArg, "legacyMvRm\0", 11 ) ){ + rc = 1; + } #endif #if defined(FOSSIL_ENABLE_TH1_DOCS) else if( 0 == fossil_strnicmp( zArg, "th1Docs\0", 8 ) ){ rc = 1; } Index: win/Makefile.mingw ================================================================== --- win/Makefile.mingw +++ win/Makefile.mingw @@ -52,10 +52,14 @@ #### Automatically build OpenSSL when building Fossil (causes rebuild # issues when building incrementally). # # FOSSIL_BUILD_SSL = 1 + +#### Enable legacy treatment of mv/rm (skip checkout files) +# +# FOSSIL_ENABLE_LEGACY_MV_RM = 1 #### Enable TH1 scripts in embedded documentation files # # FOSSIL_ENABLE_TH1_DOCS = 1 @@ -251,10 +255,16 @@ # With HTTPS support ifdef FOSSIL_ENABLE_SSL TCC += -DFOSSIL_ENABLE_SSL=1 RCC += -DFOSSIL_ENABLE_SSL=1 endif + +# With legacy treatment of mv/rm +ifdef FOSSIL_ENABLE_LEGACY_MV_RM +TCC += -DFOSSIL_ENABLE_LEGACY_MV_RM=1 +RCC += -DFOSSIL_ENABLE_LEGACY_MV_RM=1 +endif # With TH1 embedded docs support ifdef FOSSIL_ENABLE_TH1_DOCS TCC += -DFOSSIL_ENABLE_TH1_DOCS=1 RCC += -DFOSSIL_ENABLE_TH1_DOCS=1 Index: win/Makefile.mingw.mistachkin ================================================================== --- win/Makefile.mingw.mistachkin +++ win/Makefile.mingw.mistachkin @@ -52,10 +52,14 @@ #### Automatically build OpenSSL when building Fossil (causes rebuild # issues when building incrementally). # # FOSSIL_BUILD_SSL = 1 + +#### Enable legacy treatment of mv/rm (skip checkout files) +# +FOSSIL_ENABLE_LEGACY_MV_RM = 1 #### Enable TH1 scripts in embedded documentation files # FOSSIL_ENABLE_TH1_DOCS = 1 @@ -251,10 +255,16 @@ # With HTTPS support ifdef FOSSIL_ENABLE_SSL TCC += -DFOSSIL_ENABLE_SSL=1 RCC += -DFOSSIL_ENABLE_SSL=1 endif + +# With legacy treatment of mv/rm +ifdef FOSSIL_ENABLE_LEGACY_MV_RM +TCC += -DFOSSIL_ENABLE_LEGACY_MV_RM=1 +RCC += -DFOSSIL_ENABLE_LEGACY_MV_RM=1 +endif # With TH1 embedded docs support ifdef FOSSIL_ENABLE_TH1_DOCS TCC += -DFOSSIL_ENABLE_TH1_DOCS=1 RCC += -DFOSSIL_ENABLE_TH1_DOCS=1 Index: win/Makefile.msc ================================================================== --- win/Makefile.msc +++ win/Makefile.msc @@ -44,10 +44,13 @@ # Uncomment to enable SSL support # FOSSIL_ENABLE_SSL = 1 # Uncomment to build SSL libraries # FOSSIL_BUILD_SSL = 1 + +# Uncomment to enable legacy treatment of mv/rm +# FOSSIL_ENABLE_LEGACY_MV_RM = 1 # Uncomment to enable TH1 scripts in embedded documentation files # FOSSIL_ENABLE_TH1_DOCS = 1 # Uncomment to enable TH1 hooks @@ -160,10 +163,15 @@ TCC = $(TCC) /DFOSSIL_ENABLE_SSL=1 RCC = $(RCC) /DFOSSIL_ENABLE_SSL=1 LIBS = $(LIBS) $(SSLLIB) LIBDIR = $(LIBDIR) /LIBPATH:$(SSLLIBDIR) !endif + +!ifdef FOSSIL_ENABLE_LEGACY_MV_RM +TCC = $(TCC) /DFOSSIL_ENABLE_LEGACY_MV_RM=1 +RCC = $(RCC) /DFOSSIL_ENABLE_LEGACY_MV_RM=1 +!endif !ifdef FOSSIL_ENABLE_TH1_DOCS TCC = $(TCC) /DFOSSIL_ENABLE_TH1_DOCS=1 RCC = $(RCC) /DFOSSIL_ENABLE_TH1_DOCS=1 !endif Index: win/fossil.rc ================================================================== --- win/fossil.rc +++ win/fossil.rc @@ -115,10 +115,15 @@ VALUE "CommandLineIsUnicode", "Yes\0" #endif /* defined(BROKEN_MINGW_CMDLINE) */ #if defined(FOSSIL_ENABLE_SSL) VALUE "SslEnabled", "Yes, " OPENSSL_VERSION_TEXT "\0" #endif /* defined(FOSSIL_ENABLE_SSL) */ +#if defined(FOSSIL_ENABLE_LEGACY_MV_RM) + VALUE "LegacyMvRm", "Yes\0" +#else + VALUE "LegacyMvRm", "No\0" +#endif /* defined(FOSSIL_ENABLE_LEGACY_MV_RM) */ #if defined(FOSSIL_ENABLE_TH1_DOCS) VALUE "Th1Docs", "Yes\0" #else VALUE "Th1Docs", "No\0" #endif /* defined(FOSSIL_ENABLE_TH1_DOCS) */ Index: www/th1.md ================================================================== --- www/th1.md +++ www/th1.md @@ -283,10 +283,11 @@ Returns true if the binary has the given compile-time feature enabled. The possible features are: 1. **ssl** -- _Support for the HTTPS transport._ + 1. **legacyMvRm** -- _Support for legacy mv/rm command behavior._ 1. **th1Docs** -- _Support for TH1 in embedded documentation._ 1. **th1Hooks** -- _Support for TH1 command and web page hooks._ 1. **tcl** -- _Support for Tcl integration._ 1. **useTclStubs** -- _Tcl stubs enabled in the Tcl headers._ 1. **tclStubs** -- _Uses Tcl stubs (i.e. linking with stubs library)._