Fossil

Artifact [1c16a914]
Login

Artifact [1c16a914]

Artifact 1c16a914bcf35ae982e012d203fe0fd9bacdc0e7:

Attachment "full-diff.diff" to ticket [e90d38c2] added by anonymous 2010-10-14 16:29:07.
ADDED    motd
Index: src/diffcmd.c
===================================================================
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -51,11 +51,12 @@
 ** command zDiffCmd to do the diffing.
 */
 static void diff_file(
   Blob *pFile1,             /* In memory content to compare from */
   const char *zFile2,       /* On disk content to compare to */
-  const char *zName,        /* Display name of the file */
+  const char *zName1,       /* Display name of the file (from) */
+  const char *zName2,       /* Display name of the file (to) */
   const char *zDiffCmd,     /* Command for comparison */
   int ignoreEolWs           /* Ignore whitespace at end of lines */
 ){
   if( zDiffCmd==0 ){
     Blob out;      /* Diff output text */
@@ -66,11 +67,11 @@
     blob_read_from_file(&file2, zFile2);
 
     /* Compute and output the differences */
     blob_zero(&out);
     text_diff(pFile1, &file2, &out, 5, ignoreEolWs);
-    printf("--- %s\n+++ %s\n", zName, zName);
+    printf("--- %s\n+++ %s\n", zName1, zName2);
     printf("%s\n", blob_str(&out));
 
     /* Release memory resources */
     blob_reset(&file2);
     blob_reset(&out);
@@ -158,10 +159,63 @@
     blob_reset(&cmd);
   }
 }
 
 /*
+** Show the difference for a newly added or deleted file.
+**
+** The difference is the set of edits needed to transform an empty file into
+** pFile or the reverse.
+**
+** fromNull determines the direction of the diff.
+**
+** Use the internal diff logic if zDiffCmd is NULL.  Otherwise call the
+** command zDiffCmd to do the diffing.
+*/
+static void diff_file_removed(
+  Blob *pFile,              /* Content to use */
+  const char *zName,        /* Display name of the file */
+  const char *zDiffCmd,     /* Command for comparison */
+  int ignoreEolWs           /* Ignore whitespace at end of lines */
+){
+  if( zDiffCmd==0 ){
+    Blob out;      /* Diff output text */
+    Blob nullBlob;
+
+    blob_zero(&out);
+    blob_zero(&nullBlob);
+    text_diff(pFile, &nullBlob, &out, 5, ignoreEolWs);
+    printf("--- %s\n+++ /dev/null\n", zName);
+    printf("%s\n", blob_str(&out));
+
+    /* Release memory resources */
+    blob_reset(&out);
+    blob_reset(&nullBlob);
+  }else{
+    Blob cmd;
+    char zTemp[300];
+
+    /* Construct a temporary file names */
+    file_tempname(sizeof(zTemp), zTemp);
+    blob_write_to_file(pFile, zTemp);
+
+    /* Construct the external diff command */
+    blob_zero(&cmd);
+    blob_appendf(&cmd, "%s ", zDiffCmd);
+    shell_escape(&cmd, zTemp);
+    blob_append(&cmd, " /dev/null", 1);
+
+    /* Run the external diff command */
+    portable_system(blob_str(&cmd));
+
+    /* Delete the temporary file and clean up memory used */
+    unlink(zTemp);
+    blob_reset(&cmd);
+  }
+}
+
+/*
 ** Do a diff against a single file named in g.argv[2] from version zFrom
 ** against the same file on disk.
 */
 static void diff_one_against_disk(
   const char *zFrom,        /* Name of file */
@@ -170,11 +224,11 @@
 ){
   Blob fname;
   Blob content;
   file_tree_name(g.argv[2], &fname, 1);
   historical_version_of_file(zFrom, blob_str(&fname), &content, 0);
-  diff_file(&content, g.argv[2], g.argv[2], zDiffCmd, ignoreEolWs);
+  diff_file(&content, g.argv[2], g.argv[2], g.argv[2], zDiffCmd, ignoreEolWs);
   blob_reset(&content);
   blob_reset(&fname);
 }
 
 /*
@@ -183,10 +237,11 @@
 ** files on disk and the check-out on which they are based.
 */
 static void diff_all_against_disk(
   const char *zFrom,        /* Version to difference from */
   const char *zDiffCmd,     /* Use this diff command.  NULL for built-in */
+  int fullDiff,             /* Include added or remove files */
   int ignoreEolWs           /* Ignore end-of-line whitespace */
 ){
   int vid;
   Blob sql;
   Stmt q;
@@ -236,28 +291,45 @@
     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);
     char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
-    if( isDeleted ){
-      printf("DELETED  %s\n", zPathname);
-    }else if( access(zFullName, 0) ){
-      printf("MISSING  %s\n", zPathname);
-    }else if( isNew ){
-      printf("ADDED    %s\n", zPathname);
-    }else if( isChnged==3 ){
-      printf("ADDED_BY_MERGE %s\n", zPathname);
-    }else{
-      int srcid = db_column_int(&q, 4);
+    int isMissing = access(zFullName, 0);
+
+    if( fullDiff || !(isDeleted || isNew || isMissing || isChnged==3) ){
       Blob content;
-      content_get(srcid, &content);
+      const char *zPathnameSrc;
+      if( isNew || isChnged==3 ){
+        blob_zero(&content);
+	zPathnameSrc = "/dev/null";
+      }else{
+        int srcid = db_column_int(&q, 4);
+        content_get(srcid, &content);
+	zPathnameSrc = zPathname;
+      }
       printf("Index: %s\n======================================="
              "============================\n",
              zPathname
       );
-      diff_file(&content, zFullName, zPathname, zDiffCmd, ignoreEolWs);
+      if( isDeleted || isMissing ){
+        diff_file_removed(&content, zPathname, zDiffCmd, ignoreEolWs);
+      }else{
+        diff_file(&content, zFullName, zPathnameSrc, zPathname, zDiffCmd,
+	          ignoreEolWs
+	);
+      }
       blob_reset(&content);
+    }else{
+      if( isDeleted ){
+        printf("DELETED  %s\n", zPathname);
+      }else if( isMissing ){
+        printf("MISSING  %s\n", zPathname);
+      }else if( isNew ){
+        printf("ADDED    %s\n", zPathname);
+      }else if( isChnged==3){
+        printf("ADDED_BY_MERGE %s\n", zPathname);
+      }
     }
     free(zFullName);
   }
   db_finalize(&q);
   db_end_transaction(1);  /* ROLLBACK */
@@ -370,16 +442,18 @@
 ** the "-i" option is a no-op.  The "-i" option converts "gdiff" into "diff".
 */
 void diff_cmd(void){
   int isGDiff;               /* True for gdiff.  False for normal diff */
   int isInternDiff;          /* True for internal diff */
+  int isFullDiff;            /* True for full diffs */
   const char *zFrom;         /* Source version number */
   const char *zTo;           /* Target version number */
   const char *zDiffCmd = 0;  /* External diff command. NULL for internal diff */
 
   isGDiff = g.argv[1][0]=='g';
   isInternDiff = find_option("internal","i",0)!=0;
+  isFullDiff = find_option("full", "f",0)!=0;
   zFrom = find_option("from", "r", 1);
   zTo = find_option("to", 0, 1);
 
   if( zTo==0 ){
     db_must_be_within_tree();
@@ -388,11 +462,11 @@
       zDiffCmd = db_get(isGDiff ? "gdiff-command" : "diff-command", 0);
     }
     if( g.argc==3 ){
       diff_one_against_disk(zFrom, zDiffCmd, 0);
     }else{
-      diff_all_against_disk(zFrom, zDiffCmd, 0);
+      diff_all_against_disk(zFrom, zDiffCmd, isFullDiff, 0);
     }
   }else if( zFrom==0 ){
     fossil_fatal("must use --from if --to is present");
   }else{
     db_find_and_open_repository(1);