[FYI/PATCH] diff: add diff_flush_patch_id()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Call it like this:

unsigned char id[20];
if (diff_flush_patch_id(diff_options, id))
	printf("And the patch id is: %s\n", sha1_to_hex(id));

This patch also adds a switch "--with-patch-id" to the diff family, to
print out the patch id before each patch.

Signed-off-by: Johannes Schindelin <Johannes.Schindelin@xxxxxx>

---


	> > > 	- add a DIFF_FORMAT_PATCH_ID
	> > 
	> > Please don't add any DIFF_FORMAT_*.  I'm cleaning the diff output code
	> > and replacing diff_options.output_format with one-bit flags.
	> 
	> Okay. For the purposes of git-format-patch, this is not needed 
	> anyway, but rather a function which takes two tree objects and 
	> returns the patch id. When you are finished it should be easy to 
	> add this as a display format.

	Timo, I am prepared to redo this patch when you finished
	the cleanup.

 diff.c |  129 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 diff.h |    3 +
 2 files changed, 132 insertions(+), 0 deletions(-)

diff --git a/diff.c b/diff.c
index 5b34f73..1140d54 100644
--- a/diff.c
+++ b/diff.c
@@ -1460,6 +1460,8 @@ int diff_opt_parse(struct diff_options *
 		options->output_format = DIFF_FORMAT_PATCH;
 		options->with_stat = 1;
 	}
+	else if (!strcmp(arg, "--with-patch-id"))
+		options->with_patch_id = 1;
 	else if (!strcmp(arg, "-z"))
 		options->line_termination = 0;
 	else if (!strncmp(arg, "-l", 2))
@@ -2027,12 +2029,139 @@ static void diff_summary(struct diff_fil
 	}
 }
 
+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 */
+int diff_flush_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 = 3;
+		ecb.outf = xdiff_outf;
+		ecb.priv = &data;
+		xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
+	}
+
+	SHA1_Final(sha1, &ctx);
+	return 0;
+}
+
 void diff_flush(struct diff_options *options)
 {
 	struct diff_queue_struct *q = &diff_queued_diff;
 	int i;
 	int diff_output_format = options->output_format;
 	struct diffstat_t *diffstat = NULL;
+	unsigned char sha1[20];
+
+	if (options->with_patch_id && !diff_flush_patch_id(options, sha1))
+		printf("patch-id %s\n", sha1_to_hex(sha1));
 
 	if (diff_output_format == DIFF_FORMAT_DIFFSTAT || options->with_stat) {
 		diffstat = xcalloc(sizeof (struct diffstat_t), 1);
diff --git a/diff.h b/diff.h
index 7d7b6cd..29aac52 100644
--- a/diff.h
+++ b/diff.h
@@ -27,6 +27,7 @@ struct diff_options {
 	unsigned recursive:1,
 		 with_raw:1,
 		 with_stat:1,
+		 with_patch_id:1,
 		 tree_in_recursive:1,
 		 binary:1,
 		 full_index:1,
@@ -185,4 +186,6 @@ extern int run_diff_files(struct rev_inf
 
 extern int run_diff_index(struct rev_info *revs, int cached);
 
+extern int diff_flush_patch_id(struct diff_options *, unsigned char *);
+
 #endif /* DIFF_H */
-- 
1.4.0.g319e-dirty

-
: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]