Check-in [9fd8009007]
Not logged in
Overview

SHA1 Hash:9fd80090073cc5e781c07d5debab7a3a030503cd
Date: 2008-11-09 22:43:04
User: drh
Comment:Bug fix in the "mv" command. Add filename change tracking to the check-in information screens. You must run rebuild on existing respositories when upgrading to this version of fossil.
Timelines: ancestors | descendants | both | trunk
Other Links: files | ZIP archive | manifest

Tags And Properties
Changes
[hide diffs]

Modified src/add.c from [905321226f] to [6a50b3b72e].

@@ -194,10 +194,15 @@
     file_tree_name(g.argv[2], &orig, 1);
     db_multi_exec(
       "INSERT INTO mv VALUES(%B,%B)", &orig, &dest
     );
   }else{
+    if( blob_eq(&dest, ".") ){
+      blob_reset(&dest);
+    }else{
+      blob_append(&dest, "/", 1);
+    }
     for(i=2; i<g.argc-1; i++){
       Blob orig;
       char *zOrig;
       int nOrig;
       file_tree_name(g.argv[i], &orig, 1);
@@ -218,11 +223,11 @@
           zTail = file_tail(zPath);
         }else{
           zTail = &zPath[nOrig+1];
         }
         db_multi_exec(
-          "INSERT INTO mv VALUES('%s','%s/%s')",
+          "INSERT INTO mv VALUES('%s','%s%s')",
           zPath, blob_str(&dest), zTail
         );
       }
       db_finalize(&q);
     }

Modified src/info.c from [a90375841a] to [97b0bae401].

@@ -394,30 +394,50 @@
     style_header("Baseline Information");
     login_anonymous_available();
   }
   db_finalize(&q);
   showTags(rid, "");
-  @ <div class="section">Files Changed</div>
+  @ <div class="section">File Changes</div>
   @ <ul>
   db_prepare(&q,
-     "SELECT name, pid, fid"
+     "SELECT a.name, b.name"
+     "  FROM mlink, filename AS a, filename AS b"
+     " WHERE mid=%d"
+     "   AND a.fnid=mlink.fnid"
+     "   AND b.fnid=mlink.pfnid",
+     rid
+  );
+  while( db_step(&q)==SQLITE_ROW ){
+    const char *zName = db_column_text(&q, 0);
+    const char *zPrior = db_column_text(&q, 1);
+    @ <li><b>Renamed:</b>
+    if( g.okHistory ){
+      @ <a href="%s(g.zBaseURL)/finfo?name=%T(zName)">%h(zPrior)</a> to
+      @ <a href="%s(g.zBaseURL)/finfo?name=%T(zName)">%h(zName)</a></li>
+    }else{
+      @ %h(zPrior) to %h(zName)</li>
+    }
+  }
+  db_finalize(&q);
+  db_prepare(&q,
+     "SELECT name, pid, fid "
      "  FROM mlink, filename"
      " WHERE mid=%d"
+     "   AND fid!=pid"
      "   AND filename.fnid=mlink.fnid",
      rid
   );
   while( db_step(&q)==SQLITE_ROW ){
     const char *zName = db_column_text(&q, 0);
     int pid = db_column_int(&q, 1);
     int fid = db_column_int(&q, 2);
-    @ <li>
     if( pid && fid ){
-      @ <b>Modified:</b>
+      @ <li><b>Modified:</b>
     }else if( fid ){
-      @ <b>Added:</b>
-    }else{
-      @ <b>Deleted:</b>
+      @ <li><b>Added:</b>
+    }else if( pid ){
+      @ <li><b>Deleted:</b>
     }
     if( g.okHistory ){
       @ <a href="%s(g.zBaseURL)/finfo?name=%T(zName)">%h(zName)</a></li>
     }else{
       @ %h(zName)</li>

Modified src/manifest.c from [608b98745d] to [5a2927ef5a].

@@ -65,10 +65,12 @@
   int nFileAlloc;       /* Slots allocated in aFile[] */
   struct {
     char *zName;           /* Name of a file */
     char *zUuid;           /* UUID of the file */
     char *zPerm;           /* File permissions */
+    char *zPrior;          /* Prior name if the name was changed */
+    int iRename;           /* index of renamed name in prior/next manifest */
   } *aFile;
   int nParent;          /* Number of parents */
   int nParentAlloc;     /* Slots allocated in azParent[] */
   char **azParent;      /* UUIDs of parents */
   int nCChild;          /* Number of cluster children */
@@ -300,10 +302,12 @@
         if( zPriorName[0] ){
           defossilize(zPriorName);
           if( !file_is_simple_pathname(zPriorName) ){
             goto manifest_syntax_error;
           }
+        }else{
+          zPriorName = 0;
         }
         if( p->nFile>=p->nFileAlloc ){
           p->nFileAlloc = p->nFileAlloc*2 + 10;
           p->aFile = realloc(p->aFile, p->nFileAlloc*sizeof(p->aFile[0]) );
           if( p->aFile==0 ) fossil_panic("out of memory");
@@ -310,10 +314,12 @@
         }
         i = p->nFile++;
         p->aFile[i].zName = zName;
         p->aFile[i].zUuid = zUuid;
         p->aFile[i].zPerm = zPerm;
+        p->aFile[i].zPrior = zPriorName;
+        p->aFile[i].iRename = -1;
         if( i>0 && strcmp(p->aFile[i-1].zName, zName)>=0 ){
           goto manifest_syntax_error;
         }
         break;
       }
@@ -701,18 +707,28 @@
 */
 static void add_one_mlink(
   int mid,                  /* The record ID of the manifest */
   const char *zFromUuid,    /* UUID for the mlink.pid field */
   const char *zToUuid,      /* UUID for the mlink.fid field */
-  const char *zFilename     /* Filename */
+  const char *zFilename,    /* Filename */
+  const char *zPrior        /* Previous filename.  NULL if unchanged */
 ){
-  int fnid, pid, fid;
+  int fnid, pfnid, pid, fid;
 
   fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zFilename);
   if( fnid==0 ){
     db_multi_exec("INSERT INTO filename(name) VALUES(%Q)", zFilename);
     fnid = db_last_insert_rowid();
+  }
+  if( zPrior==0 ){
+    pfnid = 0;
+  }else{
+    pfnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zPrior);
+    if( pfnid==0 ){
+      db_multi_exec("INSERT INTO filename(name) VALUES(%Q)", zPrior);
+      pfnid = db_last_insert_rowid();
+    }
   }
   if( zFromUuid==0 ){
     pid = 0;
   }else{
     pid = uuid_to_rid(zFromUuid, 1);
@@ -721,22 +737,50 @@
     fid = 0;
   }else{
     fid = uuid_to_rid(zToUuid, 1);
   }
   db_multi_exec(
-    "INSERT INTO mlink(mid,pid,fid,fnid)"
-    "VALUES(%d,%d,%d,%d)", mid, pid, fid, fnid
+    "INSERT INTO mlink(mid,pid,fid,fnid,pfnid)"
+    "VALUES(%d,%d,%d,%d,%d)", mid, pid, fid, fnid, pfnid
   );
   if( pid && fid ){
     content_deltify(pid, fid, 0);
   }
 }
 
 /*
-** Add mlink table entries associated with manifest cid.
-** There is an mlink entry for every file that changed going
-** from pid to cid.
+** Locate a file named zName in the aFile[] array of the given
+** manifest.  We assume that filenames are in sorted order.
+** Use a binary search.  Return turn the index of the matching
+** entry.  Or return -1 if not found.
+*/
+static int find_file_in_manifest(Manifest *p, const char *zName){
+  int lwr, upr;
+  int c;
+  int i;
+  lwr = 0;
+  upr = p->nFile - 1;
+  while( lwr<=upr ){
+    i = (lwr+upr)/2;
+    c = strcmp(p->aFile[i].zName, zName);
+    if( c<0 ){
+      lwr = i+1;
+    }else if( c>0 ){
+      upr = i-1;
+    }else{
+      return i;
+    }
+  }
+  return -1;
+}
+
+/*
+** Add mlink table entries associated with manifest cid.  The
+** parent manifest is pid.
+**
+** A single mlink entry is added for every file that changed content
+** and/or name going from pid to cid.
 **
 ** Deleted files have mlink.fid=0.
 ** Added files have mlink.pid=0.
 ** Edited files have both mlink.pid!=0 and mlink.fid!=0
 */
@@ -757,33 +801,64 @@
     content_get(cid, &otherContent);
   }
   if( blob_size(&otherContent)==0 ) return;
   if( manifest_parse(&other, &otherContent)==0 ) return;
   content_deltify(pid, cid, 0);
+
+  /* Use the iRename fields to find the cross-linkage between
+  ** renamed files.  */
+  for(j=0; j<pChild->nFile; j++){
+    const char *zPrior = pChild->aFile[j].zPrior;
+    if( zPrior && zPrior[0] ){
+      i = find_file_in_manifest(pParent, zPrior);
+      if( i>=0 ){
+        pChild->aFile[j].iRename = i;
+        pParent->aFile[i].iRename = j;
+      }
+    }
+  }
+
+  /* Construct the mlink entries */
   for(i=j=0; i<pParent->nFile && j<pChild->nFile; ){
-    int c = strcmp(pParent->aFile[i].zName, pChild->aFile[j].zName);
-    if( c<0 ){
-      add_one_mlink(cid, pParent->aFile[i].zUuid, 0, pParent->aFile[i].zName);
+    int c;
+    if( pParent->aFile[i].iRename>=0 ){
+      i++;
+    }else if( (c = strcmp(pParent->aFile[i].zName, pChild->aFile[j].zName))<0 ){
+      add_one_mlink(cid, pParent->aFile[i].zUuid,0,pParent->aFile[i].zName,0);
       i++;
     }else if( c>0 ){
-      add_one_mlink(cid, 0, pChild->aFile[j].zUuid, pChild->aFile[j].zName);
+      int rn = pChild->aFile[j].iRename;
+      if( rn>=0 ){
+        add_one_mlink(cid, pParent->aFile[rn].zUuid, pChild->aFile[j].zUuid,
+                      pChild->aFile[j].zName, pParent->aFile[rn].zName);
+      }else{
+        add_one_mlink(cid, 0, pChild->aFile[j].zUuid, pChild->aFile[j].zName,0);
+      }
       j++;
     }else{
       if( strcmp(pParent->aFile[i].zUuid, pChild->aFile[j].zUuid)!=0 ){
-      add_one_mlink(cid, pParent->aFile[i].zUuid, pChild->aFile[j].zUuid,
-                    pChild->aFile[j].zName);
+        add_one_mlink(cid, pParent->aFile[i].zUuid, pChild->aFile[j].zUuid,
+                      pChild->aFile[j].zName, 0);
       }
       i++;
       j++;
     }
   }
   while( i<pParent->nFile ){
-    add_one_mlink(cid, pParent->aFile[i].zUuid, 0, pParent->aFile[i].zName);
+    if( pParent->aFile[i].iRename<0 ){
+      add_one_mlink(cid, pParent->aFile[i].zUuid, 0, pParent->aFile[i].zName,0);
+    }
     i++;
   }
   while( j<pChild->nFile ){
-    add_one_mlink(cid, 0, pChild->aFile[j].zUuid, pChild->aFile[j].zName);
+    int rn = pChild->aFile[j].iRename;
+    if( rn>=0 ){
+      add_one_mlink(cid, pParent->aFile[rn].zUuid, pChild->aFile[j].zUuid,
+                    pChild->aFile[j].zName, pParent->aFile[rn].zName);
+    }else{
+      add_one_mlink(cid, 0, pChild->aFile[j].zUuid, pChild->aFile[j].zName,0);
+    }
     j++;
   }
   manifest_clear(&other);
 }
 

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

@@ -178,11 +178,12 @@
 @ --
 @ CREATE TABLE mlink(
 @   mid INTEGER REFERENCES blob,        -- Manifest ID where change occurs
 @   pid INTEGER REFERENCES blob,        -- File ID in parent manifest
 @   fid INTEGER REFERENCES blob,        -- Changed file ID in this manifest
-@   fnid INTEGER REFERENCES filename    -- Name of the file
+@   fnid INTEGER REFERENCES filename,   -- Name of the file
+@   pfnid INTEGER REFERENCES filename   -- Previous name. 0 if unchanged
 @ );
 @ CREATE INDEX mlink_i1 ON mlink(mid);
 @ CREATE INDEX mlink_i2 ON mlink(fnid);
 @ CREATE INDEX mlink_i3 ON mlink(fid);
 @ CREATE INDEX mlink_i4 ON mlink(pid);