Merge branch 'th/diff'
authorJunio C Hamano <junkio@cox.net>
Wed, 5 Jul 2006 23:31:24 +0000 (16:31 -0700)
committerJunio C Hamano <junkio@cox.net>
Wed, 5 Jul 2006 23:31:24 +0000 (16:31 -0700)
* th/diff:
  builtin-diff: turn recursive on when defaulting to --patch format.
  t4013: note improvements brought by the new output code.
  t4013: add format-patch tests.
  format-patch: fix diff format option implementation
  combine-diff.c: type sanity.
  t4013 test updates for new output code.
  Fix some more diff options changes.
  Fix diff-tree -s
  log --raw: Don't descend into subdirectories by default
  diff-tree: Use ---\n as a message separator
  Print empty line between raw, stat, summary and patch
  t4013: add more tests around -c and --cc
  whatchanged: Default to DIFF_FORMAT_RAW
  Don't xcalloc() struct diffstat_t
  Add msg_sep to diff_options
  DIFF_FORMAT_RAW is not default anymore
  Set default diff output format after parsing command line
  Make --raw option available for all diff commands
  Merge with_raw, with_stat and summary variables to output_format
  t4013: add tests for diff/log family output options.

1  2 
builtin-log.c
combine-diff.c
diff.c
diff.h
revision.c

diff --cc builtin-log.c
Simple merge
diff --cc combine-diff.c
Simple merge
diff --cc diff.c
index 428ff786ebdbd48a47ae5faf4c65c01e38403ad4,1c131ff4dcdab52abec6f182e1a9310820532189..507e4019e8bc2764daaf31ce76112ab509895704
--- 1/diff.c
--- 2/diff.c
+++ b/diff.c
@@@ -2104,197 -2095,96 +2095,235 @@@ static void diff_summary(struct diff_fi
        }
  }
  
- void diff_flush(struct diff_options *options)
 +struct patch_id_t {
 +      struct xdiff_emit_state xm;
 +      SHA_CTX *ctx;
 +      int patchlen;
 +};
 +
 +static int remove_space(char *line, int len)
 +{
 +      int i;
 +        char *dst = line;
 +        unsigned char c;
 +
 +        for (i = 0; i < len; i++)
 +                if (!isspace((c = line[i])))
 +                        *dst++ = c;
 +
 +        return dst - line;
 +}
 +
 +static void patch_id_consume(void *priv, char *line, unsigned long len)
 +{
 +      struct patch_id_t *data = priv;
 +      int new_len;
 +
 +      /* Ignore line numbers when computing the SHA1 of the patch */
 +      if (!strncmp(line, "@@ -", 4))
 +              return;
 +
 +      new_len = remove_space(line, len);
 +
 +      SHA1_Update(data->ctx, line, new_len);
 +      data->patchlen += new_len;
 +}
 +
 +/* returns 0 upon success, and writes result into sha1 */
 +static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1)
 +{
 +      struct diff_queue_struct *q = &diff_queued_diff;
 +      int i;
 +      SHA_CTX ctx;
 +      struct patch_id_t data;
 +      char buffer[PATH_MAX * 4 + 20];
 +
 +      SHA1_Init(&ctx);
 +      memset(&data, 0, sizeof(struct patch_id_t));
 +      data.ctx = &ctx;
 +      data.xm.consume = patch_id_consume;
 +
 +      for (i = 0; i < q->nr; i++) {
 +              xpparam_t xpp;
 +              xdemitconf_t xecfg;
 +              xdemitcb_t ecb;
 +              mmfile_t mf1, mf2;
 +              struct diff_filepair *p = q->queue[i];
 +              int len1, len2;
 +
 +              if (p->status == 0)
 +                      return error("internal diff status error");
 +              if (p->status == DIFF_STATUS_UNKNOWN)
 +                      continue;
 +              if (diff_unmodified_pair(p))
 +                      continue;
 +              if ((DIFF_FILE_VALID(p->one) && S_ISDIR(p->one->mode)) ||
 +                  (DIFF_FILE_VALID(p->two) && S_ISDIR(p->two->mode)))
 +                      continue;
 +              if (DIFF_PAIR_UNMERGED(p))
 +                      continue;
 +
 +              diff_fill_sha1_info(p->one);
 +              diff_fill_sha1_info(p->two);
 +              if (fill_mmfile(&mf1, p->one) < 0 ||
 +                              fill_mmfile(&mf2, p->two) < 0)
 +                      return error("unable to read files to diff");
 +
 +              /* Maybe hash p->two? into the patch id? */
 +              if (mmfile_is_binary(&mf2))
 +                      continue;
 +
 +              len1 = remove_space(p->one->path, strlen(p->one->path));
 +              len2 = remove_space(p->two->path, strlen(p->two->path));
 +              if (p->one->mode == 0)
 +                      len1 = snprintf(buffer, sizeof(buffer),
 +                                      "diff--gita/%.*sb/%.*s"
 +                                      "newfilemode%06o"
 +                                      "---/dev/null"
 +                                      "+++b/%.*s",
 +                                      len1, p->one->path,
 +                                      len2, p->two->path,
 +                                      p->two->mode,
 +                                      len2, p->two->path);
 +              else if (p->two->mode == 0)
 +                      len1 = snprintf(buffer, sizeof(buffer),
 +                                      "diff--gita/%.*sb/%.*s"
 +                                      "deletedfilemode%06o"
 +                                      "---a/%.*s"
 +                                      "+++/dev/null",
 +                                      len1, p->one->path,
 +                                      len2, p->two->path,
 +                                      p->one->mode,
 +                                      len1, p->one->path);
 +              else
 +                      len1 = snprintf(buffer, sizeof(buffer),
 +                                      "diff--gita/%.*sb/%.*s"
 +                                      "---a/%.*s"
 +                                      "+++b/%.*s",
 +                                      len1, p->one->path,
 +                                      len2, p->two->path,
 +                                      len1, p->one->path,
 +                                      len2, p->two->path);
 +              SHA1_Update(&ctx, buffer, len1);
 +
 +              xpp.flags = XDF_NEED_MINIMAL;
 +              xecfg.ctxlen = 3;
 +              xecfg.flags = XDL_EMIT_FUNCNAMES;
 +              ecb.outf = xdiff_outf;
 +              ecb.priv = &data;
 +              xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
 +      }
 +
 +      SHA1_Final(sha1, &ctx);
 +      return 0;
 +}
 +
 +int diff_flush_patch_id(struct diff_options *options, unsigned char *sha1)
 +{
 +      struct diff_queue_struct *q = &diff_queued_diff;
 +      int i;
 +      int result = diff_get_patch_id(options, sha1);
 +
 +      for (i = 0; i < q->nr; i++)
 +              diff_free_filepair(q->queue[i]);
 +
 +      free(q->queue);
 +      q->queue = NULL;
 +      q->nr = q->alloc = 0;
 +
 +      return result;
 +}
 +
+ static int is_summary_empty(const struct diff_queue_struct *q)
  {
-       struct diff_queue_struct *q = &diff_queued_diff;
        int i;
-       int diff_output_format = options->output_format;
-       struct diffstat_t *diffstat = NULL;
  
-       if (diff_output_format == DIFF_FORMAT_DIFFSTAT || options->with_stat) {
-               diffstat = xcalloc(sizeof (struct diffstat_t), 1);
-               diffstat->xm.consume = diffstat_consume;
+       for (i = 0; i < q->nr; i++) {
+               const struct diff_filepair *p = q->queue[i];
+               switch (p->status) {
+               case DIFF_STATUS_DELETED:
+               case DIFF_STATUS_ADDED:
+               case DIFF_STATUS_COPIED:
+               case DIFF_STATUS_RENAMED:
+                       return 0;
+               default:
+                       if (p->score)
+                               return 0;
+                       if (p->one->mode && p->two->mode &&
+                           p->one->mode != p->two->mode)
+                               return 0;
+                       break;
+               }
        }
+       return 1;
+ }
+ void diff_flush(struct diff_options *options)
+ {
+       struct diff_queue_struct *q = &diff_queued_diff;
+       int i, output_format = options->output_format;
+       int separator = 0;
+       /*
+        * Order: raw, stat, summary, patch
+        * or:    name/name-status/checkdiff (other bits clear)
+        */
+       if (!q->nr)
+               goto free_queue;
  
-       if (options->with_raw) {
+       if (output_format & (DIFF_FORMAT_RAW |
+                            DIFF_FORMAT_NAME |
+                            DIFF_FORMAT_NAME_STATUS |
+                            DIFF_FORMAT_CHECKDIFF)) {
                for (i = 0; i < q->nr; i++) {
                        struct diff_filepair *p = q->queue[i];
-                       flush_one_pair(p, DIFF_FORMAT_RAW, options, NULL);
+                       if (check_pair_status(p))
+                               flush_one_pair(p, options);
                }
-               putchar(options->line_termination);
+               separator++;
        }
-       if (options->with_stat) {
+       if (output_format & DIFF_FORMAT_DIFFSTAT) {
+               struct diffstat_t diffstat;
+               memset(&diffstat, 0, sizeof(struct diffstat_t));
+               diffstat.xm.consume = diffstat_consume;
                for (i = 0; i < q->nr; i++) {
                        struct diff_filepair *p = q->queue[i];
-                       flush_one_pair(p, DIFF_FORMAT_DIFFSTAT, options,
-                                      diffstat);
+                       if (check_pair_status(p))
+                               diff_flush_stat(p, options, &diffstat);
                }
-               show_stats(diffstat);
-               free(diffstat);
-               diffstat = NULL;
-               if (options->summary)
-                       for (i = 0; i < q->nr; i++)
-                               diff_summary(q->queue[i]);
-               if (options->stat_sep)
-                       fputs(options->stat_sep, stdout);
-               else
-                       putchar(options->line_termination);
-       }
-       for (i = 0; i < q->nr; i++) {
-               struct diff_filepair *p = q->queue[i];
-               flush_one_pair(p, diff_output_format, options, diffstat);
+               show_stats(&diffstat);
+               separator++;
        }
  
-       if (diffstat) {
-               show_stats(diffstat);
-               free(diffstat);
+       if (output_format & DIFF_FORMAT_SUMMARY && !is_summary_empty(q)) {
+               for (i = 0; i < q->nr; i++)
+                       diff_summary(q->queue[i]);
+               separator++;
        }
  
-       for (i = 0; i < q->nr; i++) {
-               if (diffstat && options->summary)
-                       diff_summary(q->queue[i]);
-               diff_free_filepair(q->queue[i]);
+       if (output_format & DIFF_FORMAT_PATCH) {
+               if (separator) {
+                       if (options->stat_sep) {
+                               /* attach patch instead of inline */
+                               fputs(options->stat_sep, stdout);
+                       } else {
+                               putchar(options->line_termination);
+                       }
+               }
+               for (i = 0; i < q->nr; i++) {
+                       struct diff_filepair *p = q->queue[i];
+                       if (check_pair_status(p))
+                               diff_flush_patch(p, options);
+               }
        }
  
+       for (i = 0; i < q->nr; i++)
+               diff_free_filepair(q->queue[i]);
+ free_queue:
        free(q->queue);
        q->queue = NULL;
        q->nr = q->alloc = 0;
diff --cc diff.h
Simple merge
diff --cc revision.c
Simple merge