From patchwork Thu Apr 2 07:09:22 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 11470181 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 9712515AB for ; Thu, 2 Apr 2020 07:09:40 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 75B1520784 for ; Thu, 2 Apr 2020 07:09:40 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="L3ujEh93"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="S4yo+W7Y" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1733114AbgDBHJS (ORCPT ); Thu, 2 Apr 2020 03:09:18 -0400 Received: from out3-smtp.messagingengine.com ([66.111.4.27]:60571 "EHLO out3-smtp.messagingengine.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728612AbgDBHJR (ORCPT ); Thu, 2 Apr 2020 03:09:17 -0400 Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.nyi.internal (Postfix) with ESMTP id 08E8C5C028F; Thu, 2 Apr 2020 03:09:17 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute3.internal (MEProxy); Thu, 02 Apr 2020 03:09:17 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=date :from:to:cc:subject:message-id:references:mime-version :content-type:in-reply-to; s=fm3; bh=kXhCDV4jmHqEtHWXlMbTY/O6mzR l0JCm4WOa10GSc9M=; b=L3ujEh93gUWbzdOK/V7eOOYaCe3+wffIj/hcWecsVw2 lSZ9n8xs2RiMXVXB9wi8WYwYU+SUSRsO+hQgMyl8cuou8wihYBXlkD7YDUVpOvWk WboVX1rfEKkm6FwBHvMDTTdg6TZ+5JFYhMBcl/bkPGtsNWsW75gGN850hp6xYR2f t8yKKLBL9fg3eCHY84dr9DMdJ5XOEs2IFzd9DIzi3lpx94fvoztOBkCi9EI3FFli 5HApLccnslJ/2OK2e9r9a1AhG4RYikXf3qFSRNjAVyno8KZ8zwIdj2/2NdfzV33c jmjIL4Ty86LaVn3I56V09qc+Ivd+nkzAK1weRTGen2w== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to:x-me-proxy :x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm2; bh=kXhCDV 4jmHqEtHWXlMbTY/O6mzRl0JCm4WOa10GSc9M=; b=S4yo+W7YNAwxuRKCoCbCeo 2j2xHASPjm/gBdFBQ3jGjg7go7Zh6vjzBC2kw/FOgCi0efMklN7sRRLteDQH/a8X 657Rp16PIgMiuoNJcqCHDSbkB0f+J6QmFHRTPu1g/Updfs9F6q5N24kk/3BRlZgW +oPe7dXRpmn0QuZeb0168w0PlQfanH3o+/M245f8yqxljYlbimjyG5kyi9G1jPBr NClW3Bafx8uXprH+Yn3uoI6jErkTkji15Y0sfllMd+EE7aRKGTaVm0o32ID5asUf D6UJ9GaRW1e6ExSyy4CkHFfAaUVVWicJLNOZzL8qKZskPKfxZFgS1h+ibqbvvpRw == X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeduhedrtdefgdduudeiucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvffukfhfgggtuggjsehgtderredttddvnecuhfhrohhmpefrrghtrhhi tghkucfuthgvihhnhhgrrhguthcuoehpshesphhkshdrihhmqeenucfkphepkeelrdduvd drleegrddvkeenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhr ohhmpehpshesphhkshdrihhm X-ME-Proxy: Received: from vm-mail.pks.im (x590c5e1c.dyn.telefonica.de [89.12.94.28]) by mail.messagingengine.com (Postfix) with ESMTPA id 68B8E306CD75; Thu, 2 Apr 2020 03:09:16 -0400 (EDT) Received: from localhost (ncase [10.192.0.11]) by vm-mail.pks.im (OpenSMTPD) with ESMTPSA id 4dcf2220 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Thu, 2 Apr 2020 07:09:15 +0000 (UTC) Date: Thu, 2 Apr 2020 09:09:22 +0200 From: Patrick Steinhardt To: git Cc: Christian Couder , Junio C Hamano Subject: [PATCH v3 1/9] refs: fix segfault when aborting empty transaction Message-ID: <7a297db4daaee84dc90ddeaa8f77b68a39231ef1.1585811013.git.ps@pks.im> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org When cleaning up a transaction that has no updates queued, then the transaction's backend data will not have been allocated. We correctly handle this for the packed backend, where the cleanup function checks whether the backend data has been allocated at all -- if not, then there is nothing to clean up. For the files backend we do not check this and as a result will hit a segfault due to dereferencing a `NULL` pointer when cleaning up such a transaction. Fix the issue by checking whether `backend_data` is set in the files backend, too. Signed-off-by: Patrick Steinhardt --- refs/files-backend.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/refs/files-backend.c b/refs/files-backend.c index 561c33ac8a..6516c7bc8c 100644 --- a/refs/files-backend.c +++ b/refs/files-backend.c @@ -2565,17 +2565,19 @@ static void files_transaction_cleanup(struct files_ref_store *refs, } } - if (backend_data->packed_transaction && - ref_transaction_abort(backend_data->packed_transaction, &err)) { - error("error aborting transaction: %s", err.buf); - strbuf_release(&err); + if (backend_data) { + if (backend_data->packed_transaction && + ref_transaction_abort(backend_data->packed_transaction, &err)) { + error("error aborting transaction: %s", err.buf); + strbuf_release(&err); + } + + if (backend_data->packed_refs_locked) + packed_refs_unlock(refs->packed_ref_store); + + free(backend_data); } - if (backend_data->packed_refs_locked) - packed_refs_unlock(refs->packed_ref_store); - - free(backend_data); - transaction->state = REF_TRANSACTION_CLOSED; } From patchwork Thu Apr 2 07:09:27 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 11470183 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id CB7B51667 for ; Thu, 2 Apr 2020 07:09:40 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id A0A5320784 for ; Thu, 2 Apr 2020 07:09:40 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="BesSw1Ws"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="Zy009x9c" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2387444AbgDBHJZ (ORCPT ); Thu, 2 Apr 2020 03:09:25 -0400 Received: from out3-smtp.messagingengine.com ([66.111.4.27]:52571 "EHLO out3-smtp.messagingengine.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2387403AbgDBHJZ (ORCPT ); Thu, 2 Apr 2020 03:09:25 -0400 Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.nyi.internal (Postfix) with ESMTP id C08555C0281; Thu, 2 Apr 2020 03:09:23 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute3.internal (MEProxy); Thu, 02 Apr 2020 03:09:23 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=date :from:to:cc:subject:message-id:references:mime-version :content-type:in-reply-to; s=fm3; bh=9nyYQw0I6X7TuKb5N1BpfD/eCx0 47AyTZ8RmD30iCmk=; b=BesSw1Ws2xjln+4HeHzZ887NOyRqYU+T+pZR3sPpxYA XX7NvBzWv7JKyBlA5fQLFr39+s/p31QUZynXEyQR2iR8x4OlqKLMQkvmLIsqVym+ wk7JM5EpMuonlRs9q1rtoYijt4HWiGmHYN3KYRoKQLCaq80uJlAV7S4DQBHRpmvm kLFYCxKFqAqujxM8OvsgLgufZSxYRTO2uGWwADYqnRJKyb/JsP4NEK7tvQ7apmOu Itxu28sjUCqQLjNYLE+qQwUlr0FyDchaADQgNNHwBP8Jwv9eM6FViAoCeUhlaxBw qC8WVoZjsY1EwxMXhF9qgRJ4L2ulwa92WQtYGF2SJsw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to:x-me-proxy :x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm2; bh=9nyYQw 0I6X7TuKb5N1BpfD/eCx047AyTZ8RmD30iCmk=; b=Zy009x9cezG7x24K2dgN8M KtkFsoNoVmqsYCIaoqzShzwq7etE6eStLRU6e87RBHwDADRailgRq056UbDNm7rE Y8tWWHd1R+7zhi6uPQ5Gt8AQS9C86uHVrAQtE642LrIB994jMa22R1/Gmz8VCqoh 8wpelRvGKRAxh5Iz8EZ6oxn/b62hf3KIG+4pSDFZ3FR6sHb9JTWy5H/OMGyLCzHQ Gk9gVVVGr88v5Zp99p5EYsFOYgjo0jK+8c6m45/oymlHgaOliWFYtZ2SkrrNJQ6R TOkrRrkvv678o08dLmgc3TYfnqlPuIhBgeSH5fY2cH5qXMQZJDxOib1OtHJdXm7g == X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeduhedrtdefgdduudeiucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvffukfhfgggtuggjsehgtderredttddvnecuhfhrohhmpefrrghtrhhi tghkucfuthgvihhnhhgrrhguthcuoehpshesphhkshdrihhmqeenucfkphepkeelrdduvd drleegrddvkeenucevlhhushhtvghrufhiiigvpedvnecurfgrrhgrmhepmhgrihhlfhhr ohhmpehpshesphhkshdrihhm X-ME-Proxy: Received: from vm-mail.pks.im (x590c5e1c.dyn.telefonica.de [89.12.94.28]) by mail.messagingengine.com (Postfix) with ESMTPA id 14D23306CDA9; Thu, 2 Apr 2020 03:09:22 -0400 (EDT) Received: from localhost (ncase [10.192.0.11]) by vm-mail.pks.im (OpenSMTPD) with ESMTPSA id 847ad378 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Thu, 2 Apr 2020 07:09:20 +0000 (UTC) Date: Thu, 2 Apr 2020 09:09:27 +0200 From: Patrick Steinhardt To: git Cc: Christian Couder , Junio C Hamano Subject: [PATCH v3 2/9] git-update-ref.txt: add missing word Message-ID: <15857e1b8ca800a92fa96fee818a54456bfbd330.1585811013.git.ps@pks.im> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org The description for the "verify" command is lacking a single word "is", which this commit corrects. Signed-off-by: Patrick Steinhardt --- Documentation/git-update-ref.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/git-update-ref.txt b/Documentation/git-update-ref.txt index 9671423117..9bd039ce08 100644 --- a/Documentation/git-update-ref.txt +++ b/Documentation/git-update-ref.txt @@ -107,7 +107,7 @@ delete:: verify:: Verify against but do not change it. If - zero or missing, the ref must not exist. + is zero or missing, the ref must not exist. option:: Modify behavior of the next command naming a . From patchwork Thu Apr 2 07:09:33 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 11470185 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 035801892 for ; Thu, 2 Apr 2020 07:09:41 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id D53D320784 for ; Thu, 2 Apr 2020 07:09:40 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="dLsraSyD"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="mROyA6zA" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2387453AbgDBHJa (ORCPT ); Thu, 2 Apr 2020 03:09:30 -0400 Received: from out3-smtp.messagingengine.com ([66.111.4.27]:53855 "EHLO out3-smtp.messagingengine.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728612AbgDBHJ3 (ORCPT ); Thu, 2 Apr 2020 03:09:29 -0400 Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.nyi.internal (Postfix) with ESMTP id 62B465C0293; Thu, 2 Apr 2020 03:09:28 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute3.internal (MEProxy); Thu, 02 Apr 2020 03:09:28 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=date :from:to:cc:subject:message-id:references:mime-version :content-type:in-reply-to; s=fm3; bh=TTGqwR3oq5EKMx2DqlfVM/DTzGx jU2VK2vU2N75/Hk4=; b=dLsraSyDLJtCJFXU0W5aRXLV3oZOWg3jDWgG6cy9giA UzA7BJBUEpojlsfbAz4l58nstATpuaETC7X6SMN2eE2f+IuL+syzyvLEoXGNwZ5b ToRkZCq8ekzn6B/rRaEAfCnit76Ninpi88J9TAdAmd3jB84dR5nUttpoWajuh+pu 3HqrLjlVPcYW9osSulEMVtfqEEd8piW28XeVdLLx5rTBpxMfNICZftfcTiYm9rFx v/38S1NLUHqmRho63KMO9MTg4gE5KJB+mKmMM+2T2gswaAcwOdxAWBG7Y1d1PB8k YO06A4iTmd7wObmCG20NiDCviMErSh5Eo/dP2RmmU8Q== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to:x-me-proxy :x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm2; bh=TTGqwR 3oq5EKMx2DqlfVM/DTzGxjU2VK2vU2N75/Hk4=; b=mROyA6zAuI7neI3ai2EkEO Tiq3SBVgdf6nGo9zsIVFxfv0Ok916bWwE7soKW7rJowXlCXJnAd/PGrYURu8Apzq KCyl81LDQl3JsO8aS+mcsYHazUf5vaGkD7iJycG0ixxmOV2/dl2cpZOioklNNGo7 CCigrt2tN2KLofJXwwAL0W6+pjL7UP8m5Jf3HGKvhtckC1uKpbiiKQAk8yNfp5c7 HbrXG4BK5IEBc+seQP/PZWuhdJKL+UaGM9TAuAFvyMEbTEY79zSCW9fh8GJwAyME KKyPuh6xNLGeQW04ab1E6Lp0MpWa2lJZQDIuADu6C3MEaWgCDbRrlkCkRJYYfTwg == X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeduhedrtdefgdduudeiucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvffukfhfgggtuggjsehgtderredttddvnecuhfhrohhmpefrrghtrhhi tghkucfuthgvihhnhhgrrhguthcuoehpshesphhkshdrihhmqeenucfkphepkeelrdduvd drleegrddvkeenucevlhhushhtvghrufhiiigvpeefnecurfgrrhgrmhepmhgrihhlfhhr ohhmpehpshesphhkshdrihhm X-ME-Proxy: Received: from vm-mail.pks.im (x590c5e1c.dyn.telefonica.de [89.12.94.28]) by mail.messagingengine.com (Postfix) with ESMTPA id C63DF306CD98; Thu, 2 Apr 2020 03:09:27 -0400 (EDT) Received: from localhost (ncase [10.192.0.11]) by vm-mail.pks.im (OpenSMTPD) with ESMTPSA id 8f61b50f (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Thu, 2 Apr 2020 07:09:26 +0000 (UTC) Date: Thu, 2 Apr 2020 09:09:33 +0200 From: Patrick Steinhardt To: git Cc: Christian Couder , Junio C Hamano Subject: [PATCH v3 3/9] strbuf: provide function to append whole lines Message-ID: References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org While the strbuf interface already provides functions to read a line into it that completely replaces its current contents, we do not have an interface that allows for appending lines without discarding current contents. Add a new function `strbuf_appendwholeline` that reads a line including its terminating character into a strbuf non-destructively. This is a preparatory step for git-update-ref(1) reading standard input line-wise instead of as a block. Signed-off-by: Patrick Steinhardt --- strbuf.c | 10 ++++++++++ strbuf.h | 6 ++++++ 2 files changed, 16 insertions(+) diff --git a/strbuf.c b/strbuf.c index bb0065ccaf..6e74901bfa 100644 --- a/strbuf.c +++ b/strbuf.c @@ -690,6 +690,16 @@ int strbuf_getwholeline(struct strbuf *sb, FILE *fp, int term) } #endif +int strbuf_appendwholeline(struct strbuf *sb, FILE *fp, int term) +{ + struct strbuf line = STRBUF_INIT; + if (strbuf_getwholeline(&line, fp, term)) + return EOF; + strbuf_addbuf(sb, &line); + strbuf_release(&line); + return 0; +} + static int strbuf_getdelim(struct strbuf *sb, FILE *fp, int term) { if (strbuf_getwholeline(sb, fp, term)) diff --git a/strbuf.h b/strbuf.h index ce8e49c0b2..411063ca76 100644 --- a/strbuf.h +++ b/strbuf.h @@ -502,6 +502,12 @@ int strbuf_getline(struct strbuf *sb, FILE *file); */ int strbuf_getwholeline(struct strbuf *sb, FILE *file, int term); +/** + * Like `strbuf_getwholeline`, but appends the line instead of + * resetting the buffer first. + */ +int strbuf_appendwholeline(struct strbuf *sb, FILE *file, int term); + /** * Like `strbuf_getwholeline`, but operates on a file descriptor. * It reads one character at a time, so it is very slow. Do not From patchwork Thu Apr 2 07:09:38 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 11470187 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 38CB41874 for ; Thu, 2 Apr 2020 07:09:41 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 0D10220784 for ; Thu, 2 Apr 2020 07:09:41 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="aW3KugoF"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="XEmbdwRe" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2387502AbgDBHJf (ORCPT ); Thu, 2 Apr 2020 03:09:35 -0400 Received: from out3-smtp.messagingengine.com ([66.111.4.27]:47495 "EHLO out3-smtp.messagingengine.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2387447AbgDBHJf (ORCPT ); Thu, 2 Apr 2020 03:09:35 -0400 Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.nyi.internal (Postfix) with ESMTP id 291B25C0281; Thu, 2 Apr 2020 03:09:34 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute3.internal (MEProxy); Thu, 02 Apr 2020 03:09:34 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=date :from:to:cc:subject:message-id:references:mime-version :content-type:in-reply-to; s=fm3; bh=yM9X7I4cWYrAHEkC6K+XmEnQGrD DWu/uule9ZBR7Oa8=; b=aW3KugoFs6DJDM0IFJPCGwAciiU66LWyGHmLKO8MJWv /pU/WcpP9at/SS3BwFTFy0XnQZqQwxIWi3omtUngq5TJqI098w3bWYEobj53z94C CcdaYTFPGzjQpLDxm+iwe596dOCdnYKAZv76QXqeb3etoYim2HxjQog8jikPi/rm b4QY1cUwg4384yZwIt4qwIJRwrl/Hn/TwI9bYu8f+PxaHjlgs0jKvnNx5G/Rl5RI SSW/p/INJsQEY6YrEZQUdOVFNFMl2zgjAL/e8AT3zJePu+BzPHliqxKlHueJYfga tRqzatGsco33Fq6DjtAMPVqUfpwz8ymZsGvsFwrKJgQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to:x-me-proxy :x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm2; bh=yM9X7I 4cWYrAHEkC6K+XmEnQGrDDWu/uule9ZBR7Oa8=; b=XEmbdwReoZubDZJ66/E2Er VZXgf8v1yv77bfxid8/hvMKseo+jUdkvTCuzk/3XBBmjLOCpo+3NeAcWr2OuNfEv yT0ejOdtUlZpRCwnEWpV6UQcUdh6nPukVWhcxLo10dpRUi71q6P1/aZb4HXq2h7q U4d9xVR91dl+pe3Rh9OpKuYIBJ0yU7z3iSJ69Zv3+Wj1YJ1wyuudAVORdkAgZ4U0 ljqWPWLJGynT1V61cqBsCsKXs92YoKpSDEP3gQG2z+Pdhyg+mrN/DOiP4VFTjyvB WuBm2txQqS07qofTGByyEMZc69m2uc3o/AwbkjCVzu9YiTcW1KAIk3z3w54yRRtw == X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeduhedrtdefgdduudeiucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvffukfhfgggtuggjsehgtderredttddvnecuhfhrohhmpefrrghtrhhi tghkucfuthgvihhnhhgrrhguthcuoehpshesphhkshdrihhmqeenucfkphepkeelrdduvd drleegrddvkeenucevlhhushhtvghrufhiiigvpeegnecurfgrrhgrmhepmhgrihhlfhhr ohhmpehpshesphhkshdrihhm X-ME-Proxy: Received: from vm-mail.pks.im (x590c5e1c.dyn.telefonica.de [89.12.94.28]) by mail.messagingengine.com (Postfix) with ESMTPA id 6F973306CD75; Thu, 2 Apr 2020 03:09:33 -0400 (EDT) Received: from localhost (ncase [10.192.0.11]) by vm-mail.pks.im (OpenSMTPD) with ESMTPSA id e063f603 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Thu, 2 Apr 2020 07:09:31 +0000 (UTC) Date: Thu, 2 Apr 2020 09:09:38 +0200 From: Patrick Steinhardt To: git Cc: Christian Couder , Junio C Hamano Subject: [PATCH v3 4/9] update-ref: organize commands in an array Message-ID: <0f881d49366fe9d9806b08af35319475ca07abc3.1585811013.git.ps@pks.im> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org We currently manually wire up all commands known to `git-update-ref --stdin`, making it harder than necessary to preprocess arguments after the command is determined. To make this more extensible, let's refactor the code to use an array of known commands instead. While this doesn't add a lot of value now, it is a preparatory step to implement line-wise reading of commands. As we're going to introduce commands without trailing spaces, this commit also moves whitespace parsing into the respective commands. Signed-off-by: Patrick Steinhardt --- builtin/update-ref.c | 41 +++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/builtin/update-ref.c b/builtin/update-ref.c index 2d8f7f0578..a6ff88b95b 100644 --- a/builtin/update-ref.c +++ b/builtin/update-ref.c @@ -310,7 +310,8 @@ static const char *parse_cmd_verify(struct ref_transaction *transaction, return next; } -static const char *parse_cmd_option(struct strbuf *input, const char *next) +static const char *parse_cmd_option(struct ref_transaction *transaction, + struct strbuf *input, const char *next) { const char *rest; if (skip_prefix(next, "no-deref", &rest) && *rest == line_termination) @@ -320,33 +321,49 @@ static const char *parse_cmd_option(struct strbuf *input, const char *next) return rest; } +static const struct parse_cmd { + const char *prefix; + const char *(*fn)(struct ref_transaction *, struct strbuf *, const char *); +} command[] = { + { "update", parse_cmd_update }, + { "create", parse_cmd_create }, + { "delete", parse_cmd_delete }, + { "verify", parse_cmd_verify }, + { "option", parse_cmd_option }, +}; + static void update_refs_stdin(struct ref_transaction *transaction) { struct strbuf input = STRBUF_INIT; const char *next; + int i; if (strbuf_read(&input, 0, 1000) < 0) die_errno("could not read from stdin"); next = input.buf; /* Read each line dispatch its command */ while (next < input.buf + input.len) { + const struct parse_cmd *cmd = NULL; + if (*next == line_termination) die("empty command in input"); else if (isspace(*next)) die("whitespace before command: %s", next); - else if (skip_prefix(next, "update ", &next)) - next = parse_cmd_update(transaction, &input, next); - else if (skip_prefix(next, "create ", &next)) - next = parse_cmd_create(transaction, &input, next); - else if (skip_prefix(next, "delete ", &next)) - next = parse_cmd_delete(transaction, &input, next); - else if (skip_prefix(next, "verify ", &next)) - next = parse_cmd_verify(transaction, &input, next); - else if (skip_prefix(next, "option ", &next)) - next = parse_cmd_option(&input, next); - else + + for (i = 0; i < ARRAY_SIZE(command); i++) { + const char *prefix = command[i].prefix; + + if (!skip_prefix(next, prefix, &next) || + !skip_prefix(next, " ", &next)) + continue; + + cmd = &command[i]; + break; + } + if (!cmd) die("unknown command: %s", next); + next = cmd->fn(transaction, &input, next); next++; } From patchwork Thu Apr 2 07:09:43 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 11470189 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 6442C2D34 for ; Thu, 2 Apr 2020 07:09:41 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 425D820784 for ; Thu, 2 Apr 2020 07:09:41 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="NiYz5upb"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="zzsfl8/v" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2387509AbgDBHJk (ORCPT ); Thu, 2 Apr 2020 03:09:40 -0400 Received: from out3-smtp.messagingengine.com ([66.111.4.27]:55501 "EHLO out3-smtp.messagingengine.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2387447AbgDBHJj (ORCPT ); Thu, 2 Apr 2020 03:09:39 -0400 Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.nyi.internal (Postfix) with ESMTP id C57EE5C0293; Thu, 2 Apr 2020 03:09:38 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute3.internal (MEProxy); Thu, 02 Apr 2020 03:09:38 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=date :from:to:cc:subject:message-id:references:mime-version :content-type:in-reply-to; s=fm3; bh=c/r194pnijwD639zp9GRammRLa+ motWVbhfHPCgM2EY=; b=NiYz5upbxutOmG9vkfQz1Os1LYoKxnzIsTBqjvqU+Ky Uat207hHHtWzwUX4AYSd7ivbhcMt1hF278WIK3DM280502+CfGjXTKlXQXtVClWD tQnhOfF7YI0B+aSK36KzvsckT3SWZaWYUn8WBmzQjp0fgnekLu8x4mWXs5hkYDF0 n9J+cgXAFSWb2EID3a3tqLoQ31iKZdJs4K5yj1vhcM6tWeALLP6bFPsv2TFZi+s0 JDBV5FoklwHisfnsrQJLRsUnK+bhhopKwPH4VAWXMnKFFddRKlgZEssZGSy5CM7+ crQO+TIEnTpQoOFRhstlxkyfDArqBPuwzNf0TNgsh2A== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to:x-me-proxy :x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm2; bh=c/r194 pnijwD639zp9GRammRLa+motWVbhfHPCgM2EY=; b=zzsfl8/vk180U/MHeQAzuQ bIB6nk276R3Bcb5YP6n0RHh7njytAEVlC+V3jYqs9vLxyP6210gK1BHnP3D6wAYE cfellz1WAfrC1u3C3S3RuunExh86SZ3rUjaM2ztBXbeAQ+iYFwA9YHPDuqeI/kz0 Bls9r5Td0Szt/ejhFg2TZlyuF+vDGVZQ+sJoUaF1KtXDzNC863YqX6XvbVunBLgO NNVofrEw1Tm8Fdh4O8Z08rvM+Zq8ppJFTxEeyXmMY1MZVyOwbSxMqXgHS5vIpWu6 iEymebA9YPiAgQOjIX2yJ9AgyDOBAkNh/mZqMh6chrHOjoXgKoSLi+0U5zxa4blg == X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeduhedrtdefgdduudeiucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvffukfhfgggtuggjsehgtderredttddvnecuhfhrohhmpefrrghtrhhi tghkucfuthgvihhnhhgrrhguthcuoehpshesphhkshdrihhmqeenucfkphepkeelrdduvd drleegrddvkeenucevlhhushhtvghrufhiiigvpeehnecurfgrrhgrmhepmhgrihhlfhhr ohhmpehpshesphhkshdrihhm X-ME-Proxy: Received: from vm-mail.pks.im (x590c5e1c.dyn.telefonica.de [89.12.94.28]) by mail.messagingengine.com (Postfix) with ESMTPA id 3167A306CD98; Thu, 2 Apr 2020 03:09:38 -0400 (EDT) Received: from localhost (ncase [10.192.0.11]) by vm-mail.pks.im (OpenSMTPD) with ESMTPSA id cff692a1 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Thu, 2 Apr 2020 07:09:36 +0000 (UTC) Date: Thu, 2 Apr 2020 09:09:43 +0200 From: Patrick Steinhardt To: git Cc: Christian Couder , Junio C Hamano Subject: [PATCH v3 5/9] update-ref: drop unused argument for `parse_refname` Message-ID: References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org The `parse_refname` function accepts a `struct strbuf *input` argument that isn't used at all. As we're about to convert commands to not use a strbuf anymore but instead an end pointer, let's drop this argument now to make the converting commit easier to review. Signed-off-by: Patrick Steinhardt --- builtin/update-ref.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/builtin/update-ref.c b/builtin/update-ref.c index a6ff88b95b..1bba5ea6c2 100644 --- a/builtin/update-ref.c +++ b/builtin/update-ref.c @@ -50,7 +50,7 @@ static const char *parse_arg(const char *next, struct strbuf *arg) * the argument. Die if C-quoting is malformed or the reference name * is invalid. */ -static char *parse_refname(struct strbuf *input, const char **next) +static char *parse_refname(const char **next) { struct strbuf ref = STRBUF_INIT; @@ -186,7 +186,7 @@ static const char *parse_cmd_update(struct ref_transaction *transaction, struct object_id new_oid, old_oid; int have_old; - refname = parse_refname(input, &next); + refname = parse_refname(&next); if (!refname) die("update: missing "); @@ -220,7 +220,7 @@ static const char *parse_cmd_create(struct ref_transaction *transaction, char *refname; struct object_id new_oid; - refname = parse_refname(input, &next); + refname = parse_refname(&next); if (!refname) die("create: missing "); @@ -253,7 +253,7 @@ static const char *parse_cmd_delete(struct ref_transaction *transaction, struct object_id old_oid; int have_old; - refname = parse_refname(input, &next); + refname = parse_refname(&next); if (!refname) die("delete: missing "); @@ -288,7 +288,7 @@ static const char *parse_cmd_verify(struct ref_transaction *transaction, char *refname; struct object_id old_oid; - refname = parse_refname(input, &next); + refname = parse_refname(&next); if (!refname) die("verify: missing "); From patchwork Thu Apr 2 07:09:48 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 11470193 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 3B2431392 for ; Thu, 2 Apr 2020 07:09:46 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 1019B2080C for ; Thu, 2 Apr 2020 07:09:46 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="QmmVD5pJ"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="N962f3I7" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2387511AbgDBHJo (ORCPT ); Thu, 2 Apr 2020 03:09:44 -0400 Received: from out3-smtp.messagingengine.com ([66.111.4.27]:38915 "EHLO out3-smtp.messagingengine.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725789AbgDBHJo (ORCPT ); Thu, 2 Apr 2020 03:09:44 -0400 Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.nyi.internal (Postfix) with ESMTP id 7F2DF5C0290; Thu, 2 Apr 2020 03:09:43 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute3.internal (MEProxy); Thu, 02 Apr 2020 03:09:43 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=date :from:to:cc:subject:message-id:references:mime-version :content-type:in-reply-to; s=fm3; bh=xIlHGRT5bwk2fhL7S3NG4XJBPsc YbODI905bbJ0V9Cg=; b=QmmVD5pJQu7mICjW5JMULss4OBp26ZYgmDTBYr08CyU JDHEwzbx7VGHB1U1eUdl+pnIPDROHhGpc9Qg4nudzDNMuIDlfa9NGNyYB7fOibQg oh413whcfzKu9+G7aDF1kNco8j5PnIHL3JReXRyy3JGtH79z3F2+gFNuck3fLFkJ D9lyT+UGcGpLUPp+kZzqCdjsRtuKhHiAzXZxYGZMMtPdE0HeoTbTKT5LcwRTdqqe G+40ajUayL6AEd6Gq2fzN6KS35pgZE3TEVT3o5wZr+4enK0DVRlVo0q6dliG/Xdl Hx/7gE/alcF0+iOMLps1K/2BqChG+lJ6Njw+7vShM2g== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to:x-me-proxy :x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm2; bh=xIlHGR T5bwk2fhL7S3NG4XJBPscYbODI905bbJ0V9Cg=; b=N962f3I7miMe/T6q11fgvn iXsWCHPgTXs4iSWQfb6wThz40hmjLAt5b5EKNchj2AIXn3DOLhNKmNC8htMEOREz hcip+i3bV0eGE/lzCo0Dx1v364yJydWKawXEzaMEcSHK+XDz2oE/Ulh/LT10EcY/ 6BnT3LUK4B4cMDVeB5PoZGJgN9uRhoT5aM3daSaMfyOyAI1Y6a7tFjAhEEEZO3lg QpVITM7yBuJKwP4ulO6IUA2DUT6nN9bHb6oppQqCc/V9aiTdY+/soswFXdK6SOkk 0d20exti1acwyAOGK92dLiPahk00Ikppf822bFIgsdHKgRGjx4T4YK3S6FT8xMLw == X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeduhedrtdefgdduudeiucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvffukfhfgggtuggjsehgtderredttddvnecuhfhrohhmpefrrghtrhhi tghkucfuthgvihhnhhgrrhguthcuoehpshesphhkshdrihhmqeenucfkphepkeelrdduvd drleegrddvkeenucevlhhushhtvghrufhiiigvpeeinecurfgrrhgrmhepmhgrihhlfhhr ohhmpehpshesphhkshdrihhm X-ME-Proxy: Received: from vm-mail.pks.im (x590c5e1c.dyn.telefonica.de [89.12.94.28]) by mail.messagingengine.com (Postfix) with ESMTPA id C8689306CDC6; Thu, 2 Apr 2020 03:09:42 -0400 (EDT) Received: from localhost (ncase [10.192.0.11]) by vm-mail.pks.im (OpenSMTPD) with ESMTPSA id ad95fdaa (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Thu, 2 Apr 2020 07:09:41 +0000 (UTC) Date: Thu, 2 Apr 2020 09:09:48 +0200 From: Patrick Steinhardt To: git Cc: Christian Couder , Junio C Hamano Subject: [PATCH v3 6/9] update-ref: pass end pointer instead of strbuf Message-ID: <192cbf59446e5d0dbd842008d0d43581b85dfdbe.1585811013.git.ps@pks.im> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org We currently pass both an `strbuf` containing the current command line as well as the `next` pointer pointing to the first argument to commands. This is both confusing and makes code more intertwined. Convert this to use a simple pointer as well as a pointer pointing to the end of the input as a preparatory step to line-wise reading of stdin. Signed-off-by: Patrick Steinhardt --- builtin/update-ref.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/builtin/update-ref.c b/builtin/update-ref.c index 1bba5ea6c2..381d347fb4 100644 --- a/builtin/update-ref.c +++ b/builtin/update-ref.c @@ -95,7 +95,7 @@ static char *parse_refname(const char **next) * provided but cannot be converted to a SHA-1, die. flags can * include PARSE_SHA1_OLD and/or PARSE_SHA1_ALLOW_EMPTY. */ -static int parse_next_oid(struct strbuf *input, const char **next, +static int parse_next_oid(const char **next, const char *end, struct object_id *oid, const char *command, const char *refname, int flags) @@ -103,7 +103,7 @@ static int parse_next_oid(struct strbuf *input, const char **next, struct strbuf arg = STRBUF_INIT; int ret = 0; - if (*next == input->buf + input->len) + if (*next == end) goto eof; if (line_termination) { @@ -128,7 +128,7 @@ static int parse_next_oid(struct strbuf *input, const char **next, die("%s %s: expected NUL but got: %s", command, refname, *next); (*next)++; - if (*next == input->buf + input->len) + if (*next == end) goto eof; strbuf_addstr(&arg, *next); *next += arg.len; @@ -179,7 +179,7 @@ static int parse_next_oid(struct strbuf *input, const char **next, */ static const char *parse_cmd_update(struct ref_transaction *transaction, - struct strbuf *input, const char *next) + const char *next, const char *end) { struct strbuf err = STRBUF_INIT; char *refname; @@ -190,11 +190,11 @@ static const char *parse_cmd_update(struct ref_transaction *transaction, if (!refname) die("update: missing "); - if (parse_next_oid(input, &next, &new_oid, "update", refname, + if (parse_next_oid(&next, end, &new_oid, "update", refname, PARSE_SHA1_ALLOW_EMPTY)) die("update %s: missing ", refname); - have_old = !parse_next_oid(input, &next, &old_oid, "update", refname, + have_old = !parse_next_oid(&next, end, &old_oid, "update", refname, PARSE_SHA1_OLD); if (*next != line_termination) @@ -214,7 +214,7 @@ static const char *parse_cmd_update(struct ref_transaction *transaction, } static const char *parse_cmd_create(struct ref_transaction *transaction, - struct strbuf *input, const char *next) + const char *next, const char *end) { struct strbuf err = STRBUF_INIT; char *refname; @@ -224,7 +224,7 @@ static const char *parse_cmd_create(struct ref_transaction *transaction, if (!refname) die("create: missing "); - if (parse_next_oid(input, &next, &new_oid, "create", refname, 0)) + if (parse_next_oid(&next, end, &new_oid, "create", refname, 0)) die("create %s: missing ", refname); if (is_null_oid(&new_oid)) @@ -246,7 +246,7 @@ static const char *parse_cmd_create(struct ref_transaction *transaction, } static const char *parse_cmd_delete(struct ref_transaction *transaction, - struct strbuf *input, const char *next) + const char *next, const char *end) { struct strbuf err = STRBUF_INIT; char *refname; @@ -257,7 +257,7 @@ static const char *parse_cmd_delete(struct ref_transaction *transaction, if (!refname) die("delete: missing "); - if (parse_next_oid(input, &next, &old_oid, "delete", refname, + if (parse_next_oid(&next, end, &old_oid, "delete", refname, PARSE_SHA1_OLD)) { have_old = 0; } else { @@ -282,7 +282,7 @@ static const char *parse_cmd_delete(struct ref_transaction *transaction, } static const char *parse_cmd_verify(struct ref_transaction *transaction, - struct strbuf *input, const char *next) + const char *next, const char *end) { struct strbuf err = STRBUF_INIT; char *refname; @@ -292,7 +292,7 @@ static const char *parse_cmd_verify(struct ref_transaction *transaction, if (!refname) die("verify: missing "); - if (parse_next_oid(input, &next, &old_oid, "verify", refname, + if (parse_next_oid(&next, end, &old_oid, "verify", refname, PARSE_SHA1_OLD)) oidclr(&old_oid); @@ -311,7 +311,7 @@ static const char *parse_cmd_verify(struct ref_transaction *transaction, } static const char *parse_cmd_option(struct ref_transaction *transaction, - struct strbuf *input, const char *next) + const char *next, const char *end) { const char *rest; if (skip_prefix(next, "no-deref", &rest) && *rest == line_termination) @@ -323,7 +323,7 @@ static const char *parse_cmd_option(struct ref_transaction *transaction, static const struct parse_cmd { const char *prefix; - const char *(*fn)(struct ref_transaction *, struct strbuf *, const char *); + const char *(*fn)(struct ref_transaction *, const char *, const char *); } command[] = { { "update", parse_cmd_update }, { "create", parse_cmd_create }, @@ -363,7 +363,7 @@ static void update_refs_stdin(struct ref_transaction *transaction) if (!cmd) die("unknown command: %s", next); - next = cmd->fn(transaction, &input, next); + next = cmd->fn(transaction, next, input.buf + input.len); next++; } From patchwork Thu Apr 2 07:09:53 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 11470195 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 0F56A15AB for ; Thu, 2 Apr 2020 07:09:52 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id D7ACC2078B for ; Thu, 2 Apr 2020 07:09:51 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="NpDY+N3Q"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="XCYYyMPK" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2387538AbgDBHJu (ORCPT ); Thu, 2 Apr 2020 03:09:50 -0400 Received: from out3-smtp.messagingengine.com ([66.111.4.27]:56341 "EHLO out3-smtp.messagingengine.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725789AbgDBHJt (ORCPT ); Thu, 2 Apr 2020 03:09:49 -0400 Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.nyi.internal (Postfix) with ESMTP id 3B98F5C028F; Thu, 2 Apr 2020 03:09:48 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute3.internal (MEProxy); Thu, 02 Apr 2020 03:09:48 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=date :from:to:cc:subject:message-id:references:mime-version :content-type:in-reply-to; s=fm3; bh=O6AMiESRLD83K6zQxtKvWe18N/H t4Wi3hNEvQO1P7BU=; b=NpDY+N3QzES65ay6Yb0yrL8h6QMbtFOqnBgnmvv2leG FvDhKpAb3RhCt9LDkKJvIlT495pwBnUf1v4yeerpsEDkQx1A910O3tyX+LdecLAJ Tajzb7jx7/mC9XNNLJis7+8B+2mDn6J8cycutzEAyav+r097VQMH9X79E268+nTO wC6c4NbY7mDa7MJvSjPPNMGozDyxEpn0riIzNEhuLlF70jptchvdLZQGbCs+sKkh C8U7YkpYetOKUd6fW92jqv96QqyCi0IjLuOoLXOGLrj31p+C/JrK0w0gu4ApBVDx ysNAHq2Cr1RELCOC4CsZK8zzyYGoLHknO7Z+vGq6uzw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to:x-me-proxy :x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm2; bh=O6AMiE SRLD83K6zQxtKvWe18N/Ht4Wi3hNEvQO1P7BU=; b=XCYYyMPKoogM3ZUsBrBHyR 5wfaLSyG+LVt4tcnPi9vmHkPcU9wbidIfxlsqVWnwWR4A9E+nLxiBsfRtPwfIqkN H8L4bkJnGlEtk54RFjug/YjGSaZoFedvm5SP8Dsn3X5aEc179AAkmoUc7fqwtYWj ozHRMoybBH+ixDB5/yhcjqnq/YnOJdYFrGw6/SQPNp+CDmNVhUa/SwlG+DCQyLxE /GX8CNVS4RB8jF21uBYfK4FISaYVug4jAIdJs/Oa7xWzLTqLD1R6LBOePbE3tKDP V3l1+/a8jCdreIeErLSaMMGdhUccigwIqZIXs2QqygqSypqg6UIUOlUqUZI9Ryjw == X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeduhedrtdefgdduudejucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvffukfhfgggtuggjsehgtderredttddvnecuhfhrohhmpefrrghtrhhi tghkucfuthgvihhnhhgrrhguthcuoehpshesphhkshdrihhmqeenucfkphepkeelrdduvd drleegrddvkeenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhr ohhmpehpshesphhkshdrihhm X-ME-Proxy: Received: from vm-mail.pks.im (x590c5e1c.dyn.telefonica.de [89.12.94.28]) by mail.messagingengine.com (Postfix) with ESMTPA id 87F5E306CD98; Thu, 2 Apr 2020 03:09:47 -0400 (EDT) Received: from localhost (ncase [10.192.0.11]) by vm-mail.pks.im (OpenSMTPD) with ESMTPSA id 45aaa4b8 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Thu, 2 Apr 2020 07:09:46 +0000 (UTC) Date: Thu, 2 Apr 2020 09:09:53 +0200 From: Patrick Steinhardt To: git Cc: Christian Couder , Junio C Hamano Subject: [PATCH v3 7/9] update-ref: move transaction handling into `update_refs_stdin()` Message-ID: References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org While the actual logic to update the transaction is handled in `update_refs_stdin()`, the transaction itself is started and committed in `cmd_update_ref()` itself. This makes it hard to handle transaction abortion and commits as part of `update_refs_stdin()` itself, which is required in order to introduce transaction handling features to `git update-refs --stdin`. Refactor the code to move all transaction handling into `update_refs_stdin()` to prepare for transaction handling features. Signed-off-by: Patrick Steinhardt --- builtin/update-ref.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/builtin/update-ref.c b/builtin/update-ref.c index 381d347fb4..0f34b68904 100644 --- a/builtin/update-ref.c +++ b/builtin/update-ref.c @@ -332,15 +332,21 @@ static const struct parse_cmd { { "option", parse_cmd_option }, }; -static void update_refs_stdin(struct ref_transaction *transaction) +static void update_refs_stdin(void) { - struct strbuf input = STRBUF_INIT; + struct strbuf input = STRBUF_INIT, err = STRBUF_INIT; + struct ref_transaction *transaction; const char *next; int i; if (strbuf_read(&input, 0, 1000) < 0) die_errno("could not read from stdin"); next = input.buf; + + transaction = ref_transaction_begin(&err); + if (!transaction) + die("%s", err.buf); + /* Read each line dispatch its command */ while (next < input.buf + input.len) { const struct parse_cmd *cmd = NULL; @@ -367,6 +373,11 @@ static void update_refs_stdin(struct ref_transaction *transaction) next++; } + if (ref_transaction_commit(transaction, &err)) + die("%s", err.buf); + + ref_transaction_free(transaction); + strbuf_release(&err); strbuf_release(&input); } @@ -401,21 +412,11 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix) } if (read_stdin) { - struct strbuf err = STRBUF_INIT; - struct ref_transaction *transaction; - - transaction = ref_transaction_begin(&err); - if (!transaction) - die("%s", err.buf); if (delete || argc > 0) usage_with_options(git_update_ref_usage, options); if (end_null) line_termination = '\0'; - update_refs_stdin(transaction); - if (ref_transaction_commit(transaction, &err)) - die("%s", err.buf); - ref_transaction_free(transaction); - strbuf_release(&err); + update_refs_stdin(); return 0; } From patchwork Thu Apr 2 07:09:57 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 11470197 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 751C01392 for ; Thu, 2 Apr 2020 07:09:55 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 411D92078E for ; Thu, 2 Apr 2020 07:09:55 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="Rn21MBAe"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="f4rsYwjH" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2387545AbgDBHJy (ORCPT ); Thu, 2 Apr 2020 03:09:54 -0400 Received: from out3-smtp.messagingengine.com ([66.111.4.27]:51147 "EHLO out3-smtp.messagingengine.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725789AbgDBHJy (ORCPT ); Thu, 2 Apr 2020 03:09:54 -0400 Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.nyi.internal (Postfix) with ESMTP id EE1B95C028D; Thu, 2 Apr 2020 03:09:52 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute3.internal (MEProxy); Thu, 02 Apr 2020 03:09:52 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=date :from:to:cc:subject:message-id:references:mime-version :content-type:in-reply-to; s=fm3; bh=JNtzGwZ7jYj24wKTpl9eK6iafaT igj7Es7cpy3cEbX8=; b=Rn21MBAenS5x3OYbg4TJkhwwLmd1x7j4CmOIWb3So2W RNfex6+vJGlvNMWnY+gjgA5+2IeTd0Ze6C309Ndqo6y0CvlWg0oGtTwC0B51q6jf Hudowv6fnGsPR9qH8jygokrKgWdR33Xsav7dwtS/y9lN4s017Sgj09TUkhKMNdFI CTvT04qVnMf/3wKDv0PlfYRI88I897kpXS0jaMpZP6PUW7Zn0NAhLSBbfQFqGwxH T1ln8G3qaxS7b8fZR6rwaWSCAfTNwi5m14Me3Syzb8t/Kb+q1xdsmGmdkiQ0y1Qp rkkPmobtWUCdlU4cZSNQmFbKVaACWO3rW5VxrvdMKrA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to:x-me-proxy :x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm2; bh=JNtzGw Z7jYj24wKTpl9eK6iafaTigj7Es7cpy3cEbX8=; b=f4rsYwjH1nAewFV+b/zjFf ynm/wrOcfWp89Bb5MzP4FY9QD5MQKcQHTkth0i2jVFELj5SPcxbGxaEZOc4g3rn6 ljJZvQJbhYRoVy3nX84DyqaYlfZKLvfVKle1jaO4Ciy+X2hQFOQiGaYrqhqwd7MW 4m2oX4Jlbs0dLpPRPC49TwKctNk3amZ7nsSg6YebGA+20OBwn1ttM57AoUFmFLMF 1xIBthP32m1kzW8EEJkdksMTMtspa7cw7OqbqvqQCcgGMfAPIHqFvBrEcBscUPvC JD2Cuaeiz84ZZWdEDX8E+tnTLAlK4VCONYhiJGQ4rfNf7XDzLSSvih3CjXBIN8gg == X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeduhedrtdefgdduudejucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvffukfhfgggtuggjsehgtderredttddvnecuhfhrohhmpefrrghtrhhi tghkucfuthgvihhnhhgrrhguthcuoehpshesphhkshdrihhmqeenucfkphepkeelrdduvd drleegrddvkeenucevlhhushhtvghrufhiiigvpedunecurfgrrhgrmhepmhgrihhlfhhr ohhmpehpshesphhkshdrihhm X-ME-Proxy: Received: from vm-mail.pks.im (x590c5e1c.dyn.telefonica.de [89.12.94.28]) by mail.messagingengine.com (Postfix) with ESMTPA id 42FD7306CDC1; Thu, 2 Apr 2020 03:09:52 -0400 (EDT) Received: from localhost (ncase [10.192.0.11]) by vm-mail.pks.im (OpenSMTPD) with ESMTPSA id 8264c6c8 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Thu, 2 Apr 2020 07:09:50 +0000 (UTC) Date: Thu, 2 Apr 2020 09:09:57 +0200 From: Patrick Steinhardt To: git Cc: Christian Couder , Junio C Hamano Subject: [PATCH v3 8/9] update-ref: read commands in a line-wise fashion Message-ID: <02ff6b7337cd821c74f2221c2c567e0105c01e0d.1585811014.git.ps@pks.im> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org The git-update-ref(1) supports a `--stdin` mode that allows it to read all reference updates from standard input. This is mainly used to allow for atomic reference updates that are all or nothing, so that either all references will get updated or none. Currently, git-update-ref(1) reads all commands as a single block of up to 1000 characters and only starts processing after stdin gets closed. This is less flexible than one might wish for, as it doesn't really allow for longer-lived transactions and doesn't allow any verification without committing everything. E.g. one may imagine the following exchange: > start < start: ok > update refs/heads/master $NEWOID1 $OLDOID1 > update refs/heads/branch $NEWOID2 $OLDOID2 > prepare < prepare: ok > commit < commit: ok When reading all input as a whole block, the above interactive protocol is obviously impossible to achieve. But by converting the command to read commands linewise, we can make it more interactive than before. Obviously, the linewise interface is only a first step in making git-update-ref(1) work in a more transaction-oriented way. Missing is most importantly support for transactional commands that manage the current transaction. Signed-off-by: Patrick Steinhardt --- builtin/update-ref.c | 85 +++++++++++++++++++++++--------------------- 1 file changed, 45 insertions(+), 40 deletions(-) diff --git a/builtin/update-ref.c b/builtin/update-ref.c index 0f34b68904..348407b896 100644 --- a/builtin/update-ref.c +++ b/builtin/update-ref.c @@ -178,8 +178,8 @@ static int parse_next_oid(const char **next, const char *end, * depending on how line_termination is set. */ -static const char *parse_cmd_update(struct ref_transaction *transaction, - const char *next, const char *end) +static void parse_cmd_update(struct ref_transaction *transaction, + const char *next, const char *end) { struct strbuf err = STRBUF_INIT; char *refname; @@ -209,12 +209,10 @@ static const char *parse_cmd_update(struct ref_transaction *transaction, update_flags = default_flags; free(refname); strbuf_release(&err); - - return next; } -static const char *parse_cmd_create(struct ref_transaction *transaction, - const char *next, const char *end) +static void parse_cmd_create(struct ref_transaction *transaction, + const char *next, const char *end) { struct strbuf err = STRBUF_INIT; char *refname; @@ -241,12 +239,10 @@ static const char *parse_cmd_create(struct ref_transaction *transaction, update_flags = default_flags; free(refname); strbuf_release(&err); - - return next; } -static const char *parse_cmd_delete(struct ref_transaction *transaction, - const char *next, const char *end) +static void parse_cmd_delete(struct ref_transaction *transaction, + const char *next, const char *end) { struct strbuf err = STRBUF_INIT; char *refname; @@ -277,12 +273,10 @@ static const char *parse_cmd_delete(struct ref_transaction *transaction, update_flags = default_flags; free(refname); strbuf_release(&err); - - return next; } -static const char *parse_cmd_verify(struct ref_transaction *transaction, - const char *next, const char *end) +static void parse_cmd_verify(struct ref_transaction *transaction, + const char *next, const char *end) { struct strbuf err = STRBUF_INIT; char *refname; @@ -306,71 +300,82 @@ static const char *parse_cmd_verify(struct ref_transaction *transaction, update_flags = default_flags; free(refname); strbuf_release(&err); - - return next; } -static const char *parse_cmd_option(struct ref_transaction *transaction, - const char *next, const char *end) +static void parse_cmd_option(struct ref_transaction *transaction, + const char *next, const char *end) { const char *rest; if (skip_prefix(next, "no-deref", &rest) && *rest == line_termination) update_flags |= REF_NO_DEREF; else die("option unknown: %s", next); - return rest; } static const struct parse_cmd { const char *prefix; - const char *(*fn)(struct ref_transaction *, const char *, const char *); + void (*fn)(struct ref_transaction *, const char *, const char *); + unsigned args; } command[] = { - { "update", parse_cmd_update }, - { "create", parse_cmd_create }, - { "delete", parse_cmd_delete }, - { "verify", parse_cmd_verify }, - { "option", parse_cmd_option }, + { "update", parse_cmd_update, 3 }, + { "create", parse_cmd_create, 2 }, + { "delete", parse_cmd_delete, 2 }, + { "verify", parse_cmd_verify, 2 }, + { "option", parse_cmd_option, 1 }, }; static void update_refs_stdin(void) { struct strbuf input = STRBUF_INIT, err = STRBUF_INIT; struct ref_transaction *transaction; - const char *next; - int i; - - if (strbuf_read(&input, 0, 1000) < 0) - die_errno("could not read from stdin"); - next = input.buf; + int i, j; transaction = ref_transaction_begin(&err); if (!transaction) die("%s", err.buf); /* Read each line dispatch its command */ - while (next < input.buf + input.len) { + while (!strbuf_getwholeline(&input, stdin, line_termination)) { const struct parse_cmd *cmd = NULL; - if (*next == line_termination) + if (*input.buf == line_termination) die("empty command in input"); - else if (isspace(*next)) - die("whitespace before command: %s", next); + else if (isspace(*input.buf)) + die("whitespace before command: %s", input.buf); for (i = 0; i < ARRAY_SIZE(command); i++) { const char *prefix = command[i].prefix; + char c; - if (!skip_prefix(next, prefix, &next) || - !skip_prefix(next, " ", &next)) + if (!starts_with(input.buf, prefix)) + continue; + + /* + * If the command has arguments, verify that it's + * followed by a space. Otherwise, it shall be followed + * by a line terminator. + */ + c = command[i].args ? ' ' : line_termination; + if (input.buf[strlen(prefix)] != c) continue; cmd = &command[i]; break; } if (!cmd) - die("unknown command: %s", next); + die("unknown command: %s", input.buf); - next = cmd->fn(transaction, next, input.buf + input.len); - next++; + /* + * Read additional arguments if NUL-terminated. Do not raise an + * error in case there is an early EOF to let the command + * handle missing arguments with a proper error message. + */ + for (j = 1; line_termination == '\0' && j < cmd->args; j++) + if (strbuf_appendwholeline(&input, stdin, line_termination)) + break; + + cmd->fn(transaction, input.buf + strlen(cmd->prefix) + !!cmd->args, + input.buf + input.len); } if (ref_transaction_commit(transaction, &err)) From patchwork Thu Apr 2 07:10:02 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 11470201 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 1EDA61392 for ; Thu, 2 Apr 2020 07:10:01 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id DB72F20784 for ; Thu, 2 Apr 2020 07:10:00 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="tEs1Uglx"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="gWCs/Hft" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2387547AbgDBHJ7 (ORCPT ); Thu, 2 Apr 2020 03:09:59 -0400 Received: from out3-smtp.messagingengine.com ([66.111.4.27]:34753 "EHLO out3-smtp.messagingengine.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725789AbgDBHJ7 (ORCPT ); Thu, 2 Apr 2020 03:09:59 -0400 Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.nyi.internal (Postfix) with ESMTP id AD5D15C028F; Thu, 2 Apr 2020 03:09:57 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute3.internal (MEProxy); Thu, 02 Apr 2020 03:09:57 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=date :from:to:cc:subject:message-id:references:mime-version :content-type:in-reply-to; s=fm3; bh=gHKhqEzfzf+pJT3EE9SPXsIspcI 0LdiWVpadawE2gD4=; b=tEs1Uglx7uBG23fvkanhrl04uLFPanzsL/WUfvpcfK3 g2UIgnvHtqvZ7aqrgKCChaYm2+9mDMnwsi7nGUOhYy59KHaJ6Rp5ttvdUZC5Plun dy1hxaFFYwR7Ckq3GZzBZ1vDYrb6fwvfK7g89AvTS4+d7WoNOgY9t+4EICuI2uvQ QewgD6bZcyeWTPPUNyUMuCZWBN9l7S/VYCEZPszudfnC6XvW2yZKfqcFFd9ZTwfC JmpDLyLdOsgoU5tzqPjifV2YedMcQLmKnbEMUCca75Ef9xCr3J0U3UbLGuM93okV LghEvqGwUNHJLhUk2GRbj8W4NoggUBtbsdTl2xmpUXw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to:x-me-proxy :x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm2; bh=gHKhqE zfzf+pJT3EE9SPXsIspcI0LdiWVpadawE2gD4=; b=gWCs/HftM6YVx6FforCMmU Ix1vzsQdKtzVzGYir1XOc0c2xbijnwS36PjO8AzcDhzpESuYPn/Tg5aMJj2bTk3S /hCXMAw6ojvgywTswQowX3IjpCQPOzt5f3gTGONBbAFwB5TjOlIHsCFgYZvQj8sD hRKpZ9Y4B9X8S0hPKkvKT+Qyt6iL5+64fHbWQEpGh5bQiBsB/qCyaIkvbBeCSVMZ /RFenC8aoG/vdPQo9uEDoYOnLdOkRZEluypgjJTxVHaeRO6M/DbWRLR0eGX8ON+/ hZyi0+WuHJTgOLi5D86+X7KgCd2PRy9Y1Bn00UpErDZSjwVlTh8M3HUaZQwrfhMA == X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeduhedrtdefgdduudejucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvffukfhfgggtuggjsehgtderredttddvnecuhfhrohhmpefrrghtrhhi tghkucfuthgvihhnhhgrrhguthcuoehpshesphhkshdrihhmqeenucfkphepkeelrdduvd drleegrddvkeenucevlhhushhtvghrufhiiigvpedvnecurfgrrhgrmhepmhgrihhlfhhr ohhmpehpshesphhkshdrihhm X-ME-Proxy: Received: from vm-mail.pks.im (x590c5e1c.dyn.telefonica.de [89.12.94.28]) by mail.messagingengine.com (Postfix) with ESMTPA id 0137F306CDA9; Thu, 2 Apr 2020 03:09:56 -0400 (EDT) Received: from localhost (ncase [10.192.0.11]) by vm-mail.pks.im (OpenSMTPD) with ESMTPSA id 91e464ce (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Thu, 2 Apr 2020 07:09:55 +0000 (UTC) Date: Thu, 2 Apr 2020 09:10:02 +0200 From: Patrick Steinhardt To: git Cc: Christian Couder , Junio C Hamano Subject: [PATCH v3 9/9] update-ref: implement interactive transaction handling Message-ID: <5670bea2b15bafbd93d7d507b35e54980ad06fb9.1585811014.git.ps@pks.im> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org The git-update-ref(1) command can only handle queueing transactions right now via its "--stdin" parameter, but there is no way for users to handle the transaction itself in a more explicit way. E.g. in a replicated scenario, one may imagine a coordinator that spawns git-update-ref(1) for multiple repositories and only if all agree that an update is possible will the coordinator send a commit. Such a transactional session could look like > start < start: ok > update refs/heads/master $OLD $NEW > prepare < prepare: ok # All nodes have returned "ok" > commit < commit: ok or > start < start: ok > create refs/heads/master $OLD $NEW > prepare < fatal: cannot lock ref 'refs/heads/master': reference already exists # On all other nodes: > abort < abort: ok In order to allow for such transactional sessions, this commit introduces four new commands for git-update-ref(1), which matches those we have internally already with the exception of "start": - start: start a new transaction - prepare: prepare the transaction, that is try to lock all references and verify their current value matches the expected one - commit: explicitly commit a session, that is update references to match their new expected state - abort: abort a session and roll back all changes By design, git-update-ref(1) will commit as soon as standard input is being closed. While fine in a non-transactional world, it is definitely unexpected in a transactional world. Because of this, as soon as any of the new transactional commands is used, the default will change to aborting without an explicit "commit". To avoid a race between queueing updates and the first "prepare" that starts a transaction, the "start" command has been added to start an explicit transaction. Add some tests to exercise this new functionality. Signed-off-by: Patrick Steinhardt --- Documentation/git-update-ref.txt | 26 ++++++ builtin/update-ref.c | 106 +++++++++++++++++++++++-- t/t1400-update-ref.sh | 131 +++++++++++++++++++++++++++++++ 3 files changed, 255 insertions(+), 8 deletions(-) diff --git a/Documentation/git-update-ref.txt b/Documentation/git-update-ref.txt index 9bd039ce08..3e737c2360 100644 --- a/Documentation/git-update-ref.txt +++ b/Documentation/git-update-ref.txt @@ -66,6 +66,10 @@ performs all modifications together. Specify commands of the form: delete SP [SP ] LF verify SP [SP ] LF option SP LF + start LF + prepare LF + commit LF + abort LF With `--create-reflog`, update-ref will create a reflog for each ref even if one would not ordinarily be created. @@ -83,6 +87,10 @@ quoting: delete SP NUL [] NUL verify SP NUL [] NUL option SP NUL + start NUL + prepare NUL + commit NUL + abort NUL In this format, use 40 "0" to specify a zero value, and use the empty string to specify a missing value. @@ -114,6 +122,24 @@ option:: The only valid option is `no-deref` to avoid dereferencing a symbolic ref. +start:: + Start a transaction. In contrast to a non-transactional session, a + transaction will automatically abort if the session ends without an + explicit commit. + +prepare:: + Prepare to commit the transaction. This will create lock files for all + queued reference updates. If one reference could not be locked, the + transaction will be aborted. + +commit:: + Commit all reference updates queued for the transaction, ending the + transaction. + +abort:: + Abort the transaction, releasing all locks if the transaction is in + prepared state. + If all s can be locked with matching s simultaneously, all modifications are performed. Otherwise, no modifications are performed. Note that while each individual diff --git a/builtin/update-ref.c b/builtin/update-ref.c index 348407b896..b74dd9a69d 100644 --- a/builtin/update-ref.c +++ b/builtin/update-ref.c @@ -312,21 +312,80 @@ static void parse_cmd_option(struct ref_transaction *transaction, die("option unknown: %s", next); } +static void parse_cmd_start(struct ref_transaction *transaction, + const char *next, const char *end) +{ + if (*next != line_termination) + die("start: extra input: %s", next); + puts("start: ok"); +} + +static void parse_cmd_prepare(struct ref_transaction *transaction, + const char *next, const char *end) +{ + struct strbuf error = STRBUF_INIT; + if (*next != line_termination) + die("prepare: extra input: %s", next); + if (ref_transaction_prepare(transaction, &error)) + die("prepare: %s", error.buf); + puts("prepare: ok"); +} + +static void parse_cmd_abort(struct ref_transaction *transaction, + const char *next, const char *end) +{ + struct strbuf error = STRBUF_INIT; + if (*next != line_termination) + die("abort: extra input: %s", next); + if (ref_transaction_abort(transaction, &error)) + die("abort: %s", error.buf); + puts("abort: ok"); +} + +static void parse_cmd_commit(struct ref_transaction *transaction, + const char *next, const char *end) +{ + struct strbuf error = STRBUF_INIT; + if (*next != line_termination) + die("commit: extra input: %s", next); + if (ref_transaction_commit(transaction, &error)) + die("commit: %s", error.buf); + puts("commit: ok"); + ref_transaction_free(transaction); +} + +enum update_refs_state { + /* Non-transactional state open for updates. */ + UPDATE_REFS_OPEN, + /* A transaction has been started. */ + UPDATE_REFS_STARTED, + /* References are locked and ready for commit */ + UPDATE_REFS_PREPARED, + /* Transaction has been committed or closed. */ + UPDATE_REFS_CLOSED, +}; + static const struct parse_cmd { const char *prefix; void (*fn)(struct ref_transaction *, const char *, const char *); unsigned args; + enum update_refs_state state; } command[] = { - { "update", parse_cmd_update, 3 }, - { "create", parse_cmd_create, 2 }, - { "delete", parse_cmd_delete, 2 }, - { "verify", parse_cmd_verify, 2 }, - { "option", parse_cmd_option, 1 }, + { "update", parse_cmd_update, 3, UPDATE_REFS_OPEN }, + { "create", parse_cmd_create, 2, UPDATE_REFS_OPEN }, + { "delete", parse_cmd_delete, 2, UPDATE_REFS_OPEN }, + { "verify", parse_cmd_verify, 2, UPDATE_REFS_OPEN }, + { "option", parse_cmd_option, 1, UPDATE_REFS_OPEN }, + { "start", parse_cmd_start, 0, UPDATE_REFS_STARTED }, + { "prepare", parse_cmd_prepare, 0, UPDATE_REFS_PREPARED }, + { "abort", parse_cmd_abort, 0, UPDATE_REFS_CLOSED }, + { "commit", parse_cmd_commit, 0, UPDATE_REFS_CLOSED }, }; static void update_refs_stdin(void) { struct strbuf input = STRBUF_INIT, err = STRBUF_INIT; + enum update_refs_state state = UPDATE_REFS_OPEN; struct ref_transaction *transaction; int i, j; @@ -374,14 +433,45 @@ static void update_refs_stdin(void) if (strbuf_appendwholeline(&input, stdin, line_termination)) break; + switch (state) { + case UPDATE_REFS_OPEN: + case UPDATE_REFS_STARTED: + /* Do not downgrade a transaction to a non-transaction. */ + if (cmd->state >= state) + state = cmd->state; + break; + case UPDATE_REFS_PREPARED: + if (cmd->state != UPDATE_REFS_CLOSED) + die("prepared transactions can only be closed"); + state = cmd->state; + break; + case UPDATE_REFS_CLOSED: + die("transaction is closed"); + break; + } + cmd->fn(transaction, input.buf + strlen(cmd->prefix) + !!cmd->args, input.buf + input.len); } - if (ref_transaction_commit(transaction, &err)) - die("%s", err.buf); + switch (state) { + case UPDATE_REFS_OPEN: + /* Commit by default if no transaction was requested. */ + if (ref_transaction_commit(transaction, &err)) + die("%s", err.buf); + ref_transaction_free(transaction); + break; + case UPDATE_REFS_STARTED: + case UPDATE_REFS_PREPARED: + /* If using a transaction, we want to abort it. */ + if (ref_transaction_abort(transaction, &err)) + die("%s", err.buf); + break; + case UPDATE_REFS_CLOSED: + /* Otherwise no need to do anything, the transaction was closed already. */ + break; + } - ref_transaction_free(transaction); strbuf_release(&err); strbuf_release(&input); } diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh index a6224ef65f..48d0d42afd 100755 --- a/t/t1400-update-ref.sh +++ b/t/t1400-update-ref.sh @@ -1404,4 +1404,135 @@ test_expect_success 'handle per-worktree refs in refs/bisect' ' ! test_cmp main-head worktree-head ' +test_expect_success 'transaction handles empty commit' ' + cat >stdin <<-EOF && + start + prepare + commit + EOF + git update-ref --stdin actual && + printf "%s: ok\n" start prepare commit >expect && + test_cmp expect actual +' + +test_expect_success 'transaction handles empty commit with missing prepare' ' + cat >stdin <<-EOF && + start + commit + EOF + git update-ref --stdin actual && + printf "%s: ok\n" start commit >expect && + test_cmp expect actual +' + +test_expect_success 'transaction handles sole commit' ' + cat >stdin <<-EOF && + commit + EOF + git update-ref --stdin actual && + printf "%s: ok\n" commit >expect && + test_cmp expect actual +' + +test_expect_success 'transaction handles empty abort' ' + cat >stdin <<-EOF && + start + prepare + abort + EOF + git update-ref --stdin actual && + printf "%s: ok\n" start prepare abort >expect && + test_cmp expect actual +' + +test_expect_success 'transaction exits on multiple aborts' ' + cat >stdin <<-EOF && + abort + abort + EOF + test_must_fail git update-ref --stdin actual 2>err && + printf "%s: ok\n" abort >expect && + test_cmp expect actual && + grep "fatal: transaction is closed" err +' + +test_expect_success 'transaction exits on start after prepare' ' + cat >stdin <<-EOF && + prepare + start + EOF + test_must_fail git update-ref --stdin err >actual && + printf "%s: ok\n" prepare >expect && + test_cmp expect actual && + grep "fatal: prepared transactions can only be closed" err +' + +test_expect_success 'transaction handles empty abort with missing prepare' ' + cat >stdin <<-EOF && + start + abort + EOF + git update-ref --stdin actual && + printf "%s: ok\n" start abort >expect && + test_cmp expect actual +' + +test_expect_success 'transaction handles sole abort' ' + cat >stdin <<-EOF && + abort + EOF + git update-ref --stdin actual && + printf "%s: ok\n" abort >expect && + test_cmp expect actual +' + +test_expect_success 'transaction can handle commit' ' + cat >stdin <<-EOF && + start + create $a HEAD + commit + EOF + git update-ref --stdin actual && + printf "%s: ok\n" start commit >expect && + test_cmp expect actual && + git rev-parse HEAD >expect && + git rev-parse $a >actual && + test_cmp expect actual +' + +test_expect_success 'transaction can handle abort' ' + cat >stdin <<-EOF && + start + create $b HEAD + abort + EOF + git update-ref --stdin actual && + printf "%s: ok\n" start abort >expect && + test_cmp expect actual && + test_path_is_missing .git/$b +' + +test_expect_success 'transaction aborts by default' ' + cat >stdin <<-EOF && + start + create $b HEAD + EOF + git update-ref --stdin actual && + printf "%s: ok\n" start >expect && + test_cmp expect actual && + test_path_is_missing .git/$b +' + +test_expect_success 'transaction with prepare aborts by default' ' + cat >stdin <<-EOF && + start + create $b HEAD + prepare + EOF + git update-ref --stdin actual && + printf "%s: ok\n" start prepare >expect && + test_cmp expect actual && + test_path_is_missing .git/$b +' + test_done