From patchwork Tue Mar 19 18:35:36 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Kristoffer Haugsbakk X-Patchwork-Id: 13597020 Received: from wfhigh5-smtp.messagingengine.com (wfhigh5-smtp.messagingengine.com [64.147.123.156]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C589D39851 for ; Tue, 19 Mar 2024 18:37:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=64.147.123.156 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710873426; cv=none; b=TPbiB3YsZAEPT3dDBikmwqLLkty/eqsUYm3Yk5PONAMdWePHU0dF3GZeX9o3yKwrNDyWcuLNEmHN9BYUORO0AvEuxIgb+vm84RMkxIokd8K5W8IDpHeO0K36aCTCzDMWFkaPHRbeMTTDHRQw8+otI4KPY/pCf2TedCWuw46GiR8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710873426; c=relaxed/simple; bh=CvYZP08pp7iX6MoRF1DvRrtRZ2ygkfRhZ3MddLPvpGI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=leXVfddon7suk7JGA6Ba6DGdVsr3gIo6Rwpb1Sz+Lgu9x3ZzVarOlvDq9L0SYTFBvDIPWgMNOv6oNm+WAl50zb1gw3E3ibRu/TL0wKMLKh1dqQhQu44hCiM5ifTwkx2yPm0leSuZk0hhkRYLRW3GCmtP8PxSarJZx7q4qwiIMOY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=khaugsbakk.name; spf=pass smtp.mailfrom=khaugsbakk.name; dkim=pass (2048-bit key) header.d=khaugsbakk.name header.i=@khaugsbakk.name header.b=nAjUPLFg; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=MMxkJt4l; arc=none smtp.client-ip=64.147.123.156 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=khaugsbakk.name Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=khaugsbakk.name Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=khaugsbakk.name header.i=@khaugsbakk.name header.b="nAjUPLFg"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="MMxkJt4l" Received: from compute4.internal (compute4.nyi.internal [10.202.2.44]) by mailfhigh.west.internal (Postfix) with ESMTP id B5E7218000F5; Tue, 19 Mar 2024 14:37:02 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute4.internal (MEProxy); Tue, 19 Mar 2024 14:37:03 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=khaugsbakk.name; h=cc:cc:content-transfer-encoding:content-type:content-type :date:date:from:from:in-reply-to:in-reply-to:message-id :mime-version:references:reply-to:subject:subject:to:to; s=fm1; t=1710873422; x=1710959822; bh=o8/07PNSFS3lUY5D2D3ZdzcJL6QZzjEg GUT3AB97b14=; b=nAjUPLFgsPEkL2GqoT873ExxHI8njE10qzHU03XeMbLivhkn h4lrqNXwVMpRTf+cd0jK4frkH8yD1CCWYadQ9q5HVNPvz3BAXFIZB7C+ZqnPFicC l9npVbuz2VEli4MvprAAC2xJO1vWby3wCW38nISmZ6NiZmKX0yb7X1RFvMb0RZ5y 3b0aD9VkDrlJOymQ6C01TLBPwz0++kOBHx1E+ykDNHGlz+mmHhhrZVIiGs3YnPJk QbnO756qjRhEdOdwk9cYWyPcLvB9kWJw+b+0pBFwoV6E4ohZuJXesTokn5bWPAl8 e37d5+nUzNSCk1Ax7MR6teAw4dQwOohJ/+Auxw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:content-type:date:date:feedback-id:feedback-id :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to:x-me-proxy:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm2; t=1710873422; x= 1710959822; bh=o8/07PNSFS3lUY5D2D3ZdzcJL6QZzjEgGUT3AB97b14=; b=M MxkJt4lxWjuRb1faQn68ZwgsRvTO7Vh29GZcgmVPZC8qFVJAnJ+o2dBkw8+fnjeY GG3nXVmTu5/h85Ltxio62UbLCtaAy5Xga43CIdLhrToq5+ZyOAdcLwdZmX2oImma M4/ozNHXdvcoO1jBnF3GJeWZmP74i1jLCcg1K+1vsnWD9MCW9obNLF3YLPvRs8pJ 9XAOPEekEo9BE8zbShxiEY68vcPBmTRf3tpUc1pWr9mjJP9Fl/d9SeiK1lg3x6es Wz4Zfo0x/P4tUYIiNc0ieHvItzRIXM6SGzDHAbq8P3c2WQCvOlR7quHCUpg6Uzk6 uWRfw4+d32nU6ElWYyKYw== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvledrledtgdeklecutefuodetggdotefrodftvf curfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfghnecu uegrihhlohhuthemuceftddtnecunecujfgurhephffvvefufffkofgjfhggtgfgsehtke ertdertdejnecuhfhrohhmpefmrhhishhtohhffhgvrhcujfgruhhgshgsrghkkhcuoegt ohguvgeskhhhrghughhssggrkhhkrdhnrghmvgeqnecuggftrfgrthhtvghrnhepueeiue ffuefftefhhfefleelhfeuheettedtheevgeejteehgfevffeugffglefhnecuffhomhgr ihhnpehkvghrnhgvlhdrohhrghenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmh epmhgrihhlfhhrohhmpegtohguvgeskhhhrghughhssggrkhhkrdhnrghmvg X-ME-Proxy: Feedback-ID: i2671468f:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Tue, 19 Mar 2024 14:37:00 -0400 (EDT) From: Kristoffer Haugsbakk To: git@vger.kernel.org Cc: Kristoffer Haugsbakk , Jeff King Subject: [PATCH v2 1/3] revision: add a per-email field to rev-info Date: Tue, 19 Mar 2024 19:35:36 +0100 Message-ID: <9a7102b708e4afe78447e48e4baf5b6d66ca50d1.1710873210.git.code@khaugsbakk.name> X-Mailer: git-send-email 2.44.0.144.g29ae9861142 In-Reply-To: References: Precedence: bulk X-Mailing-List: git@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Commit-Hash: 9a7102b708e4afe78447e48e4baf5b6d66ca50d1 Add `pe_header` to `rev_info` to store per-email headers. The next commit will add an option to `format-patch` which will allow the user to store headers per-email; a complement to options like `--add-header`. To make this possible we need a new field to store these headers. We also need to take ownership of `extra_headers_p` in `log_write_email_headers`; facilitate this by removing constness from the relevant pointers. Helped-by: Jeff King Signed-off-by: Kristoffer Haugsbakk --- Notes (series): v2: • Replaces “log-tree: take ownership of pointer” • Link: https://lore.kernel.org/git/3b12a8cf393b6d8f0877fd7d87173c565d7d5a90.1709841147.git.code@khaugsbakk.name/ • More preliminary work • Link: https://lore.kernel.org/git/20240313065454.GB125150@coredump.intra.peff.net/ log-tree.c | 21 +++++++++++---------- log-tree.h | 2 +- pretty.h | 2 +- revision.h | 4 +++- 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/log-tree.c b/log-tree.c index e5438b029d9..f6cdde6e8f3 100644 --- a/log-tree.c +++ b/log-tree.c @@ -470,16 +470,21 @@ void fmt_output_email_subject(struct strbuf *sb, struct rev_info *opt) } void log_write_email_headers(struct rev_info *opt, struct commit *commit, - const char **extra_headers_p, + char **extra_headers_p, int *need_8bit_cte_p, int maybe_multipart) { - const char *extra_headers = opt->extra_headers; + struct strbuf headers = STRBUF_INIT; const char *name = oid_to_hex(opt->zero_commit ? null_oid() : &commit->object.oid); *need_8bit_cte_p = 0; /* unknown */ + if (opt->extra_headers) + strbuf_addstr(&headers, opt->extra_headers); + if (opt->pe_headers) + strbuf_addstr(&headers, opt->pe_headers); + fprintf(opt->diffopt.file, "From %s Mon Sep 17 00:00:00 2001\n", name); graph_show_oneline(opt->graph); if (opt->message_id) { @@ -496,16 +501,13 @@ void log_write_email_headers(struct rev_info *opt, struct commit *commit, graph_show_oneline(opt->graph); } if (opt->mime_boundary && maybe_multipart) { - static struct strbuf subject_buffer = STRBUF_INIT; static struct strbuf buffer = STRBUF_INIT; struct strbuf filename = STRBUF_INIT; *need_8bit_cte_p = -1; /* NEVER */ - strbuf_reset(&subject_buffer); strbuf_reset(&buffer); - strbuf_addf(&subject_buffer, - "%s" + strbuf_addf(&headers, "MIME-Version: 1.0\n" "Content-Type: multipart/mixed;" " boundary=\"%s%s\"\n" @@ -516,10 +518,8 @@ void log_write_email_headers(struct rev_info *opt, struct commit *commit, "Content-Type: text/plain; " "charset=UTF-8; format=fixed\n" "Content-Transfer-Encoding: 8bit\n\n", - extra_headers ? extra_headers : "", mime_boundary_leader, opt->mime_boundary, mime_boundary_leader, opt->mime_boundary); - extra_headers = subject_buffer.buf; if (opt->numbered_files) strbuf_addf(&filename, "%d", opt->nr); @@ -539,7 +539,7 @@ void log_write_email_headers(struct rev_info *opt, struct commit *commit, opt->diffopt.stat_sep = buffer.buf; strbuf_release(&filename); } - *extra_headers_p = extra_headers; + *extra_headers_p = headers.len ? strbuf_detach(&headers, NULL) : NULL; } static void show_sig_lines(struct rev_info *opt, int status, const char *bol) @@ -678,7 +678,7 @@ void show_log(struct rev_info *opt) struct log_info *log = opt->loginfo; struct commit *commit = log->commit, *parent = log->parent; int abbrev_commit = opt->abbrev_commit ? opt->abbrev : the_hash_algo->hexsz; - const char *extra_headers = opt->extra_headers; + char *extra_headers = opt->extra_headers; struct pretty_print_context ctx = {0}; opt->loginfo = NULL; @@ -857,6 +857,7 @@ void show_log(struct rev_info *opt) strbuf_release(&msgbuf); free(ctx.notes_message); + free(ctx.after_subject); if (cmit_fmt_is_mail(ctx.fmt) && opt->idiff_oid1) { struct diff_queue_struct dq; diff --git a/log-tree.h b/log-tree.h index 41c776fea52..94978e2c838 100644 --- a/log-tree.h +++ b/log-tree.h @@ -29,7 +29,7 @@ void format_decorations(struct strbuf *sb, const struct commit *commit, int use_color, const struct decoration_options *opts); void show_decorations(struct rev_info *opt, struct commit *commit); void log_write_email_headers(struct rev_info *opt, struct commit *commit, - const char **extra_headers_p, + char **extra_headers_p, int *need_8bit_cte_p, int maybe_multipart); void load_ref_decorations(struct decoration_filter *filter, int flags); diff --git a/pretty.h b/pretty.h index 421209e9ec2..bdce3191875 100644 --- a/pretty.h +++ b/pretty.h @@ -35,7 +35,7 @@ struct pretty_print_context { */ enum cmit_fmt fmt; int abbrev; - const char *after_subject; + char *after_subject; int preserve_subject; struct date_mode date_mode; unsigned date_mode_explicit:1; diff --git a/revision.h b/revision.h index 94c43138bc3..95e92397a7a 100644 --- a/revision.h +++ b/revision.h @@ -290,7 +290,9 @@ struct rev_info { struct ident_split from_ident; struct string_list *ref_message_ids; int add_signoff; - const char *extra_headers; + char *extra_headers; + /* per-email headers */ + char *pe_headers; const char *log_reencode; const char *subject_prefix; int patch_name_max; From patchwork Tue Mar 19 18:35:37 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Kristoffer Haugsbakk X-Patchwork-Id: 13597021 Received: from wfhigh5-smtp.messagingengine.com (wfhigh5-smtp.messagingengine.com [64.147.123.156]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C7D5F39ACD for ; Tue, 19 Mar 2024 18:37:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=64.147.123.156 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710873428; cv=none; b=sK0P3v9/QNNXJmzmENBudCvtvuY3gK9nJmOAag7AlrIqbIwM3gjV8+B7pTMDxc8iWhoKsUXdstol0gHFK/vUZBSnCvQj4/aITP/C517em8UXjKsJaNyR3QizyCdeMiOyOA319XjT6zAAhjAGcN/sRfO+ElWv9BAPFQq+6lKCakg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710873428; c=relaxed/simple; bh=gSuG3iMxscHnEw+s9HYdSeITTtlTzp7XCxd3ji0GHMA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=KBWnljaTP/yHKhHyjYQQM0fy1y2GQ+HEVL6Z7Gb7TEaIqyL82YORHJAcf3imtzPW4S2EDHz9WWbCbWuMg4GQ79xdtQ2EIzNZTKomt3V8qQl5JI1biDOOw+FT/Ihb1YD0zi7ZVDV0j6T4uxJkIvI2ReX7aRPuIKK57Muo2x1PRug= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=khaugsbakk.name; spf=pass smtp.mailfrom=khaugsbakk.name; dkim=pass (2048-bit key) header.d=khaugsbakk.name header.i=@khaugsbakk.name header.b=jLQQqkfL; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=aKuUuzi3; arc=none smtp.client-ip=64.147.123.156 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=khaugsbakk.name Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=khaugsbakk.name Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=khaugsbakk.name header.i=@khaugsbakk.name header.b="jLQQqkfL"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="aKuUuzi3" Received: from compute6.internal (compute6.nyi.internal [10.202.2.47]) by mailfhigh.west.internal (Postfix) with ESMTP id AF8D518000B9; Tue, 19 Mar 2024 14:37:04 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute6.internal (MEProxy); Tue, 19 Mar 2024 14:37:04 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=khaugsbakk.name; h=cc:cc:content-transfer-encoding:content-type:content-type :date:date:from:from:in-reply-to:in-reply-to:message-id :mime-version:references:reply-to:subject:subject:to:to; s=fm1; t=1710873424; x=1710959824; bh=PpYCCzjSZOJM574j+x2YEkJ5BSyiGAPw KTjNWZTw/yk=; b=jLQQqkfLZQ7aP90xJvggLC9NE0illTjAcszaGJAoExVa5gZg /WoiQWufApgMz80P+IJzkkVN+ZToGT5GxVqT8P8DKchb2QZqlVBHFk9ONuly+F7J FEgbRx+4lXKDk9HFJTP9xcCkPPUk/wBW1e4eW+/YI5Agxctk9F/+AgCD4+5kZfmE 2X3Z1eQwKkGwOvK65S8K6GxIXac52DnSmz0lSNsmnqGb2H6qbpNtuEa3zqCfOn18 WoWxiSkF2GVFY4wqzTol635UF7sWISAINxPl2aOLWKBNauRWG8gy2dv0OBtBs4Xc /PM32fntz5Z+SQc7btAYMYlMTBWrwXO+mfaBww== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:content-type:date:date:feedback-id:feedback-id :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to:x-me-proxy:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm2; t=1710873424; x= 1710959824; bh=PpYCCzjSZOJM574j+x2YEkJ5BSyiGAPwKTjNWZTw/yk=; b=a KuUuzi3Vsv+gyqHkz7WtEtkP0F0t1M00Z9OrMNz/nnXSBfu7QmutpgzIrt8sk0pJ 10wNRoLQUxJJF77TKdhlwGDrOStuREYArUIe7G4G1M2JkPRRyGas1BDJAqbIuCaR tBZUGHfrYOAqCcel/JN0mh+46wm4t/b9Y1zw3u4xoJw9t3Yiao5IlLqpy2DkIb4o wYmEzipSl0DUrcfFu3UhQMc7PSaDlGH+QKjIkOoVSSvf3AIgkuKKHMx4HoAmiQaY iNNRqN7qDFxJxt4/C/Ssw31/pyRnFAFxiT3Hpa9Hk8L2Fbxk5DsoaGekJCz8iALR XqJnk6Y3tAkp8r8BCZ+2A== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvledrledtgdeklecutefuodetggdotefrodftvf curfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfghnecu uegrihhlohhuthemuceftddtnecunecujfgurhephffvvefufffkofgjfhggtgfgsehtke ertdertdejnecuhfhrohhmpefmrhhishhtohhffhgvrhcujfgruhhgshgsrghkkhcuoegt ohguvgeskhhhrghughhssggrkhhkrdhnrghmvgeqnecuggftrfgrthhtvghrnhepueeiue ffuefftefhhfefleelhfeuheettedtheevgeejteehgfevffeugffglefhnecuffhomhgr ihhnpehkvghrnhgvlhdrohhrghenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmh epmhgrihhlfhhrohhmpegtohguvgeskhhhrghughhssggrkhhkrdhnrghmvg X-ME-Proxy: Feedback-ID: i2671468f:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Tue, 19 Mar 2024 14:37:03 -0400 (EDT) From: Kristoffer Haugsbakk To: git@vger.kernel.org Cc: Kristoffer Haugsbakk Subject: [PATCH v2 2/3] format-patch: teach `--header-cmd` Date: Tue, 19 Mar 2024 19:35:37 +0100 Message-ID: <8c511797a476a86bf231595d6d7f5db790f12731.1710873210.git.code@khaugsbakk.name> X-Mailer: git-send-email 2.44.0.144.g29ae9861142 In-Reply-To: References: Precedence: bulk X-Mailing-List: git@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Commit-Hash: 8c511797a476a86bf231595d6d7f5db790f12731 X-Previous-Commits: f405a0140b5655bc66a0a7a603517a421d7669cf 3b12a8cf393b6d8f0877fd7d87173c565d7d5a90 Teach git-format-patch(1) `--header-cmd` (with negation) and the accompanying config variable `format.headerCmd` which allows the user to add extra headers per-patch. format-patch knows `--add-header`. However, that seems most useful for series-wide headers; you cannot really control what the header is like per patch or specifically for the cover letter. To that end, teach format-patch a new option which runs a command that has access to the hash of the current commit (if it is a code patch) and the patch count which is used for the patch files that this command outputs. Also include an environment variable which tells the version of this API so that the command can detect and error out in case the API changes. This is inspired by `--header-cmd` of git-send-email(1). § Discussion The command can use the provided commit hash to provide relevant information in the header. For example, the command could output a header for the current commit as well as the previously-published commits: X-Commit-Hash: 97b53c04894578b23d0c650f69885f734699afc7 X-Previous-Commits: 4ad5d4190649dcb5f26c73a6f15ab731891b9dfd d275d1d179b90592ddd7b5da2ae4573b3f7a37b7 402b7937951073466bf4527caffd38175391c7da Now interested parties can use this information to track where the patches come from. This information could of course be given between the three-dash/three-hyphen line and the patch proper. However, the project might prefer to use this part for extra patch information written by the author and leave the above information for tooling; this way the extra information does not need to disturb the reader. Signed-off-by: Kristoffer Haugsbakk --- Notes (series): v2: • Simplify tests: use `true` and `false` as commands • Fix indentation • Don’t use `const` for owned pointer (avoid cast when freeing) • Link: https://lore.kernel.org/git/cover.1709841147.git.code@khaugsbakk.name/T/#m12d104a5a769c7f6e02b1d0a75855142004e9206 • Use AsciiDoc definition list • Link: https://lore.kernel.org/git/53ea3745-205b-40c0-a4c5-9be26d9b88bf@gmail.com/ Documentation/config/format.txt | 5 ++++ Documentation/git-format-patch.txt | 23 ++++++++++++++++ builtin/log.c | 43 ++++++++++++++++++++++++++++++ t/t4014-format-patch.sh | 36 +++++++++++++++++++++++++ 4 files changed, 107 insertions(+) diff --git a/Documentation/config/format.txt b/Documentation/config/format.txt index 7410e930e53..c184b865824 100644 --- a/Documentation/config/format.txt +++ b/Documentation/config/format.txt @@ -31,6 +31,11 @@ format.headers:: Additional email headers to include in a patch to be submitted by mail. See linkgit:git-format-patch[1]. +format.headerCmd:: + Command to run for each patch that should output RFC 2822 email + headers. Has access to some information per patch via + environment variables. See linkgit:git-format-patch[1]. + format.to:: format.cc:: Additional recipients to include in a patch to be submitted diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt index 728bb3821c1..4f87fd25db9 100644 --- a/Documentation/git-format-patch.txt +++ b/Documentation/git-format-patch.txt @@ -303,6 +303,29 @@ feeding the result to `git send-email`. `Cc:`, and custom) headers added so far from config or command line. +--[no-]header-cmd=:: + Run __ for each patch. __ should output valid RFC 2822 + email headers. This can also be configured with + the configuration variable `format.headerCmd`. Can be turned off + with `--no-header-cmd`. This works independently of + `--[no-]add-header`. ++ +__ has access to these environment variables: ++ +-- +GIT_FP_HEADER_CMD_VERSION;; + The version of this API. Currently `1`. __ may return exit code + `2` in order to signal that it does not support the given version. +GIT_FP_HEADER_CMD_HASH;; + The hash of the commit corresponding to the current patch. Not set if + the current patch is the cover letter. +GIT_FP_HEADER_CMD_COUNT;; + The current patch count. Increments for each patch. +-- ++ +`git format-patch` will error out if __ returns a non-zero exit +code. + --[no-]cover-letter:: In addition to the patches, generate a cover letter file containing the branch description, shortlog and the overall diffstat. You can diff --git a/builtin/log.c b/builtin/log.c index e5da0d10434..bc656b5e0f8 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -43,10 +43,13 @@ #include "tmp-objdir.h" #include "tree.h" #include "write-or-die.h" +#include "run-command.h" #define MAIL_DEFAULT_WRAP 72 #define COVER_FROM_AUTO_MAX_SUBJECT_LEN 100 #define FORMAT_PATCH_NAME_MAX_DEFAULT 64 +#define HC_VERSION "1" +#define HC_NOT_SUPPORTED 2 /* Set a default date-time format for git log ("log.date" config variable) */ static const char *default_date_mode = NULL; @@ -902,6 +905,7 @@ static int auto_number = 1; static char *default_attach = NULL; +static const char *header_cmd = NULL; static struct string_list extra_hdr = STRING_LIST_INIT_NODUP; static struct string_list extra_to = STRING_LIST_INIT_NODUP; static struct string_list extra_cc = STRING_LIST_INIT_NODUP; @@ -1100,6 +1104,8 @@ static int git_format_config(const char *var, const char *value, format_no_prefix = 1; return 0; } + if (!strcmp(var, "format.headercmd")) + return git_config_string(&header_cmd, var, value); /* * ignore some porcelain config which would otherwise be parsed by @@ -1419,6 +1425,7 @@ static void make_cover_letter(struct rev_info *rev, int use_separate_file, show_range_diff(rev->rdiff1, rev->rdiff2, &range_diff_opts); strvec_clear(&other_arg); } + free(pp.after_subject); } static char *clean_message_id(const char *msg_id) @@ -1869,6 +1876,35 @@ static void infer_range_diff_ranges(struct strbuf *r1, } } +/* Returns an owned pointer */ +static char *header_cmd_output(struct rev_info *rev, const struct commit *cmit) +{ + struct child_process header_cmd_proc = CHILD_PROCESS_INIT; + struct strbuf output = STRBUF_INIT; + int res; + + strvec_pushl(&header_cmd_proc.args, header_cmd, NULL); + if (cmit) + strvec_pushf(&header_cmd_proc.env, "GIT_FP_HEADER_CMD_HASH=%s", + oid_to_hex(&cmit->object.oid)); + strvec_pushl(&header_cmd_proc.env, + "GIT_FP_HEADER_CMD_VERSION=" HC_VERSION, NULL); + strvec_pushf(&header_cmd_proc.env, "GIT_FP_HEADER_CMD_COUNT=%" PRIuMAX, + (uintmax_t)rev->nr); + res = capture_command(&header_cmd_proc, &output, 0); + if (res) { + if (res == HC_NOT_SUPPORTED) + die(_("header-cmd %s: returned exit " + "code %d; the command does not support " + "version " HC_VERSION), + header_cmd, HC_NOT_SUPPORTED); + else + die(_("header-cmd %s: failed with exit code %d"), + header_cmd, res); + } + return strbuf_detach(&output, NULL); +} + int cmd_format_patch(int argc, const char **argv, const char *prefix) { struct commit *commit; @@ -1959,6 +1995,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) OPT_GROUP(N_("Messaging")), OPT_CALLBACK(0, "add-header", NULL, N_("header"), N_("add email header"), header_callback), + OPT_STRING(0, "header-cmd", &header_cmd, N_("email"), N_("command that will be run to generate headers")), OPT_STRING_LIST(0, "to", &extra_to, N_("email"), N_("add To: header")), OPT_STRING_LIST(0, "cc", &extra_cc, N_("email"), N_("add Cc: header")), OPT_CALLBACK_F(0, "from", &from, N_("ident"), @@ -2325,6 +2362,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) if (cover_letter) { if (thread) gen_message_id(&rev, "cover"); + if (header_cmd) + rev.pe_headers = header_cmd_output(&rev, NULL); make_cover_letter(&rev, !!output_directory, origin, nr, list, description_file, branch_name, quiet); print_bases(&bases, rev.diffopt.file); @@ -2334,6 +2373,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) /* interdiff/range-diff in cover-letter; omit from patches */ rev.idiff_oid1 = NULL; rev.rdiff1 = NULL; + free(rev.pe_headers); } rev.add_signoff = do_signoff; @@ -2380,6 +2420,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) gen_message_id(&rev, oid_to_hex(&commit->object.oid)); } + if (header_cmd) + rev.pe_headers = header_cmd_output(&rev, commit); if (output_directory && open_next_file(rev.numbered_files ? NULL : commit, NULL, &rev, quiet)) die(_("failed to create output files")); @@ -2406,6 +2448,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) } if (output_directory) fclose(rev.diffopt.file); + free(rev.pe_headers); } stop_progress(&progress); free(list); diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh index e37a1411ee2..dc85c4c28fe 100755 --- a/t/t4014-format-patch.sh +++ b/t/t4014-format-patch.sh @@ -238,6 +238,42 @@ test_expect_failure 'configuration To: header (rfc2047)' ' grep "^To: =?UTF-8?q?R=20=C3=84=20Cipient?= \$" hdrs9 ' +test_expect_success '--header-cmd' ' + write_script cmd <<-\EOF && + printf "X-S: $GIT_FP_HEADER_CMD_HASH\n" + printf "X-V: $GIT_FP_HEADER_CMD_VERSION\n" + printf "X-C: $GIT_FP_HEADER_CMD_COUNT\n" + EOF + expect_sha1=$(git rev-parse side) && + git format-patch --header-cmd=./cmd --stdout main..side >patch && + grep "^X-S: $expect_sha1" patch && + grep "^X-V: 1" patch && + grep "^X-C: 3" patch +' + +test_expect_success '--header-cmd with no output works' ' + git format-patch --header-cmd=true --stdout main..side +' + +test_expect_success '--header-cmd reports failed command' ' + cat > expect <<-\EOF && + fatal: header-cmd false: failed with exit code 1 + EOF + test_must_fail git format-patch --header-cmd=false --stdout main..side >actual 2>&1 && + test_cmp expect actual +' + +test_expect_success '--header-cmd reports exit code 2' ' + write_script cmd <<-\EOF && + exit 2 + EOF + cat > expect <<-\EOF && + fatal: header-cmd ./cmd: returned exit code 2; the command does not support version 1 + EOF + test_must_fail git format-patch --header-cmd=./cmd --stdout main..side >actual 2>&1 && + test_cmp expect actual +' + # check_patch : Verify that looks like a half-sane # patch email to avoid a false positive with !grep check_patch () { From patchwork Tue Mar 19 18:35:38 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kristoffer Haugsbakk X-Patchwork-Id: 13597022 Received: from wfout5-smtp.messagingengine.com (wfout5-smtp.messagingengine.com [64.147.123.148]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A760A39FD0 for ; Tue, 19 Mar 2024 18:37:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=64.147.123.148 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710873429; cv=none; b=fmypxnwJzbAYs2KNcCFwhGNpLdY+ZvhVKLdEo8cWYHdiqIwxt2m/FWMsUn77nAo9jYEiY7eRUmsxs/cUmV40XsMyh7sUNmyW0pp+j5ad/QY0tzdJ8ZJRq+2d9dRvLQzHkPdZzENtuG83W1P9Q9kXAftJAmclgkrujoWfErssZYE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710873429; c=relaxed/simple; bh=D8kpe5vwWqGeGiEytyDhj8iHvw7Pe8aLp+z9tqFyZDk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=MBcjai2sCYTvKKOlfJfj+3tbAjJmTqrh/DWL+6CDZlbA6oIY2nv6ILxlhn3Xkrb1IjIDHsAPEvj1OIFCPwuAQwM3+MPEiyLFq2FPImM9JJNUhwA4SqDBTPJa8iKLGjrt72IeMU9+NOkHBGoGpSB7dib/YIk/fOybIZz8bJkfWF4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=khaugsbakk.name; spf=pass smtp.mailfrom=khaugsbakk.name; dkim=pass (2048-bit key) header.d=khaugsbakk.name header.i=@khaugsbakk.name header.b=mZgUDG6n; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=mpphTa/E; arc=none smtp.client-ip=64.147.123.148 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=khaugsbakk.name Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=khaugsbakk.name Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=khaugsbakk.name header.i=@khaugsbakk.name header.b="mZgUDG6n"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="mpphTa/E" Received: from compute4.internal (compute4.nyi.internal [10.202.2.44]) by mailfout.west.internal (Postfix) with ESMTP id BF7CE1C00092; Tue, 19 Mar 2024 14:37:06 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute4.internal (MEProxy); Tue, 19 Mar 2024 14:37:06 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=khaugsbakk.name; h=cc:cc:content-transfer-encoding:content-type:date:date:from :from:in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to; s=fm1; t=1710873426; x= 1710959826; bh=N712S9B/bAGgyrcDabO5BlX0LLGJpooX2bqL3xKq6GE=; b=m ZgUDG6nPdnZXEJ8oc7WL5/nJ0BUNaUxGZ1WnMnv4jIdiJbOz8cJ4XjobxYEFeTvU GShJbsVlLwfiERAYAsoZSy2lJlfcVYow0LVqn95QGIgUqSCFYrBsMgIHeXIdgDJV y6rA/MYgxd73curtdNqp672K9JK8wxcNBG9gh6LYwWJV02I14zyU2k7sS5IMxp3g UGDJlbobKTlumXOAnAfkx2pWvTs1ZdsYjbWMPKDUmXW/xiKRpAVkUIF8q3WU6gAs ZuQ6LZqEz7Dp+xrrZydqoPCWkJfWUxPTWpqEWTtsKKafAsNDOdlTn8bsl0UFrIL0 Qmnf7bg02edaN6Zakso7g== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to:x-me-proxy:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm2; t=1710873426; x= 1710959826; bh=N712S9B/bAGgyrcDabO5BlX0LLGJpooX2bqL3xKq6GE=; b=m pphTa/E4WhD01GvgCzKZii1DIRcXuAwfqQUr/wQpAg9Oyk2FT9cRdJRMyH04DFj0 YygxOL/3UqbnJJburAhU9/8KklafUKVovkHxghTKIFVehB7PgaI4/o3XWyz6Ytj5 CxJzmCIPZUY2AAqdA72G5IoI4ErsJDrJsh5tQ1NoHAmb1KZ3rjEBnwCOrQxNugvf KRIgRarJmexQR4VreQpG69Cw9mtyHcN0M7NsRknj6fjHuUu6wfrwjQD/q2FtjWIH j1hGYdFn1mLRxhlagP0TEYCgm6OXdqHw3ljK1r1PXlu4yKMIanpe3XDfMnETdxaX /FMvStv5AqW/VcUw09SBQ== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvledrledtgdeklecutefuodetggdotefrodftvf curfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfghnecu uegrihhlohhuthemuceftddtnecunecujfgurhephffvvefufffkofgjfhgggfestdekre dtredttdenucfhrhhomhepmfhrihhsthhofhhfvghrucfjrghughhssggrkhhkuceotgho uggvsehkhhgruhhgshgsrghkkhdrnhgrmhgvqeenucggtffrrghtthgvrhhnpeetudeihe eguddtgfduveekhfevudeiieetjefhffetiedtgeejieehtdfhjefgteenucevlhhushht vghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpegtohguvgeskhhhrghugh hssggrkhhkrdhnrghmvg X-ME-Proxy: Feedback-ID: i2671468f:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Tue, 19 Mar 2024 14:37:05 -0400 (EDT) From: Kristoffer Haugsbakk To: git@vger.kernel.org Cc: Kristoffer Haugsbakk Subject: [PATCH v2 3/3] format-patch: check if header output looks valid Date: Tue, 19 Mar 2024 19:35:38 +0100 Message-ID: X-Mailer: git-send-email 2.44.0.144.g29ae9861142 In-Reply-To: References: Precedence: bulk X-Mailing-List: git@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Commit-Hash: c570467c8db35d96e4262857658fcc64328d810c X-Previous-Commits: 0e8409227e4e8eb73bac7dff97e3f53584b4e283 Implement a function based on `mailinfo.c:is_mail`. Signed-off-by: Kristoffer Haugsbakk --- Notes (series): Isolating this for review as its own commit so that I can point out the provenance. May well be squashed into the main patch eventually. builtin/log.c | 33 +++++++++++++++++++++++++++++++++ t/t4014-format-patch.sh | 13 +++++++++++++ 2 files changed, 46 insertions(+) diff --git a/builtin/log.c b/builtin/log.c index bc656b5e0f8..2902c2bf6fe 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -1876,6 +1876,35 @@ static void infer_range_diff_ranges(struct strbuf *r1, } } +static int is_mail(struct strbuf *sb) +{ + const char *header_regex = "^[!-9;-~]+:"; + regex_t regex; + int ret = 1, i; + struct string_list list = STRING_LIST_INIT_DUP; + + if (regcomp(®ex, header_regex, REG_NOSUB | REG_EXTENDED)) + die("invalid pattern: %s", header_regex); + string_list_split(&list, sb->buf, '\n', -1); + for (i = 0; i < list.nr; i++) { + /* End of header */ + if (!*list.items[i].string && i == (list.nr - 1)) + break; + /* Ignore indented folded lines */ + if (*list.items[i].string == '\t' || + *list.items[i].string == ' ') + continue; + /* It's a header if it matches header_regex */ + if (regexec(®ex, list.items[i].string, 0, NULL, 0)) { + ret = 0; + break; + } + } + string_list_clear(&list, 1); + regfree(®ex); + return ret; +} + /* Returns an owned pointer */ static char *header_cmd_output(struct rev_info *rev, const struct commit *cmit) { @@ -1902,6 +1931,10 @@ static char *header_cmd_output(struct rev_info *rev, const struct commit *cmit) die(_("header-cmd %s: failed with exit code %d"), header_cmd, res); } + if (!is_mail(&output)) + die(_("header-cmd %s: returned output which was " + "not recognized as valid RFC 2822 headers"), + header_cmd); return strbuf_detach(&output, NULL); } diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh index dc85c4c28fe..533a5b246e5 100755 --- a/t/t4014-format-patch.sh +++ b/t/t4014-format-patch.sh @@ -255,6 +255,19 @@ test_expect_success '--header-cmd with no output works' ' git format-patch --header-cmd=true --stdout main..side ' +test_expect_success '--header-cmd without headers-like output fails' ' + write_script cmd <<-\EOF && + printf "X-S: $GIT_FP_HEADER_CMD_HASH\n" + printf "\n" + printf "X-C: $GIT_FP_HEADER_CMD_COUNT\n" + EOF + cat > expect <<-\EOF && + fatal: header-cmd ./cmd: returned output which was not recognized as valid RFC 2822 headers + EOF + test_must_fail git format-patch --header-cmd=./cmd --stdout main..side >actual 2>&1 && + test_cmp expect actual +' + test_expect_success '--header-cmd reports failed command' ' cat > expect <<-\EOF && fatal: header-cmd false: failed with exit code 1