Check-in [e146d800ac]
Not logged in
Overview

SHA1 Hash:e146d800ac37390cfec72c43ddbb88f583970c89
Date: 2008-11-09 19:22:06
User: drh
Comment:Add the "mv" and "rename" commands (aliases for the same thing).
Timelines: ancestors | descendants | both | trunk
Other Links: files | ZIP archive | manifest

Tags And Properties
Changes
[hide diffs]

Modified src/add.c from [8c54ff6ce9] to [905321226f].

@@ -96,11 +96,16 @@
 ** COMMAND: rm
 ** COMMAND: del
 **
 ** Usage: %fossil rm FILE...
 **    or: %fossil del FILE...
+**
 ** Remove one or more files from the tree.
+**
+** 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.
 */
 void del_cmd(void){
   int i;
   int vid;
 
@@ -126,7 +131,108 @@
     }
     blob_reset(&pathname);
     free(zName);
   }
   db_multi_exec("DELETE FROM vfile WHERE deleted AND rid=0");
+  db_end_transaction(0);
+}
+
+/*
+** Rename a single file.
+**
+** The original name of the file is zOrig.  The new filename is zNew.
+*/
+static void mv_one_file(int vid, const char *zOrig, const char *zNew){
+  printf("RENAME %s %s\n", zOrig, zNew);
+  db_multi_exec(
+    "UPDATE vfile SET pathname='%s' WHERE pathname='%s' AND vid=%d",
+    zNew, zOrig, vid
+  );
+}
+
+/*
+** COMMAND: mv
+** COMMAND: rename
+**
+** Usage: %fossil mv|rename OLDNAME NEWNAME
+**    or: %fossil mv|rename OLDNAME... DIR
+**
+** Move or rename one or more files within the tree
+**
+** This command does rename the files on disk.  All this command does is
+** record the fact that filenames have changed so that appropriate notations
+** can be made at the next commit/checkin.
+*/
+void mv_cmd(void){
+  int i;
+  int vid;
+  char *zDest;
+  Blob dest;
+  Stmt q;
+
+  db_must_be_within_tree();
+  vid = db_lget_int("checkout", 0);
+  if( vid==0 ){
+    fossil_panic("no checkout rename files in");
+  }
+  if( g.argc<4 ){
+    usage("OLDNAME NEWNAME");
+  }
+  zDest = g.argv[g.argc-1];
+  db_begin_transaction();
+  file_tree_name(zDest, &dest, 1);
+  db_multi_exec(
+    "UPDATE vfile SET origname=pathname WHERE origname IS NULL;"
+  );
+  db_multi_exec(
+    "CREATE TEMP TABLE mv(f TEXT UNIQUE ON CONFLICT IGNORE, t TEXT);"
+  );
+  if( file_isdir(zDest)!=1 ){
+    Blob orig;
+    if( g.argc!=4 ){
+      usage("OLDNAME NEWNAME");
+    }
+    file_tree_name(g.argv[2], &orig, 1);
+    db_multi_exec(
+      "INSERT INTO mv VALUES(%B,%B)", &orig, &dest
+    );
+  }else{
+    for(i=2; i<g.argc-1; i++){
+      Blob orig;
+      char *zOrig;
+      int nOrig;
+      file_tree_name(g.argv[i], &orig, 1);
+      zOrig = blob_str(&orig);
+      nOrig = blob_size(&orig);
+      db_prepare(&q,
+         "SELECT pathname FROM vfile"
+         " WHERE vid=%d"
+         "   AND (pathname='%s' OR pathname GLOB '%s/*')"
+         " ORDER BY 1",
+         vid, zOrig, zOrig
+      );
+      while( db_step(&q)==SQLITE_ROW ){
+        const char *zPath = db_column_text(&q, 0);
+        int nPath = db_column_bytes(&q, 0);
+        const char *zTail;
+        if( nPath==nOrig ){
+          zTail = file_tail(zPath);
+        }else{
+          zTail = &zPath[nOrig+1];
+        }
+        db_multi_exec(
+          "INSERT INTO mv VALUES('%s','%s/%s')",
+          zPath, blob_str(&dest), zTail
+        );
+      }
+      db_finalize(&q);
+    }
+  }
+  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);
+  }
+  db_finalize(&q);
   db_end_transaction(0);
 }

Modified src/checkin.c from [ad8e78b43e] to [0b6152b93c].

@@ -36,18 +36,21 @@
 */
 static void status_report(Blob *report, const char *zPrefix){
   Stmt q;
   int nPrefix = strlen(zPrefix);
   db_prepare(&q,
-    "SELECT pathname, deleted, chnged, rid FROM vfile "
-    "WHERE file_is_selected(id) AND (chnged OR deleted OR rid=0) ORDER BY 1"
+    "SELECT pathname, deleted, chnged, rid, coalesce(origname!=pathname,0)"
+    "  FROM vfile "
+    " WHERE file_is_selected(id)"
+    "   AND (chnged OR deleted OR rid=0 OR pathname!=origname) ORDER BY 1"
   );
   while( db_step(&q)==SQLITE_ROW ){
     const char *zPathname = db_column_text(&q,0);
     int isDeleted = db_column_int(&q, 1);
     int isChnged = db_column_int(&q,2);
     int isNew = db_column_int(&q,3)==0;
+    int isRenamed = db_column_int(&q,4);
     char *zFullName = mprintf("%s/%s", g.zLocalRoot, zPathname);
     blob_append(report, zPrefix, nPrefix);
     if( isDeleted ){
       blob_appendf(report, "DELETED  %s\n", zPathname);
     }else if( access(zFullName, 0) ){
@@ -58,12 +61,14 @@
       blob_appendf(report, "DELETED  %s\n", zPathname);
     }else if( isChnged==2 ){
       blob_appendf(report, "UPDATED_BY_MERGE %s\n", zPathname);
     }else if( isChnged==3 ){
       blob_appendf(report, "ADDED_BY_MERGE %s\n", zPathname);
-    }else{
+    }else if( isChnged==1 ){
       blob_appendf(report, "EDITED   %s\n", zPathname);
+    }else if( isRenamed ){
+      blob_appendf(report, "RENAMED  %s\n", zPathname);
     }
     free(zFullName);
   }
   db_finalize(&q);
   db_prepare(&q, "SELECT uuid FROM vmerge JOIN blob ON merge=rid"
@@ -127,26 +132,32 @@
   Stmt q;
 
   db_must_be_within_tree();
   vid = db_lget_int("checkout", 0);
   vfile_check_signature(vid);
-  db_prepare(&q, "SELECT pathname, deleted, rid, chnged FROM vfile"
-                 " ORDER BY 1");
+  db_prepare(&q,
+     "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)"
+     "  FROM vfile"
+     " ORDER BY 1"
+  );
   while( db_step(&q)==SQLITE_ROW ){
     const char *zPathname = db_column_text(&q,0);
     int isDeleted = db_column_int(&q, 1);
     int isNew = db_column_int(&q,2)==0;
     int chnged = db_column_int(&q,3);
+    int renamed = db_column_int(&q,4);
     char *zFullName = mprintf("%s/%s", g.zLocalRoot, zPathname);
     if( isNew ){
       printf("ADDED     %s\n", zPathname);
     }else if( access(zFullName, 0) ){
       printf("MISSING   %s\n", zPathname);
     }else if( isDeleted ){
       printf("DELETED   %s\n", zPathname);
     }else if( chnged ){
       printf("EDITED    %s\n", zPathname);
+    }else if( renamed ){
+      printf("RENAMED   %s\n", zPathname);
     }else{
       printf("UNCHANGED %s\n", zPathname);
     }
     free(zFullName);
   }
@@ -480,28 +491,35 @@
   blob_appendf(&manifest, "C %F\n", blob_str(&comment));
   zDate = db_text(0, "SELECT datetime('now')");
   zDate[10] = 'T';
   blob_appendf(&manifest, "D %s\n", zDate);
   db_prepare(&q,
-    "SELECT pathname, uuid FROM vfile JOIN blob ON vfile.mrid=blob.rid"
+    "SELECT pathname, uuid, origname"
+    "  FROM vfile JOIN blob ON vfile.mrid=blob.rid"
     " WHERE NOT deleted AND vfile.vid=%d"
     " ORDER BY 1", vid);
   blob_zero(&filename);
   blob_appendf(&filename, "%s/", g.zLocalRoot);
   nBasename = blob_size(&filename);
   while( db_step(&q)==SQLITE_ROW ){
     const char *zName = db_column_text(&q, 0);
     const char *zUuid = db_column_text(&q, 1);
+    const char *zOrig = db_column_text(&q, 2);
     const char *zPerm;
     blob_append(&filename, zName, -1);
     if( file_isexe(blob_str(&filename)) ){
       zPerm = " x";
     }else{
       zPerm = "";
     }
     blob_resize(&filename, nBasename);
-    blob_appendf(&manifest, "F %F %s%s\n", zName, zUuid, zPerm);
+    if( zOrig==0 || strcmp(zOrig,zName)==0 ){
+      blob_appendf(&manifest, "F %F %s%s\n", zName, zUuid, zPerm);
+    }else{
+      if( zPerm[0]==0 ){ zPerm = " w"; }
+      blob_appendf(&manifest, "F %F %s%s %F\n", zName, zUuid, zPerm, zOrig);
+    }
   }
   blob_reset(&filename);
   db_finalize(&q);
   zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid);
   blob_appendf(&manifest, "P %s", zUuid);
@@ -557,11 +575,12 @@
   /* Update the vfile and vmerge tables */
   db_multi_exec(
     "DELETE FROM vfile WHERE (vid!=%d OR deleted) AND file_is_selected(id);"
     "DELETE FROM vmerge WHERE file_is_selected(id) OR id=0;"
     "UPDATE vfile SET vid=%d;"
-    "UPDATE vfile SET rid=mrid, chnged=0, deleted=0 WHERE file_is_selected(id);"
+    "UPDATE vfile SET rid=mrid, chnged=0, deleted=0, origname=NULL"
+    " WHERE file_is_selected(id);"
     , vid, nvid
   );
   db_lset_int("checkout", nvid);
 
   /* Verify that the repository checksum matches the expected checksum
@@ -791,11 +810,11 @@
   ** least one.
   */
 
   blob_appendf(&manifest, "P");
   for (i=0;i<zParentCount;i++) {
-    char* zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", zParents [i]);
+    char* zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", zParents[i]);
     blob_appendf(&manifest, " %s", zUuid);
     free(zUuid);
   }
   blob_appendf(&manifest, "\n");
 

Modified src/checkout.c from [b372b89d4e] to [01a97dfc51].

@@ -40,11 +40,12 @@
   int vid;
   db_must_be_within_tree();
   vid = db_lget_int("checkout",0);
   if( vid==0 ) return 2;
   vfile_check_signature(vid);
-  return db_exists("SELECT 1 FROM vfile WHERE chnged");
+  return db_exists("SELECT 1 FROM vfile WHERE chnged"
+                   " OR coalesce(origname!=pathname,0)");
 }
 
 /*
 ** Undo the current check-out.  Unlink all files from the disk.
 ** Clear the VFILE table.

Modified src/db.c from [47e57e78e7] to [d8256506fc].

@@ -674,17 +674,28 @@
 ** If zDbName is a valid local database file, open it and return
 ** true.  If it is not a valid local database file, return 0.
 */
 static int isValidLocalDb(const char *zDbName){
   i64 lsize;
+  int rc;
+  sqlite3_stmt *pStmt;
+
   if( access(zDbName, F_OK) ) return 0;
   lsize = file_size(zDbName);
   if( lsize%1024!=0 || lsize<4096 ) return 0;
   db_open_or_attach(zDbName, "localdb");
   g.localOpen = 1;
   db_open_config();
   db_open_repository(0);
+
+  /* If the "origname" column is missing from the vfile table, then
+  ** add it now. */
+  rc = sqlite3_prepare(g.db, "SELECT origname FROM vfile", -1, &pStmt, 0);
+  if( rc==SQLITE_ERROR ){
+    sqlite3_exec(g.db, "ALTER TABLE vfile ADD COLUMN origname TEXT", 0, 0, 0);
+  }
+
   return 1;
 }
 
 /*
 ** Locate the root directory of the local repository tree.  The root

Modified src/file.c from [d20fa8930e] to [3bd9bc50a5].

@@ -50,10 +50,23 @@
   struct stat buf;
   if( stat(zFilename, &buf)!=0 ){
     return -1;
   }
   return buf.st_mtime;
+}
+
+/*
+** Return the tail of a file pathname.  The tail is the last component
+** of the path.  For example, the tail of "/a/b/c.d" is "c.d".
+*/
+const char *file_tail(const char *z){
+  const char *zTail = z;
+  while( z[0] ){
+    if( z[0]=='/' ) zTail = &z[1];
+    z++;
+  }
+  return zTail;
 }
 
 /*
 ** Copy the content of a file from one place to another.
 */

Modified src/schema.c from [cf525ce8ed] to [353a2ed8b8].

@@ -337,12 +337,12 @@
 @   name TEXT PRIMARY KEY NOT NULL,  -- Primary name of the entry
 @   value CLOB,                      -- Content of the named parameter
 @   CHECK( typeof(name)='text' AND length(name)>=1 )
 @ );
 @
-@ -- Each entry in the vfile table represents a single file or folder
-@ -- that is part of a version.
+@ -- Each entry in the vfile table represents a single file in the
+@ -- current checkout.
 @ --
 @ -- The file.rid field is 0 for files or folders that have been
 @ -- added but not yet committed.
 @ --
 @ -- Vfile.chnged is 0 for unmodified files, 1 for files that have
@@ -359,11 +359,12 @@
 @   vid INTEGER REFERENCES blob,      -- The baseline this file is part of.
 @   chnged INT DEFAULT 0,             -- 0:unchnged 1:edited 2:m-chng 3:m-add
 @   deleted BOOLEAN DEFAULT 0,        -- True if deleted
 @   rid INTEGER,                      -- Originally from this repository record
 @   mrid INTEGER,                     -- Based on this record due to a merge
-@   pathname TEXT,                    -- Full pathname
+@   pathname TEXT,                    -- Full pathname relative to root
+@   origname TEXT                     -- Original pathname. NULL if unchanged
 @   UNIQUE(pathname,vid)
 @ );
 @
 @ -- This table holds a record of uncommitted merges in the local
 @ -- file tree.  If a VFILE entry with id has merged with another