From patchwork Mon Mar 30 13:46:13 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 11465533 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 30018159A for ; Mon, 30 Mar 2020 13:46:17 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 041FF2083E for ; Mon, 30 Mar 2020 13:46:17 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="ri9croex"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="ugFGtnLX" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728490AbgC3NqO (ORCPT ); Mon, 30 Mar 2020 09:46:14 -0400 Received: from wout4-smtp.messagingengine.com ([64.147.123.20]:38513 "EHLO wout4-smtp.messagingengine.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728065AbgC3NqO (ORCPT ); Mon, 30 Mar 2020 09:46:14 -0400 Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.west.internal (Postfix) with ESMTP id BE4A756E; Mon, 30 Mar 2020 09:46:13 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute3.internal (MEProxy); Mon, 30 Mar 2020 09:46:14 -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=8M+IWyqMnQpI+Y2/7DcyTaNJhBg 6gmwOqb1prWZCwns=; b=ri9croex3IdYVbV2t/rJZHxtBBIeH7V9FTMyNiqXU2t dFTI63EihZAoGMUZOzuGOV0SHPCC5hQhUV++x3YZsAT5Y+H5m7o+mtYZ6pcJFCh7 E2otpyIIO19VXz2kKr2+v4wI+kgv9rRfG1TICl2UPDhkPRxRcsv36TSHfGJ4l2n2 6fxD6WvR5hIflceuRbMSL30zI6CAfiYG3qD5OkpSYSlaAiFRAr6/Hb9C0yh2YZMT T6wMO+HyHdC3DTu6mNDG+ZTHU2B9jXX+x665A4cTwwYRmAKY2bhAN3ecMRMY2ZHz 9I+sy15/AEo5hV/mePPHD2y1s2tG2HURE/mPDcygouA== 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=8M+IWy qMnQpI+Y2/7DcyTaNJhBg6gmwOqb1prWZCwns=; b=ugFGtnLX6QCIw1NMFkpN4Z qtH+WpXAyg70bROGz68cR4u7D7YCkcSbfmUXqcwUEnDtbD2Xuy0eDDU8Jm/aksBj UFYh1RQQWqGlVBzkF7qZHtXLVEy8dOHev0yjUtfx3ezGa1SCR7gWAU6VqedS2Pd/ C+zUhQJ8aHFMHf5NyrMx8nxvZ6J3nSdlNXOJIdx3OaDIBcGYc1bPHez1k1DdCP7i dUf4KR4A/z2QMWgaymRLUTQVHxn1ZT6f5zj/lOmkMd6iEolNfnPr52OAUu/qoqH5 6RMU7TKakjOZZRuP5Mh/ZiMRjcPn4NuZyvb6+eAqdJs8bDl51swBsSv5B2LroO5A == X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedugedrudeihedgieekucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvffukfhfgggtuggjsehgtderredttddvnecuhfhrohhmpefrrghtrhhi tghkucfuthgvihhnhhgrrhguthcuoehpshesphhkshdrihhmqeenucfkphepjeekrdehge drvddvtddruddtvdenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhl fhhrohhmpehpshesphhkshdrihhm X-ME-Proxy: Received: from vm-mail.pks.im (x4e36dc66.dyn.telefonica.de [78.54.220.102]) by mail.messagingengine.com (Postfix) with ESMTPA id 000C4328005E; Mon, 30 Mar 2020 09:46:11 -0400 (EDT) Received: from localhost (ncase [10.192.0.11]) by vm-mail.pks.im (OpenSMTPD) with ESMTPSA id 8d61d332 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Mon, 30 Mar 2020 13:46:10 +0000 (UTC) Date: Mon, 30 Mar 2020 15:46:13 +0200 From: Patrick Steinhardt To: git Cc: Christian Couder , Junio C Hamano Subject: [PATCH v2 1/9] refs: fix segfault when aborting empty transaction Message-ID: <7a297db4daaee84dc90ddeaa8f77b68a39231ef1.1585575749.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 Mon Mar 30 13:46:20 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 11465537 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 CDFA8913 for ; Mon, 30 Mar 2020 13:46:21 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id ACFF420776 for ; Mon, 30 Mar 2020 13:46:21 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="qFjaPHhi"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="4MznmEux" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728481AbgC3NqV (ORCPT ); Mon, 30 Mar 2020 09:46:21 -0400 Received: from wout4-smtp.messagingengine.com ([64.147.123.20]:45589 "EHLO wout4-smtp.messagingengine.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728129AbgC3NqU (ORCPT ); Mon, 30 Mar 2020 09:46:20 -0400 Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.west.internal (Postfix) with ESMTP id 6D96B6E6; Mon, 30 Mar 2020 09:46:19 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute3.internal (MEProxy); Mon, 30 Mar 2020 09:46:19 -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=WwD6Mox/y9Q6/fDAXt1lViLUbJH EfB7d0Dyskob1DH0=; b=qFjaPHhiMgDx0pannIysVbRtsXPQu6+lNE3HHLDRPt7 NCwhB4cK719Yf2ATpS39gwGt/Mo11IeRKqp3wMOQ5yh6vqHKcQ9ZPY6BADUBwBMv jTlm7uhfny/jfxkOhtE/S6iitCjLSDJGZ7IbxwFnNUXmTBHwIozyQCAYGIyFycLx F+UfkIdg24jznj3ssrYuLh5oa7xRnVV03+0TjZZuPNlBdovfOaGXZGM5AFPcc4E/ L0yEHy7mwxfQ1VMl/o+Zl8gS/+ua7S6A8ELR97PgQk8ZVDd4FL3/4bXnNr4tfJ9P 166JOfESXVU1tBp79LQq2D1iZjw4hStSS/ptro11Yxw== 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=WwD6Mo x/y9Q6/fDAXt1lViLUbJHEfB7d0Dyskob1DH0=; b=4MznmEux0zHm8+gP6KwABi NZOO4+sYs1slpohhezrlULOf138Z7UvtMvJQc9Jq5IMtVAF4p7MHATXDsrwtHXMU 9IqQIMkam2/z/RPslPEctvoNTaCso2fiZQV5AnZDxp3INSDx2nb7pENgokvskTnC YYgvHaYv0ON/lTLCep8cmKEJyhzGykcY7gr7DJ5+NnAE0QRyls1lktjQ+w1nyV23 rMRZxM21WQcrSafOKKO0DXbYeRlxpfPogqotlLdo+ueAgBtwGOhufM5pjSHRpGOH aCqNdJUWgu4PUR0FbGLhlVnzp3q4sjuv2r/jNnUQt8Yxh/ahknhT/tm46CKYNuPg == X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedugedrudeihedgieekucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvffukfhfgggtuggjsehgtderredttddvnecuhfhrohhmpefrrghtrhhi tghkucfuthgvihhnhhgrrhguthcuoehpshesphhkshdrihhmqeenucfkphepjeekrdehge drvddvtddruddtvdenucevlhhushhtvghrufhiiigvpedvnecurfgrrhgrmhepmhgrihhl fhhrohhmpehpshesphhkshdrihhm X-ME-Proxy: Received: from vm-mail.pks.im (x4e36dc66.dyn.telefonica.de [78.54.220.102]) by mail.messagingengine.com (Postfix) with ESMTPA id 601573280064; Mon, 30 Mar 2020 09:46:18 -0400 (EDT) Received: from localhost (ncase [10.192.0.11]) by vm-mail.pks.im (OpenSMTPD) with ESMTPSA id e8906590 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Mon, 30 Mar 2020 13:46:16 +0000 (UTC) Date: Mon, 30 Mar 2020 15:46:20 +0200 From: Patrick Steinhardt To: git Cc: Christian Couder , Junio C Hamano Subject: [PATCH v2 2/9] git-update-ref.txt: add missing word Message-ID: <15857e1b8ca800a92fa96fee818a54456bfbd330.1585575749.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 Mon Mar 30 13:46: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: 11465539 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 1BD5F913 for ; Mon, 30 Mar 2020 13:46:28 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id ECFD92073B for ; Mon, 30 Mar 2020 13:46:27 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="U4RK8Q6X"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="fhp/DU67" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728504AbgC3Nq1 (ORCPT ); Mon, 30 Mar 2020 09:46:27 -0400 Received: from wout4-smtp.messagingengine.com ([64.147.123.20]:60103 "EHLO wout4-smtp.messagingengine.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728065AbgC3Nq1 (ORCPT ); Mon, 30 Mar 2020 09:46:27 -0400 Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.west.internal (Postfix) with ESMTP id 16EAC6EA; Mon, 30 Mar 2020 09:46:26 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute3.internal (MEProxy); Mon, 30 Mar 2020 09:46:26 -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=aGdIsIuEkIsBzUW2WZeuoU2T9ED WX+IFhO79ANbcgfE=; b=U4RK8Q6Xnn5Xmwmp4/JSTcBhkTAxXXZNE021X+npBin cuN2RLoI0nz1qbgDf0sntL93G+kQFIJqUtPEDSPHRQhaPhDOD4iRGKkPTIWVCy/X qmMtlMhvf6iAZResLwAI6IbGPWqkqzVsxtXY98KsypbkVHbLXLzRBaFr1f2lIQSP H8FeGu6Bg//t1M/y475ZZ6WnHiKjgxr/5zqMUJ4pHrtoLm+Lxh1GxvzrATSA63Qm ynMNlbN2qVP5ysHM0HuLeHFW62AwzCnMO6VmdIeTkvDWqbPA+P7SAKadeBPqwFJt neG9ZQqRfLH0R5gj1oah9CURoECZfdpphjmoaxDxxLA== 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=aGdIsI uEkIsBzUW2WZeuoU2T9EDWX+IFhO79ANbcgfE=; b=fhp/DU67sXvFWxkx5wnAoH y16EqDmO3SsHxV/XIpf3NNb3xbJkYiTJtKnhnmkWVwoIC6cw6cemzDQHqSwCtdu6 F04ZUlk6dDLx6yOljRQK4vQtWGLav4yR17bAsST1dBoObW8Eh6P7NiSLhc0XO4bx EWb100l+/lrz7WP38sxb9e+0CK/813AMUyScH+M5yk36gO+JFQpax/5ZmejAjZiK snEptuDwp6yRENRTkrIaQr+/LhYBEgLkA93+iaVKj04Z9ViPc462GXlRek8Air3Y mygO50TVm7gWLURO8Wf0a1gkg8IGXXZGK/lduhcmBHZ9RRef1yTq0KT96Jkcj6iQ == X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedugedrudeihedgieekucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvffukfhfgggtuggjsehgtderredttddvnecuhfhrohhmpefrrghtrhhi tghkucfuthgvihhnhhgrrhguthcuoehpshesphhkshdrihhmqeenucfkphepjeekrdehge drvddvtddruddtvdenucevlhhushhtvghrufhiiigvpeefnecurfgrrhgrmhepmhgrihhl fhhrohhmpehpshesphhkshdrihhm X-ME-Proxy: Received: from vm-mail.pks.im (x4e36dc66.dyn.telefonica.de [78.54.220.102]) by mail.messagingengine.com (Postfix) with ESMTPA id 25C343280069; Mon, 30 Mar 2020 09:46:25 -0400 (EDT) Received: from localhost (ncase [10.192.0.11]) by vm-mail.pks.im (OpenSMTPD) with ESMTPSA id 0f18be8f (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Mon, 30 Mar 2020 13:46:23 +0000 (UTC) Date: Mon, 30 Mar 2020 15:46:27 +0200 From: Patrick Steinhardt To: git Cc: Christian Couder , Junio C Hamano Subject: [PATCH v2 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 Mon Mar 30 13:46: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: 11465541 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 E56B8159A for ; Mon, 30 Mar 2020 13:46:33 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id B810720757 for ; Mon, 30 Mar 2020 13:46:33 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="ZJDjpnYC"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="k4IqQqab" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728517AbgC3Nqd (ORCPT ); Mon, 30 Mar 2020 09:46:33 -0400 Received: from wout4-smtp.messagingengine.com ([64.147.123.20]:46345 "EHLO wout4-smtp.messagingengine.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728065AbgC3Nqc (ORCPT ); Mon, 30 Mar 2020 09:46:32 -0400 Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.west.internal (Postfix) with ESMTP id C12CE3AA; Mon, 30 Mar 2020 09:46:31 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute3.internal (MEProxy); Mon, 30 Mar 2020 09:46:32 -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=1f1Lu6keEugHfrxsIQge5geVX55 q+O8JboNY7AbEoRQ=; b=ZJDjpnYC1mo5UcGl5EcbfpyPklT+Wv5do90H4SlsPkj NY6eCvOdwOt2ZrV3AERunyw6x92iFvMWRRNyU/5Lez1YZNoQ8BI+O41P/8quZPwC 0aUvWVqMkg88R54l1RmKwWGMn53C/WypPREIbfMRpwM/i5+8z9VOutNa8iSe+Xl8 6skKKnyRjV+2XCga/mRV1rkf+kDDeSRf81YRF601r6/p9u7VfdXzAWJgfNuVbOfV RPF84FKWV/UdTpkz6PUeMlVadIsCyZkwsjflLv3qFPENv7gOYIk2cx40ZqHm7AbF bNOWeNUQEe9GVLcfB8jGDUQaDLq+hZAx2CTikRgSjyQ== 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=1f1Lu6 keEugHfrxsIQge5geVX55q+O8JboNY7AbEoRQ=; b=k4IqQqabW2XLzbErOcNkNb THFk8sWWAIinMFVuy3wI0lHcrcAunCaE19p7Y3rsMWB0tLm/qU8rfKczuS7ubciY 7WcUs0ub6Yq8y+mNHeLVVn4NDrOEEXxok4vC4FyJON1aoXXPbaRzuYtxO91e/EJk ququWEyKO5kD3j7/i9EYhAgXdjugLQR8KDw1mSjXF9CbDBJAJGOrZ+9ZAIswuy0R AzzNwa1IiBLzcYzHQrIfIY17YPOM+B2bLw31bxikna5+X1QbIMljfEwyY+x9SCwS NT1r25bcBvE517y1QqoxKuet2+3YzzoSgN6HjZfLBncmUy1WqsahJr753J15Mkxg == X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedugedrudeihedgieekucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvffukfhfgggtuggjsehgtderredttddvnecuhfhrohhmpefrrghtrhhi tghkucfuthgvihhnhhgrrhguthcuoehpshesphhkshdrihhmqeenucfkphepjeekrdehge drvddvtddruddtvdenucevlhhushhtvghrufhiiigvpeegnecurfgrrhgrmhepmhgrihhl fhhrohhmpehpshesphhkshdrihhm X-ME-Proxy: Received: from vm-mail.pks.im (x4e36dc66.dyn.telefonica.de [78.54.220.102]) by mail.messagingengine.com (Postfix) with ESMTPA id C48113280068; Mon, 30 Mar 2020 09:46:30 -0400 (EDT) Received: from localhost (ncase [10.192.0.11]) by vm-mail.pks.im (OpenSMTPD) with ESMTPSA id b6a45f62 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Mon, 30 Mar 2020 13:46:29 +0000 (UTC) Date: Mon, 30 Mar 2020 15:46:33 +0200 From: Patrick Steinhardt To: git Cc: Christian Couder , Junio C Hamano Subject: [PATCH v2 4/9] update-ref: organize commands in an array 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 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 | 73 +++++++++++++++++++++++++++++++++----------- 1 file changed, 56 insertions(+), 17 deletions(-) diff --git a/builtin/update-ref.c b/builtin/update-ref.c index 2d8f7f0578..559475681e 100644 --- a/builtin/update-ref.c +++ b/builtin/update-ref.c @@ -171,11 +171,11 @@ static int parse_next_oid(struct strbuf *input, const char **next, /* * The following five parse_cmd_*() functions parse the corresponding * command. In each case, next points at the character following the - * command name and the following space. They each return a pointer - * to the character terminating the command, and die with an - * explanatory message if there are any parsing problems. All of - * these functions handle either text or binary format input, - * depending on how line_termination is set. + * command name. They each return a pointer to the character + * terminating the command, and die with an explanatory message if + * there are any parsing problems. All of these functions handle + * either text or binary format input, depending on how + * line_termination is set. */ static const char *parse_cmd_update(struct ref_transaction *transaction, @@ -186,6 +186,9 @@ static const char *parse_cmd_update(struct ref_transaction *transaction, struct object_id new_oid, old_oid; int have_old; + if (!skip_prefix(next, " ", &next)) + die("update: missing space after command"); + refname = parse_refname(input, &next); if (!refname) die("update: missing "); @@ -220,6 +223,9 @@ static const char *parse_cmd_create(struct ref_transaction *transaction, char *refname; struct object_id new_oid; + if (!skip_prefix(next, " ", &next)) + die("create: missing space after command"); + refname = parse_refname(input, &next); if (!refname) die("create: missing "); @@ -253,6 +259,9 @@ static const char *parse_cmd_delete(struct ref_transaction *transaction, struct object_id old_oid; int have_old; + if (!skip_prefix(next, " ", &next)) + die("delete: missing space after command"); + refname = parse_refname(input, &next); if (!refname) die("delete: missing "); @@ -288,6 +297,9 @@ static const char *parse_cmd_verify(struct ref_transaction *transaction, char *refname; struct object_id old_oid; + if (!skip_prefix(next, " ", &next)) + die("verify: missing space after command"); + refname = parse_refname(input, &next); if (!refname) die("verify: missing "); @@ -310,9 +322,12 @@ 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, " ", &next)) + die("option: missing space after command"); if (skip_prefix(next, "no-deref", &rest) && *rest == line_termination) update_flags |= REF_NO_DEREF; else @@ -320,33 +335,57 @@ 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)) + continue; + + /* + * Check that the command is terminated by an argument + * or line terminator and not only a matching prefix. + */ + if (input.buf[strlen(prefix)] != line_termination && + input.buf[strlen(prefix)] != '\0' && + input.buf[strlen(prefix)] != ' ') + continue; + + cmd = &command[i]; + break; + } + if (!cmd) die("unknown command: %s", next); + next = cmd->fn(transaction, &input, next); next++; } From patchwork Mon Mar 30 13:46:40 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 11465543 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 B5583159A for ; Mon, 30 Mar 2020 13:46:40 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 91F0E20776 for ; Mon, 30 Mar 2020 13:46:40 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="fHhjlmPe"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="ERaHyvlF" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728080AbgC3Nqj (ORCPT ); Mon, 30 Mar 2020 09:46:39 -0400 Received: from wout4-smtp.messagingengine.com ([64.147.123.20]:40465 "EHLO wout4-smtp.messagingengine.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727954AbgC3Nqj (ORCPT ); Mon, 30 Mar 2020 09:46:39 -0400 Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.west.internal (Postfix) with ESMTP id 9CE02622; Mon, 30 Mar 2020 09:46:38 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute3.internal (MEProxy); Mon, 30 Mar 2020 09:46: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=iwZsX6lhLXdKSuczgsbqmfQ2IrP FMNmSdEex3+ZPJng=; b=fHhjlmPe69q9re56f8PWmcJHq71I4LS9Mbq3BG3TBSC 8kwswD/t7xLgy/9VK/bqCYyfrgNggQn6Fc6qUCnQgeHahIsDXHYZWSbFy5BLVPwY mUzvH99tsq5pfrJbBHyBCO3hblL3+I9BU2u7GPBlDs5Uwmvr7f7WOx/J1q1NXjDR oZ1UQ1lz5FtehmVirhscVT7MX/qAgEh3GkZsL65irEH1PbS6DcoLCOJPdbmQadB3 7ovfGYG+KWujg/ByylJADsAChtjGdq7dX2GV22m8Q9nhXQoqj7X052KUfre/Yw7l KMVVcg9bFUE4r3vr7yGpF+r7YI1doYwkl6x4g1AycXA== 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=iwZsX6 lhLXdKSuczgsbqmfQ2IrPFMNmSdEex3+ZPJng=; b=ERaHyvlFF9dcm8WWznwYLU 1b37NFMVwB1QMulFUJAHcXg5ug0xZtZor2oA1yxYqMyRwlEewlLUOuFDQ+eK3fgb 7rsJdT5CUbE9o1Nm+pc2yxxX+KZdzCf7lzKwRUcD7acxnHk8wIBVt9K2WvkOkWwd 9mvRWkeizEa4325cqE2E1jyT6VsDkdwiqC4VatvKv0PZzay1Q5W7xqMN7Tjr1xlu SrBVIOd4y0oj7CEJwnwmP3fuoPnrjOG6uPjvq/SiOy1Mdi1Rj0zPp1pEY5TcygQU a/FNNZBfDHrvTkdqBWMwR6oLJcUCg4liGIcHM6u88gdqxVvx0MDx9DYcKYIlzclQ == X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedugedrudeihedgieekucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvffukfhfgggtuggjsehgtderredttddvnecuhfhrohhmpefrrghtrhhi tghkucfuthgvihhnhhgrrhguthcuoehpshesphhkshdrihhmqeenucfkphepjeekrdehge drvddvtddruddtvdenucevlhhushhtvghrufhiiigvpeehnecurfgrrhgrmhepmhgrihhl fhhrohhmpehpshesphhkshdrihhm X-ME-Proxy: Received: from vm-mail.pks.im (x4e36dc66.dyn.telefonica.de [78.54.220.102]) by mail.messagingengine.com (Postfix) with ESMTPA id 86579328005D; Mon, 30 Mar 2020 09:46:37 -0400 (EDT) Received: from localhost (ncase [10.192.0.11]) by vm-mail.pks.im (OpenSMTPD) with ESMTPSA id 53a19b53 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Mon, 30 Mar 2020 13:46:36 +0000 (UTC) Date: Mon, 30 Mar 2020 15:46:40 +0200 From: Patrick Steinhardt To: git Cc: Christian Couder , Junio C Hamano Subject: [PATCH v2 5/9] update-ref: drop unused argument for `parse_refname` Message-ID: <49a14d20462bb9d7f00e42df73fc21b050be1db0.1585575749.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 `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 559475681e..6f2aba916b 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; @@ -189,7 +189,7 @@ static const char *parse_cmd_update(struct ref_transaction *transaction, if (!skip_prefix(next, " ", &next)) die("update: missing space after command"); - refname = parse_refname(input, &next); + refname = parse_refname(&next); if (!refname) die("update: missing "); @@ -226,7 +226,7 @@ static const char *parse_cmd_create(struct ref_transaction *transaction, if (!skip_prefix(next, " ", &next)) die("create: missing space after command"); - refname = parse_refname(input, &next); + refname = parse_refname(&next); if (!refname) die("create: missing "); @@ -262,7 +262,7 @@ static const char *parse_cmd_delete(struct ref_transaction *transaction, if (!skip_prefix(next, " ", &next)) die("delete: missing space after command"); - refname = parse_refname(input, &next); + refname = parse_refname(&next); if (!refname) die("delete: missing "); @@ -300,7 +300,7 @@ static const char *parse_cmd_verify(struct ref_transaction *transaction, if (!skip_prefix(next, " ", &next)) die("verify: missing space after command"); - refname = parse_refname(input, &next); + refname = parse_refname(&next); if (!refname) die("verify: missing "); From patchwork Mon Mar 30 13:46:45 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 11465545 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 85687913 for ; Mon, 30 Mar 2020 13:46:47 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 566CB20757 for ; Mon, 30 Mar 2020 13:46:47 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="c0wzvVTZ"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="HlYXt08/" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728530AbgC3Nqq (ORCPT ); Mon, 30 Mar 2020 09:46:46 -0400 Received: from wout4-smtp.messagingengine.com ([64.147.123.20]:58871 "EHLO wout4-smtp.messagingengine.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727954AbgC3Nqq (ORCPT ); Mon, 30 Mar 2020 09:46:46 -0400 Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.west.internal (Postfix) with ESMTP id 5A5CD6AE; Mon, 30 Mar 2020 09:46:45 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute3.internal (MEProxy); Mon, 30 Mar 2020 09:46:45 -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=iiLHvfGFbXDx0F/ifU81Fk15CFN dQ7LUojXb4EG+zDs=; b=c0wzvVTZhrDy/9/z+0n7V8qYY13jpj48e2hSFlvHdZT XX8tl6vZEsyMvUZkwU3OjKBrmazsc2Cg+jckl7OVc1V2VL/S3HEDdNYe8Lplj5bj nAngpNHewPAOkccpjK6a7n/phg8TnIhmKmqdMvbl7artW7UVCGpQCfeHHcN5SU8x XFyu7/fi/PXfkClyWkUbVey53KQL0nyAt6uReCGdBOwQbYLBpB6Nx6NkSWQk0KTD 3RYum1z5UbolHKc7I2bPDrxvJsC5ROBnJdyZFd1tSrRNq/vZMRSrcE2JFy4gusho Cggv4sNpVAVbKox3pMJ1URiF0UrFdVmhp+TpmAkLG8Q== 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=iiLHvf GFbXDx0F/ifU81Fk15CFNdQ7LUojXb4EG+zDs=; b=HlYXt08/SJnjrfqbz0MvPW n2U6mYfF2tT1aHgcOrXvBmNozdg+3qTmDyliFHABKq3ndoYb1vb9FfpqdjZcttUo gBqVM0/JnydaLwaGlYaIpiDwIac80pKv1JEzp4m+4Zr9Vk8eCopzJnI/d2nXs8mO pywKVPD69QSzMl53GczC/LPqr1wuz1ndeR8s3My3yxnVvDuFL3n2+NqJASNUw2xC ADmYK7+aYWvk9ZHb7EMa3xFJsqHTnSeLYHXGX9WjOVYFTANhK3YnnrO/WJF079Uu RUzHf4s/9rJsyBzq95l8RxtoU2lx2jy4P4XGLW9br6TFffP19iTAe5Om3XtvTRxw == X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedugedrudeihedgieekucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvffukfhfgggtuggjsehgtderredttddvnecuhfhrohhmpefrrghtrhhi tghkucfuthgvihhnhhgrrhguthcuoehpshesphhkshdrihhmqeenucfkphepjeekrdehge drvddvtddruddtvdenucevlhhushhtvghrufhiiigvpeeinecurfgrrhgrmhepmhgrihhl fhhrohhmpehpshesphhkshdrihhm X-ME-Proxy: Received: from vm-mail.pks.im (x4e36dc66.dyn.telefonica.de [78.54.220.102]) by mail.messagingengine.com (Postfix) with ESMTPA id 499B0328005E; Mon, 30 Mar 2020 09:46:44 -0400 (EDT) Received: from localhost (ncase [10.192.0.11]) by vm-mail.pks.im (OpenSMTPD) with ESMTPSA id 60ad1216 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Mon, 30 Mar 2020 13:46:42 +0000 (UTC) Date: Mon, 30 Mar 2020 15:46:45 +0200 From: Patrick Steinhardt To: git Cc: Christian Couder , Junio C Hamano Subject: [PATCH v2 6/9] update-ref: pass end pointer instead of strbuf 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 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 6f2aba916b..139c3b11fa 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; @@ -193,11 +193,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) @@ -217,7 +217,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; @@ -230,7 +230,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)) @@ -252,7 +252,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; @@ -266,7 +266,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 { @@ -291,7 +291,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; @@ -304,7 +304,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); @@ -323,7 +323,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, " ", &next)) @@ -337,7 +337,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 }, @@ -385,7 +385,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 Mon Mar 30 13:46:52 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 11465547 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 6CE53913 for ; Mon, 30 Mar 2020 13:46:53 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 4A5E92073B for ; Mon, 30 Mar 2020 13:46:53 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="Bse7eXCX"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="Bpwc3FqI" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728541AbgC3Nqw (ORCPT ); Mon, 30 Mar 2020 09:46:52 -0400 Received: from wout4-smtp.messagingengine.com ([64.147.123.20]:49943 "EHLO wout4-smtp.messagingengine.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726028AbgC3Nqw (ORCPT ); Mon, 30 Mar 2020 09:46:52 -0400 Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.west.internal (Postfix) with ESMTP id 2126C3AA; Mon, 30 Mar 2020 09:46:51 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute3.internal (MEProxy); Mon, 30 Mar 2020 09:46:51 -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=rvkbuvO/T48iVrK35BqJQX1qixd Qr/h01VE4EvYSVSY=; b=Bse7eXCXnYoBY8NDk7bLiEvPnmPS7/j5po12OXovGir R+/lnyomTSSOguEokgTqByypYij+SAICxiSYcCJ+EXXFiO6s2Lhddlf7MezPPbX7 SIEylvk/uJRnBrulXFSZAerILGwd14irYONyUDa/iucSTt9d9bAm+BGs6B5SzFld lM633Gg0rAQ/7R2IxxA5Uczlwoh4dK9zfwipb8hmO/aUqt2flpwijCBsNogzJwZx 0mqBV40xA6wxMEhwNQ9bNcMTyS0xoQvcvrrqGmw9fzZuiiirTISVIoKQoEEUMi65 Odrw83cq9J6nMMf7LpyEcqYXfq4iu2pPmL7da8JSAXA== 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=rvkbuv O/T48iVrK35BqJQX1qixdQr/h01VE4EvYSVSY=; b=Bpwc3FqIGFrcRAby1MPjKY VTE7UUq4X8EuUh8lNyxpYH99wKlpNqGQcEmMm1bsBeO3THBki7tEakj5T6ckk9fm VMfm6HMAWIYf2CZan0Se31jTBp6XalgkbUHCI5Geo11J/OGKhbz78RLlceHSsyT8 kxWXsBA7EtDM8HU3DV4PEGD7TmFok0nh4LCERq4kRT4qv/ewoaPVX0soBK+A8dUw Xpw/4FK8XGhVhwxmvmv1cgKDElRrpnCsm8tV+0bjq+StFXYvmC6MtHlwR1AUMAiw vpS5/gntKiKB2Ey+6tQ6csXjbCffP7PFAwGsK5fg2ZpwXuVUprLbdK4RBEYUM/Pg == X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedugedrudeihedgieekucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvffukfhfgggtuggjsehgtderredttddvnecuhfhrohhmpefrrghtrhhi tghkucfuthgvihhnhhgrrhguthcuoehpshesphhkshdrihhmqeenucfkphepjeekrdehge drvddvtddruddtvdenucevlhhushhtvghrufhiiigvpeejnecurfgrrhgrmhepmhgrihhl fhhrohhmpehpshesphhkshdrihhm X-ME-Proxy: Received: from vm-mail.pks.im (x4e36dc66.dyn.telefonica.de [78.54.220.102]) by mail.messagingengine.com (Postfix) with ESMTPA id 0E4233280064; Mon, 30 Mar 2020 09:46:49 -0400 (EDT) Received: from localhost (ncase [10.192.0.11]) by vm-mail.pks.im (OpenSMTPD) with ESMTPSA id 794be5cf (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Mon, 30 Mar 2020 13:46:48 +0000 (UTC) Date: Mon, 30 Mar 2020 15:46:52 +0200 From: Patrick Steinhardt To: git Cc: Christian Couder , Junio C Hamano Subject: [PATCH v2 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 139c3b11fa..1a7906545d 100644 --- a/builtin/update-ref.c +++ b/builtin/update-ref.c @@ -346,15 +346,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; @@ -389,6 +395,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); } @@ -423,21 +434,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 Mon Mar 30 13:46:59 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 11465549 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 F3603913 for ; Mon, 30 Mar 2020 13:46:59 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id C878220771 for ; Mon, 30 Mar 2020 13:46:59 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="c9acE2Ed"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="UeDpk2UF" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728548AbgC3Nq7 (ORCPT ); Mon, 30 Mar 2020 09:46:59 -0400 Received: from wout4-smtp.messagingengine.com ([64.147.123.20]:52871 "EHLO wout4-smtp.messagingengine.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727954AbgC3Nq6 (ORCPT ); Mon, 30 Mar 2020 09:46:58 -0400 Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.west.internal (Postfix) with ESMTP id D30FE574; Mon, 30 Mar 2020 09:46:57 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute3.internal (MEProxy); Mon, 30 Mar 2020 09:46:58 -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=0pFPLNib2Yy1XpwBHY2APRcUkux UcyhbtXEO6q10LaA=; b=c9acE2Ed2fqJGW476QENhObKbciKT6I+iuabUqtx87/ /eyRzkGnpoGEa5mB3cTHoMTWY165lQjvP5aDx3z8BaJiMN9MKcB2y1jAgpiC/irh 5Q0ghaIvifO8rfE3fQVc8BAf9IMc/SvnM0FBMZPSoRDvCkO2x0Zr38i48q7c7GWl 3t9/3I2sX7x/VpGOHyN8HSOj2CW4MFXy3CUq2cSYQwCzj4i9ezdPxtmsmdW+wYnE FndEOq/pMCA8j6qUvsNmZuDLqlMmXP8yETBBOoZh18jIgWYHo9Pabuf02grrq/42 zBvNx4eHcSa+W9/oJ/E1INI/gAaX1Tknfg2K2M9xkAQ== 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=0pFPLN ib2Yy1XpwBHY2APRcUkuxUcyhbtXEO6q10LaA=; b=UeDpk2UFP7U8PWO2IAzsQ5 zFXi1czfVwlOsW6iSG+DaM1rvbCO4N+KSMS0g+J3sCutBvDjMfbVDjMpV12womD9 1stLZi9c3C+/IBpPLdSlzlHB8wVeX7o+UshYN9ta6ciz12evq+NbnZ7OHWL3wehR FHABXaPhvBHk0O+R2mk0rsKT3/HG5N255tVSsJC98Yq5YGz14aWDnJxdC8ioB2yM 53pv+eeUVZqP02FgOU13suHTKC2lG0KPvjr3+0I+Hk10+tcc9TQlG/1P0Q6g83mw 2yF8oSWKvgWlag7azHApxdzaSRGp+Pza6KGZykC/KgRrwRuEOEm1Ow30wrP+gC5A == X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedugedrudeihedgieekucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvffukfhfgggtuggjsehgtderredttddvnecuhfhrohhmpefrrghtrhhi tghkucfuthgvihhnhhgrrhguthcuoehpshesphhkshdrihhmqeenucfkphepjeekrdehge drvddvtddruddtvdenucevlhhushhtvghrufhiiigvpeeknecurfgrrhgrmhepmhgrihhl fhhrohhmpehpshesphhkshdrihhm X-ME-Proxy: Received: from vm-mail.pks.im (x4e36dc66.dyn.telefonica.de [78.54.220.102]) by mail.messagingengine.com (Postfix) with ESMTPA id C361C328005A; Mon, 30 Mar 2020 09:46:56 -0400 (EDT) Received: from localhost (ncase [10.192.0.11]) by vm-mail.pks.im (OpenSMTPD) with ESMTPSA id 0dc33be9 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Mon, 30 Mar 2020 13:46:55 +0000 (UTC) Date: Mon, 30 Mar 2020 15:46:59 +0200 From: Patrick Steinhardt To: git Cc: Christian Couder , Junio C Hamano Subject: [PATCH v2 8/9] update-ref: read commands in a line-wise fashion 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 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 | 80 +++++++++++++++++++++++--------------------- 1 file changed, 41 insertions(+), 39 deletions(-) diff --git a/builtin/update-ref.c b/builtin/update-ref.c index 1a7906545d..77cd235dfc 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, * 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; @@ -212,12 +212,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; @@ -247,12 +245,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; @@ -286,12 +282,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; @@ -318,12 +312,10 @@ 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, " ", &next)) @@ -332,48 +324,49 @@ static const char *parse_cmd_option(struct ref_transaction *transaction, 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 *); + /* + * If using NUL-terminated format, only the first argument will be + * available in the first line. In case a command expects more than one + * argument, we thus have to fetch an additional `extra_lines` number + * of lines. + */ + unsigned extra_lines; } 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, 2 }, + { "create", parse_cmd_create, 1 }, + { "delete", parse_cmd_delete, 1 }, + { "verify", parse_cmd_verify, 1 }, + { "option", parse_cmd_option, 0 }, }; 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; - if (!skip_prefix(next, prefix, &next)) + if (!starts_with(input.buf, prefix)) continue; /* @@ -389,10 +382,19 @@ static void update_refs_stdin(void) 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 extra lines 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 = 0; line_termination == '\0' && j < cmd->extra_lines; j++) + if (strbuf_appendwholeline(&input, stdin, line_termination)) + break; + + cmd->fn(transaction, input.buf + strlen(cmd->prefix), + input.buf + input.len); } if (ref_transaction_commit(transaction, &err)) From patchwork Mon Mar 30 13:47:05 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 11465551 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 DBA02159A for ; Mon, 30 Mar 2020 13:47:07 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id A55DC20786 for ; Mon, 30 Mar 2020 13:47:07 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="fUBYO4Wu"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="pZId018z" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728569AbgC3NrG (ORCPT ); Mon, 30 Mar 2020 09:47:06 -0400 Received: from wout4-smtp.messagingengine.com ([64.147.123.20]:54013 "EHLO wout4-smtp.messagingengine.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727954AbgC3NrG (ORCPT ); Mon, 30 Mar 2020 09:47:06 -0400 Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.west.internal (Postfix) with ESMTP id 978FE5F0; Mon, 30 Mar 2020 09:47:04 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute3.internal (MEProxy); Mon, 30 Mar 2020 09:47:04 -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=T5d/+S884lJ7yhvxBsHOPa2uCqJ hDKLOuc6vDFh0dNM=; b=fUBYO4WuJksD3EpgPssCjndrzn58sou3Ykh7agHIFvE excTiTDOEJtsUhZ9y/8igZYCVYA7mS7RKv0rK3uBDypdCmE09Vu5SGMn7hobWIzy xqWbAc+tGycvNcJneLX02XJEgoUJyIzOoH6LYblbP+T8zvo48glSRhB6yOiqbf4L zioE5BIfylqihBUAX8IptW93BA5fGxTSnTw/WwDthr27C1S4jHcYZXyNYudq+0d/ CrZQu59MPHMidQu6ZrdZRwm7fG4Pxc5+MQRt54uB0M8kMPP8WvvdgR0ozZteTg7o GuegSwKjzJw1WzHESIyJcR/kqlpye8+/4nt3WBceFYw== 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=T5d/+S 884lJ7yhvxBsHOPa2uCqJhDKLOuc6vDFh0dNM=; b=pZId018zo6K69E4Tuf8dto enA2O4KZSvQe3BbLPkiMwqLyedPopOoX0musJFx5WoQsUQa0KnUlu6K9+eMYisur JdVILe+juLDNd0oJTwwOlBsPfAsF+LuNF+biSW6/fA5TIfZJ98xMlZrUaVlm9hft oBPHFdh5kEB3gusILkzTAivRpDQnqpNTM67oyiWjlJwWDXQz3zRyCUFN+tl1kdXV reilcDQKqkAUk3NxwmOC262el9s9dJ0bJBx1C0tkXrzJGgvevbSOPV91yfUCoIDX uj2L+d+EPlEr8uIiFKbNpztzU5lsAkwLZ4UIqTtB+Fq6/YijssMq7yejkQrkmFJA == X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedugedrudeihedgieekucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvffukfhfgggtuggjsehgtderredttddvnecuhfhrohhmpefrrghtrhhi tghkucfuthgvihhnhhgrrhguthcuoehpshesphhkshdrihhmqeenucfkphepjeekrdehge drvddvtddruddtvdenucevlhhushhtvghrufhiiigvpeelnecurfgrrhgrmhepmhgrihhl fhhrohhmpehpshesphhkshdrihhm X-ME-Proxy: Received: from vm-mail.pks.im (x4e36dc66.dyn.telefonica.de [78.54.220.102]) by mail.messagingengine.com (Postfix) with ESMTPA id 861C83280069; Mon, 30 Mar 2020 09:47:03 -0400 (EDT) Received: from localhost (ncase [10.192.0.11]) by vm-mail.pks.im (OpenSMTPD) with ESMTPSA id b949498d (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Mon, 30 Mar 2020 13:47:01 +0000 (UTC) Date: Mon, 30 Mar 2020 15:47:05 +0200 From: Patrick Steinhardt To: git Cc: Christian Couder , Junio C Hamano Subject: [PATCH v2 9/9] update-ref: implement interactive transaction handling 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 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 77cd235dfc..120c0a5fc0 100644 --- a/builtin/update-ref.c +++ b/builtin/update-ref.c @@ -326,6 +326,59 @@ 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 *); @@ -336,17 +389,23 @@ static const struct parse_cmd { * of lines. */ unsigned extra_lines; + enum update_refs_state state; } command[] = { - { "update", parse_cmd_update, 2 }, - { "create", parse_cmd_create, 1 }, - { "delete", parse_cmd_delete, 1 }, - { "verify", parse_cmd_verify, 1 }, - { "option", parse_cmd_option, 0 }, + { "update", parse_cmd_update, 2, UPDATE_REFS_OPEN }, + { "create", parse_cmd_create, 1, UPDATE_REFS_OPEN }, + { "delete", parse_cmd_delete, 1, UPDATE_REFS_OPEN }, + { "verify", parse_cmd_verify, 1, UPDATE_REFS_OPEN }, + { "option", parse_cmd_option, 0, 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; @@ -393,14 +452,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), 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