From patchwork Wed Mar 25 09:53:28 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 11457341 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 CB09214B4 for ; Wed, 25 Mar 2020 09:53:30 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id A77AB2078A for ; Wed, 25 Mar 2020 09:53:30 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="MFagwVj0"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="LKbGD4BU" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727332AbgCYJx3 (ORCPT ); Wed, 25 Mar 2020 05:53:29 -0400 Received: from out5-smtp.messagingengine.com ([66.111.4.29]:45985 "EHLO out5-smtp.messagingengine.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726154AbgCYJx3 (ORCPT ); Wed, 25 Mar 2020 05:53:29 -0400 Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.nyi.internal (Postfix) with ESMTP id 7BA0D5C0105; Wed, 25 Mar 2020 05:53:28 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute3.internal (MEProxy); Wed, 25 Mar 2020 05:53: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=7sx3PFmiU/1+mQzYwYZ7meSU791 rc9wa6KKO1pYAkGA=; b=MFagwVj0Vo+mf+ncRST7RbKdCIskw0TPdxT4Pd0a9D7 lDGIN/z3qA4+NXE5rYwf/uAb2E50V58xn7VAo7o1Rn9WE1mzBwF5dnMxUqvxm0Dz zoA5BoWA2uIzy6j1In87bcEHQNDFWi/cTTO+ENnLuqUuElLA61lrk4dkhblc1Ooa 2NaewvE0u+FGOWWfcTIrtJtGrowM33n8EdjO2vr4Vjzm7MWTQtYCXh3VXYK80wZN 4dFFLik9DI8z+5Ar0MDHpBre2/tdnBJaPCsoGi2BGRcOeeQYCNMcc405ZWKgybV1 u5xAnFhTXg5uUUFu6pY6zneTQ+BOb4WfZDyLsDDSW/A== 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=7sx3PF miU/1+mQzYwYZ7meSU791rc9wa6KKO1pYAkGA=; b=LKbGD4BUsgT/S0fNMiYaTI YNHc/+xgFOTMDL/EXwmDoMCfYln31QZN6epwdrp4LJKeQSwNmIfsGags1OZP+yUw 5/9jXhlxQAFlNSQl4I/exbKmM1z3a9KGLCmmiGRf0Bjq0/rmTiJydd4TteC9Mp2T 4hjEfus0ItZLmIqYU6iIESoe0roGqjWW1q9oTuBDlcJQAbvwQuS5pZhRE8paL92P +xRrK7gqr/zgC0wnpzruX4JFelt8k65ylHzIhbBOTng7uoLW7a9qROBLB2TinjU6 S7Y/GEt5NIuzup7JEELRM7PaMHzL/6ZF4+fg9neK1NKysroTZLVvNdJ4EhtZc4Qw == X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedugedrudehfedgtdekucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvffukfhfgggtuggjsehgtderredttddvnecuhfhrohhmpefrrghtrhhi tghkucfuthgvihhnhhgrrhguthcuoehpshesphhkshdrihhmqeenucfkphepjeejrddufe drudekhedrjedvnecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhf rhhomhepphhssehpkhhsrdhimh X-ME-Proxy: Received: from vm-mail.pks.im (x4d0db948.dyn.telefonica.de [77.13.185.72]) by mail.messagingengine.com (Postfix) with ESMTPA id 151F33280063; Wed, 25 Mar 2020 05:53:27 -0400 (EDT) Received: from localhost (ncase [10.192.0.11]) by vm-mail.pks.im (OpenSMTPD) with ESMTPSA id 63dcd87f (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 25 Mar 2020 09:53:27 +0000 (UTC) Date: Wed, 25 Mar 2020 10:53:28 +0100 From: Patrick Steinhardt To: git Cc: Christian Couder Subject: [PATCH 1/9] refs: fix segfault when aborting empty transaction Message-ID: <3c7f8c47f361c46751629b44570657ef811d94d0.1585129842.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 Wed Mar 25 09:53: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: 11457343 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 9342492A for ; Wed, 25 Mar 2020 09:53:41 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 72FEE2077D for ; Wed, 25 Mar 2020 09:53:41 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="qJMCMlnM"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="VqzbSWkI" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727416AbgCYJxk (ORCPT ); Wed, 25 Mar 2020 05:53:40 -0400 Received: from out5-smtp.messagingengine.com ([66.111.4.29]:51407 "EHLO out5-smtp.messagingengine.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727281AbgCYJxk (ORCPT ); Wed, 25 Mar 2020 05:53:40 -0400 Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.nyi.internal (Postfix) with ESMTP id 376DA5C01C4; Wed, 25 Mar 2020 05:53:39 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute3.internal (MEProxy); Wed, 25 Mar 2020 05:53:39 -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=59jjfc3QkaQ7PQeRNXt/0/S/xyi 6OHnfVPijKbflU4Y=; b=qJMCMlnMl7nGp1x55U8xgAHiRU6NgRSjeGf9tkQcLhG G2VTHkrBM3X0dv95OzZyx1ovi6ruqPljlJWUp1g0HCskWJsxHrARQl/aEUoP/MAx eyatu5X18gO7E9VJzllu/LbEVnkD8Mfh7opZaL/9vMdk0Bw44aOE/Q+bR1badTJb UsLTLPIDKRthnd+MHExXjCem56dA4i2iP4nTaEFWAzz5qokGnTwAfmnEIWlaoRyB ey82echyxMrqxs8l3Ya4C1DtFVjIA3Zn5N+SZCpOpnRvIKz/qNRu90CavrIDXQxU arXquZoaPCg2gLHe4kLPCcAaQnPOknrU/cZqFtUmHkw== 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=59jjfc 3QkaQ7PQeRNXt/0/S/xyi6OHnfVPijKbflU4Y=; b=VqzbSWkIZPDOp1FqohFJHl mFQSCIcWd2ihHVZmS7OUw+nRIn89X7ZPSQwho07KcwyLRcpBbGPHME3F9SVaMr+6 7uzQtUkr8vfLBZkfZBsCOjMZSnbLj8JLwgK9Iu7xi5uif4RhSgeReXrOoGvxg9hx BwxCGAzd53x9x/PAomLztAPsZVRRA+7fF/AQIJpMLSl+b7qTKNLwDgE0+pUKRRGT ErnZmAxMMM1mHJbkj9iGNXNCxK4Kp7zOxRJdyNsMQq+3uFifDzD+w3Gk8JXqfBNI HDe2UhErFTOBweAoU8W489aVBXSlx9TazlgXl+viE3t6vQ1BPakWb2w9zkSP9oYw == X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedugedrudehfedgtdekucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvffukfhfgggtuggjsehgtderredttddvnecuhfhrohhmpefrrghtrhhi tghkucfuthgvihhnhhgrrhguthcuoehpshesphhkshdrihhmqeenucfkphepjeejrddufe drudekhedrjedvnecuvehluhhsthgvrhfuihiivgepudenucfrrghrrghmpehmrghilhhf rhhomhepphhssehpkhhsrdhimh X-ME-Proxy: Received: from vm-mail.pks.im (x4d0db948.dyn.telefonica.de [77.13.185.72]) by mail.messagingengine.com (Postfix) with ESMTPA id 9EFA93280067; Wed, 25 Mar 2020 05:53:38 -0400 (EDT) Received: from localhost (ncase [10.192.0.11]) by vm-mail.pks.im (OpenSMTPD) with ESMTPSA id 353e6bab (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 25 Mar 2020 09:53:37 +0000 (UTC) Date: Wed, 25 Mar 2020 10:53:38 +0100 From: Patrick Steinhardt To: git Cc: Christian Couder Subject: [PATCH 2/9] git-update-ref.txt: add missing word 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 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 Wed Mar 25 09:53:47 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 11457345 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 53A7692A for ; Wed, 25 Mar 2020 09:53:49 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 335612077D for ; Wed, 25 Mar 2020 09:53:49 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="IVddYw4+"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="tT7kNpQO" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727432AbgCYJxs (ORCPT ); Wed, 25 Mar 2020 05:53:48 -0400 Received: from out5-smtp.messagingengine.com ([66.111.4.29]:35803 "EHLO out5-smtp.messagingengine.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727281AbgCYJxs (ORCPT ); Wed, 25 Mar 2020 05:53:48 -0400 Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.nyi.internal (Postfix) with ESMTP id C3B275C018F; Wed, 25 Mar 2020 05:53:46 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute3.internal (MEProxy); Wed, 25 Mar 2020 05:53:46 -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=HJiDIAo4mlODyqer/nhRwYhb+/N jtjLy9pj6GlFjfR8=; b=IVddYw4+Na4palPNlYieyHaChla7fHpDFyY4Vjfdpuu 9jNfXvv7q9AYB68L/bh94t0F+Cc97xrzuDgFS4A6qaJSbYmAt1X7Ed4LisFROCrX xqrOGPaS9Eswt+GJSGhphsavLKmXN3/LSRjOcUX6FaUDMeUtnCx639GM7ufC3r+q sgZgpwYKB9pbWKhg7sfrjHfpz4wB1xDvF7BYcWMZatV7AmnmA/1Wb6qex+RLWlDQ ZByOBLMP/V9YL/gRyc52gTP79/V0rwAs/Pp56CN5mgEoqrrq1b8hLOfFE54bNB/B sb1OPLdNOBCcFEX/Awc1GmbUZHLA/W5dJJj8K2Z8+5g== 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=HJiDIA o4mlODyqer/nhRwYhb+/NjtjLy9pj6GlFjfR8=; b=tT7kNpQOoSCuVIpXjrRJMq l7nteyWgqVEDSgWSVmrVPEQx7M0aPuu6YtTnWvBNP9bioxAG5Cg1iWnV45SzZ226 9PB9CFxBw0x4il5P0j58wkgPUV/bS0q3KvJnnmg02eH/2I9UCLDx0sux1xxPx3Xj A8UzDH1attyYMfoMjO71yGsyhNxVxsfzU2DSPsEin0ep41YhHDXXYp+WZwhBGXad eNTEUhfD/x8Jfw/s4eUQQu3Uo3sajCNGhlPtx3xJ3U0T72Zcu6B5hXlhFik4BQKC hEbMy7C2BR8TITIZrV5ekoD2U+OBc7mLgmSyh7GcFU6w7ZvQNSMtkNXE/XJ0rf+Q == X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedugedrudehfedgtdekucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvffukfhfgggtuggjsehgtderredttddvnecuhfhrohhmpefrrghtrhhi tghkucfuthgvihhnhhgrrhguthcuoehpshesphhkshdrihhmqeenucfkphepjeejrddufe drudekhedrjedvnecuvehluhhsthgvrhfuihiivgepvdenucfrrghrrghmpehmrghilhhf rhhomhepphhssehpkhhsrdhimh X-ME-Proxy: Received: from vm-mail.pks.im (x4d0db948.dyn.telefonica.de [77.13.185.72]) by mail.messagingengine.com (Postfix) with ESMTPA id 4B6263280059; Wed, 25 Mar 2020 05:53:46 -0400 (EDT) Received: from localhost (ncase [10.192.0.11]) by vm-mail.pks.im (OpenSMTPD) with ESMTPSA id 6b0e0e02 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 25 Mar 2020 09:53:45 +0000 (UTC) Date: Wed, 25 Mar 2020 10:53:47 +0100 From: Patrick Steinhardt To: git Cc: Christian Couder Subject: [PATCH 3/9] strbuf: provide function to append whole lines Message-ID: <4b0a963ea5c47a951b95aa0a03966315b3e8299d.1585129842.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 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 Wed Mar 25 09:53:55 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 11457347 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 B7C7614B4 for ; Wed, 25 Mar 2020 09:53:57 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 89E642077D for ; Wed, 25 Mar 2020 09:53:57 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="i6ULELT3"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="mI+SUwu+" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727452AbgCYJx4 (ORCPT ); Wed, 25 Mar 2020 05:53:56 -0400 Received: from out5-smtp.messagingengine.com ([66.111.4.29]:56119 "EHLO out5-smtp.messagingengine.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727281AbgCYJx4 (ORCPT ); Wed, 25 Mar 2020 05:53:56 -0400 Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.nyi.internal (Postfix) with ESMTP id 6A8445C0227; Wed, 25 Mar 2020 05:53:55 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute3.internal (MEProxy); Wed, 25 Mar 2020 05:53:55 -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=lh0q1o++tE+2Dc66P8nRvQgka41 0aAtpGllrXJFNIMY=; b=i6ULELT3dZALA5gJL4CMSTHtdFlf8Sl2VujZh7xRpyq imYsdbO/zWbs7YRF8hflXnCnHCTLBijQHFiYN05yZgoIWN94Auk2vnSNgkYBFHFJ X60bpidhUnOj2vKLbnfqpgKG651xC/c70IaGhrmKnhdb0Qaz5McB1BTTrVg4AraX EMuuoIlMsItilPOgupVShPrxhZkuarSylrmWF8lNSS/WnLmCw502Gz3AK7Pj0Frc gjDBQxLYLF5PkCSAW2g4EhddexneJ/GKW9GWH66DUa5VPf7GW9zpnH3u2scZOs50 gHo7X+Ce+kFHXgN10UocZUyqwGUZwe/R1xymnmV5s7g== 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=lh0q1o ++tE+2Dc66P8nRvQgka410aAtpGllrXJFNIMY=; b=mI+SUwu+6pcrffhk0cSKFf 90a7ApqL1A9t7LSu4UwHoBasuCPOl/8402CkrzqbwGQEwLY6DYdcjtnUMZzTjtrV x32SmHGXEJ3AvT0YHLEo5JPKCczZFBIG8+9A1WX8V0BP9FfyqMn7/KsQ0p2nQScL nFGS5X7f7+NoYR9GcCQ/LguLBqbtGKFQBTWnzytuaIxwpjicTh0L64I/DUQ70V1n 6MVSK7g8RNdYnbcUXJvxGsbQnyjLJVCeDZ/ZmDyiaKUkaSx1cd5NM+SIOZ7PNYNG L1V34ze5MisujyIEP+l/zRTMWOCNXZSCh7Z0ldpjI9J6WB9zZpNzV4uonfPv0P+A == X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedugedrudehfedgtdekucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvffukfhfgggtuggjsehgtderredttddvnecuhfhrohhmpefrrghtrhhi tghkucfuthgvihhnhhgrrhguthcuoehpshesphhkshdrihhmqeenucfkphepjeejrddufe drudekhedrjedvnecuvehluhhsthgvrhfuihiivgepfeenucfrrghrrghmpehmrghilhhf rhhomhepphhssehpkhhsrdhimh X-ME-Proxy: Received: from vm-mail.pks.im (x4d0db948.dyn.telefonica.de [77.13.185.72]) by mail.messagingengine.com (Postfix) with ESMTPA id D8EF0328005E; Wed, 25 Mar 2020 05:53:54 -0400 (EDT) Received: from localhost (ncase [10.192.0.11]) by vm-mail.pks.im (OpenSMTPD) with ESMTPSA id 93f558bc (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 25 Mar 2020 09:53:53 +0000 (UTC) Date: Wed, 25 Mar 2020 10:53:55 +0100 From: Patrick Steinhardt To: git Cc: Christian Couder Subject: [PATCH 4/9] update-ref: organize commands in an array Message-ID: <50ffc263293571f8af71fd1d253ac238c6909229.1585129842.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 | 66 ++++++++++++++++++++++++++++++++------------ 1 file changed, 49 insertions(+), 17 deletions(-) diff --git a/builtin/update-ref.c b/builtin/update-ref.c index 2d8f7f0578..d2b917a47c 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,50 @@ 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 *); +} commands[] = { + { "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(commands); i++) { + if (!skip_prefix(next, commands[i].prefix , &next)) + continue; + cmd = &commands[i]; + break; + } + if (!cmd) die("unknown command: %s", next); + if (input.buf[strlen(cmd->prefix)] != line_termination && + input.buf[strlen(cmd->prefix)] != '\0' && + input.buf[strlen(cmd->prefix)] != ' ') + die("%s: no separator after command", cmd->prefix); + + next = cmd->fn(transaction, &input, next); next++; } From patchwork Wed Mar 25 09:54:01 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 11457349 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 1F00C92A for ; Wed, 25 Mar 2020 09:54:04 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id F23A32077D for ; Wed, 25 Mar 2020 09:54:03 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="ttJ0fuMq"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="x8tEsjk1" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727487AbgCYJyD (ORCPT ); Wed, 25 Mar 2020 05:54:03 -0400 Received: from out5-smtp.messagingengine.com ([66.111.4.29]:48311 "EHLO out5-smtp.messagingengine.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727281AbgCYJyC (ORCPT ); Wed, 25 Mar 2020 05:54:02 -0400 Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.nyi.internal (Postfix) with ESMTP id 1681F5C020A; Wed, 25 Mar 2020 05:54:02 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute3.internal (MEProxy); Wed, 25 Mar 2020 05:54:02 -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=hw6E7atdpdJkzwQTvHYUANYCvOs Fzlqr2b0UslbFvzw=; b=ttJ0fuMqxZacqgWNbvg+uwqBsRn+4MtN/fgIFIzc3wu Vr2lWyW3X9dGsDYLXYu/KLUgw0ETgCoDTwkkL5pfC3JgsG0GH+0V6+zoVuqBCdw8 e50KRbQ0Rf4qmd+ugUzDCr1TyGWTVW+R0C3iq9gochK9vBP0dlZRiBWI+5BhKgTG XtQpaE/s44VDoJt1G9WTRGlH21KPDZhje5FMc6zH6gnZBbWo+2MkLhcpRUw4FRic H3K7BF1y82Iwu5Z/Z4PxxHApDY88E8Mo9xe7a9dsvrqimkzRmatvw9T3LWbMEwRb 8TKOjJKo8Xpz1n/IQReNGSSvdDeSbIb9FBGBicHKZvA== 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=hw6E7a tdpdJkzwQTvHYUANYCvOsFzlqr2b0UslbFvzw=; b=x8tEsjk1F7TbVV5IenDB9/ HkbdH+HVTt5qrNkc2UgGe3nlPJ29pJ87lXWj7ZLt5K1nd+7kuFus5meTu7nUNeYw RMWwVai98vkceotBJQQe6pxxzmbRHIGT6zOTHV6LZ0EK4Ch+1tqtrJe/s62Nnfhf Jm8HVh9qwHWwBVLlEYm3KsL35BGsVXHST7xalffVwGMKc3fGCDugvEmoRCf2MmnP hmrdDFxyC90ERSGdBq5j00e4JbQqjyGDKSP2ftTQTsgVHPIZRY4/pN5V9grYx7E8 NKiOrZMZOg3aAQf65mBXlJNbCXKOaGc1QoxW3zb9qPd84GSWxvF6RMZQhex4YDZg == X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedugedrudehfedgtdekucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvffukfhfgggtuggjsehgtderredttddvnecuhfhrohhmpefrrghtrhhi tghkucfuthgvihhnhhgrrhguthcuoehpshesphhkshdrihhmqeenucfkphepjeejrddufe drudekhedrjedvnecuvehluhhsthgvrhfuihiivgepgeenucfrrghrrghmpehmrghilhhf rhhomhepphhssehpkhhsrdhimh X-ME-Proxy: Received: from vm-mail.pks.im (x4d0db948.dyn.telefonica.de [77.13.185.72]) by mail.messagingengine.com (Postfix) with ESMTPA id 74BA9328005E; Wed, 25 Mar 2020 05:54:01 -0400 (EDT) Received: from localhost (ncase [10.192.0.11]) by vm-mail.pks.im (OpenSMTPD) with ESMTPSA id 73538aa7 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 25 Mar 2020 09:54:00 +0000 (UTC) Date: Wed, 25 Mar 2020 10:54:01 +0100 From: Patrick Steinhardt To: git Cc: Christian Couder Subject: [PATCH 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 d2b917a47c..6f4e8e88c1 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 Wed Mar 25 09:54:09 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 11457351 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 C180392A for ; Wed, 25 Mar 2020 09:54:11 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 96C3120775 for ; Wed, 25 Mar 2020 09:54:11 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="ZPezLTte"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="oEzl1u3K" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727494AbgCYJyK (ORCPT ); Wed, 25 Mar 2020 05:54:10 -0400 Received: from out5-smtp.messagingengine.com ([66.111.4.29]:40403 "EHLO out5-smtp.messagingengine.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726154AbgCYJyK (ORCPT ); Wed, 25 Mar 2020 05:54:10 -0400 Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.nyi.internal (Postfix) with ESMTP id BD5A55C0227; Wed, 25 Mar 2020 05:54:08 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute3.internal (MEProxy); Wed, 25 Mar 2020 05:54:08 -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=E3pORn4g+20avaF/z39bVQaTeHZ /UXiNAg6fm9aH54E=; b=ZPezLTteraKifHRyLlFiEArpQ25QTngQQ1gJZLPqrx6 ugjSlGyQVA8t6lSfsMOLfbFJZP8ij9A8ll+GxWJ925elfKNYXwrbDyJwUnB8U6YB 7Q1WBk3djNexv+cVlB2RAGIEPxwFn8sKq6JRIyuUqZnNYX3QO2f8XsPlR/pMg4SA Cu9fY+t/0rKZmO1jcMJbrb/XCZZD4yXajMdcASWAmxcue+QCHMgEPL87ljBcv2I9 YHd0CCqI2fibPTNYur5aicSXobULGmr4Yhr/MjSVy8U4NlhAosFACk+z53+1iuvx D+W+qJA//1TgOdWaE8beGCDbgVhFnxgQAfnQtaDUJ1Q== 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=E3pORn 4g+20avaF/z39bVQaTeHZ/UXiNAg6fm9aH54E=; b=oEzl1u3KlCZK+shIU66E8V H9I5Tqt9Pycd6DSNCv0upg1pFJE9SSXHeLJTM5gnmxT2rWwIvgyoSvWJx7DCysF2 9Sglpare5+vwE/YewrF98nfwIguPHClz/p/MYkzxeMyZRsOzKdY3/TYum3ZbYNsz MkHdd4bsNRQqpoKpBDMYtm5K5pQbx7tVtOrBFthR9EJ7GxNaez//9OZ/cDxz78V2 jhBWcOJHtKQhyUAZI+JGou4STrSBgdgacFLzBL2YMs8X0msinnLTNk929D9j6CiS diQazGh3aSSR68TkKCItaIUeGYWnx0tjP91qOanjrRkerWh44VEvYzTP/NBv/5Cw == X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedugedrudehfedgtdekucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvffukfhfgggtuggjsehgtderredttddvnecuhfhrohhmpefrrghtrhhi tghkucfuthgvihhnhhgrrhguthcuoehpshesphhkshdrihhmqeenucfkphepjeejrddufe drudekhedrjedvnecuvehluhhsthgvrhfuihiivgepheenucfrrghrrghmpehmrghilhhf rhhomhepphhssehpkhhsrdhimh X-ME-Proxy: Received: from vm-mail.pks.im (x4d0db948.dyn.telefonica.de [77.13.185.72]) by mail.messagingengine.com (Postfix) with ESMTPA id 26CF7328005A; Wed, 25 Mar 2020 05:54:08 -0400 (EDT) Received: from localhost (ncase [10.192.0.11]) by vm-mail.pks.im (OpenSMTPD) with ESMTPSA id 8862f0ad (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 25 Mar 2020 09:54:07 +0000 (UTC) Date: Wed, 25 Mar 2020 10:54:09 +0100 From: Patrick Steinhardt To: git Cc: Christian Couder Subject: [PATCH 6/9] update-ref: pass end pointer instead of strbuf Message-ID: <51ebb2f8496641380aed4810fa0bb7ebc3bc0a99.1585129842.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 6f4e8e88c1..6f036ae765 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 *); } commands[] = { { "update", parse_cmd_update }, { "create", parse_cmd_create }, @@ -378,7 +378,7 @@ static void update_refs_stdin(struct ref_transaction *transaction) input.buf[strlen(cmd->prefix)] != ' ') die("%s: no separator after command", cmd->prefix); - next = cmd->fn(transaction, &input, next); + next = cmd->fn(transaction, next, input.buf + input.len); next++; } From patchwork Wed Mar 25 09:54:16 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 11457353 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 520D192A for ; Wed, 25 Mar 2020 09:54:19 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 286B62078D for ; Wed, 25 Mar 2020 09:54:19 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="ijOnzR3r"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="umKQaVsD" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727260AbgCYJyS (ORCPT ); Wed, 25 Mar 2020 05:54:18 -0400 Received: from out5-smtp.messagingengine.com ([66.111.4.29]:55539 "EHLO out5-smtp.messagingengine.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726043AbgCYJyR (ORCPT ); Wed, 25 Mar 2020 05:54:17 -0400 Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.nyi.internal (Postfix) with ESMTP id 665AC5C0227; Wed, 25 Mar 2020 05:54:16 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute3.internal (MEProxy); Wed, 25 Mar 2020 05:54:16 -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=qjE1dLyd86/2PFfowjUBjXBk9l+ Qv3TEJ4R+NS9QVbw=; b=ijOnzR3rWDrN0F0x5L86EaebKH06vYIYOCxBA01qm/E 0AVxiAgM7tLTidLXy1/reipimfI6xFZfsBVp16UDiuyY/uGltuXWekQ2h96sKIUM t9X7tR93Hf7f5LymZxINywGxJ3bQvsNMEokfQph3ESw77ZFNErnuUzq8cuBd6S2l jSAAcOuVbpPIdkN20mIElgVPwW0e4sFNZJw9cAc3FcH/P1w3IWPYB9R2nCKkPYTF rtKQq4LiBccrbMhpC3eNIA89ZNugjuv/w5Q2I2UAbVCsDxRb3dRNxDlHGRFb4Gnd 4urrIf/dLlWzDJ+pKcrDgpZv08OFsiEj9rqYJiwfTgQ== 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=qjE1dL yd86/2PFfowjUBjXBk9l+Qv3TEJ4R+NS9QVbw=; b=umKQaVsD+JCblDiALgq40i NIXd6VYaLbImaVATcfSu1FQMWf8GKI1GsOfl4tj3mCTFgL/I8lVmWEPOuIYE67D6 oG/6gqRB5HLwl9A+bdCyrapwFqo405jvAVw+Xui7aWChE07X82Us3h4RwXcaMTwf ptHy3rr7+B2IICV1n6bwHm2Et1bmkq7sJrv8sAp8v3VJW//Qo/L8HDovj30Mqdcg zzaYQgR7eCHVUfUJcO0DfZiIgcWgZjXXxmEekwRN6kcrT/R7PVFpmCrCTwbHlAyL JoeosEH6YWacxl0QJ11Vy1Wh3eEKimXRweGDwgkUoejQe1zqryZL1TeOOEy9deHg == X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedugedrudehfedgtdekucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvffukfhfgggtuggjsehgtderredttddvnecuhfhrohhmpefrrghtrhhi tghkucfuthgvihhnhhgrrhguthcuoehpshesphhkshdrihhmqeenucfkphepjeejrddufe drudekhedrjedvnecuvehluhhsthgvrhfuihiivgepieenucfrrghrrghmpehmrghilhhf rhhomhepphhssehpkhhsrdhimh X-ME-Proxy: Received: from vm-mail.pks.im (x4d0db948.dyn.telefonica.de [77.13.185.72]) by mail.messagingengine.com (Postfix) with ESMTPA id CDC57328005A; Wed, 25 Mar 2020 05:54:15 -0400 (EDT) Received: from localhost (ncase [10.192.0.11]) by vm-mail.pks.im (OpenSMTPD) with ESMTPSA id 9faa6cd2 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 25 Mar 2020 09:54:14 +0000 (UTC) Date: Wed, 25 Mar 2020 10:54:16 +0100 From: Patrick Steinhardt To: git Cc: Christian Couder Subject: [PATCH 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 6f036ae765..5f97bb0b75 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; @@ -382,6 +388,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); } @@ -416,21 +427,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 Wed Mar 25 09:54: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: 11457355 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 3AC0B92A for ; Wed, 25 Mar 2020 09:54:26 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 071F12078E for ; Wed, 25 Mar 2020 09:54:26 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="ED/D5Rj8"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="gh/7bDQL" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727566AbgCYJyZ (ORCPT ); Wed, 25 Mar 2020 05:54:25 -0400 Received: from out5-smtp.messagingengine.com ([66.111.4.29]:34409 "EHLO out5-smtp.messagingengine.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726043AbgCYJyY (ORCPT ); Wed, 25 Mar 2020 05:54:24 -0400 Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.nyi.internal (Postfix) with ESMTP id 1AD625C0229; Wed, 25 Mar 2020 05:54:23 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute3.internal (MEProxy); Wed, 25 Mar 2020 05:54: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=Wh+k+Hnb0FDreKuj4sizYeeAjpL /fLJ5sNSAB30OMvM=; b=ED/D5Rj8RNiHxNCkcauO5v3gQD3w4WczmgSkyGTP9gt XCgi1BQoRjQsbGu235dl8Q6UMiGXM6qSz9RBw83w0Bv5mxNvDV4O9AcawLPGkcof OfNXfPAoDzkRuqtF8RbpG7cDmPSZswOuKBfpWA8u1gTaPuf2y+6gJx2yhV4a7VDm ph/BVYDCJt8c1sHpeJ8AfBj1csxszMn1mfgc4dBqLkYQ+1k8GtqiO7VL9nQl1efq 8rBLitXN6qG3uo5qP47CeQW/Tju8zhdXjEbcUG8NVVNV2VY8CgWW4qza3ZBKtaTV zW2UgnygSehJ8NWBgMP7NrbynONdoRho5UFWnPEslMQ== 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=Wh+k+H nb0FDreKuj4sizYeeAjpL/fLJ5sNSAB30OMvM=; b=gh/7bDQLMDuKuuVG5RnGUu W0JxJquc8taH4fz6KiNLaww8IEkfbkyHXG6faH2NRRdv2w/JsTog+gMgPmNVT6XW CTOOCmwqBO5UE0iZqBnFHff2tPlZLc19mSYWjvrB9+EPYpPrONwshsnJ0v1qUAzz PPfKIgvTF4eqIhRe+19jICoUUBz7o4PbhjwWLpmRHreotgjG4hsI0wpHCN4TlEnc kRKqssew4WUA2idDbxVbYC1HFS3c+tTpCjrGibT+nhCOyL1fn7ClPWo9tha/N1oo mjzyruz1Gn0EH0XSuQdf4bJ+91lzms8YCqjN/0Gw+J5G/1bNk3EJrgHkF51RmT6A == X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedugedrudehfedgtdekucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvffukfhfgggtuggjsehgtderredttddvnecuhfhrohhmpefrrghtrhhi tghkucfuthgvihhnhhgrrhguthcuoehpshesphhkshdrihhmqeenucfkphepjeejrddufe drudekhedrjedvnecuvehluhhsthgvrhfuihiivgepjeenucfrrghrrghmpehmrghilhhf rhhomhepphhssehpkhhsrdhimh X-ME-Proxy: Received: from vm-mail.pks.im (x4d0db948.dyn.telefonica.de [77.13.185.72]) by mail.messagingengine.com (Postfix) with ESMTPA id 7A907328005A; Wed, 25 Mar 2020 05:54:22 -0400 (EDT) Received: from localhost (ncase [10.192.0.11]) by vm-mail.pks.im (OpenSMTPD) with ESMTPSA id 95263dc8 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 25 Mar 2020 09:54:21 +0000 (UTC) Date: Wed, 25 Mar 2020 10:54:22 +0100 From: Patrick Steinhardt To: git Cc: Christian Couder Subject: [PATCH 8/9] update-ref: read commands in a line-wise fashion Message-ID: <1db63f97ec78fad794cec51c5d96b093f7cd2440.1585129843.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 | 70 ++++++++++++++++++++------------------------ 1 file changed, 31 insertions(+), 39 deletions(-) diff --git a/builtin/update-ref.c b/builtin/update-ref.c index 5f97bb0b75..f35e3ca5ae 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,60 +324,60 @@ 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 *); + unsigned extra_lines; } commands[] = { - { "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(commands); i++) { - if (!skip_prefix(next, commands[i].prefix , &next)) + if (!starts_with(input.buf, commands[i].prefix)) continue; cmd = &commands[i]; break; } if (!cmd) - die("unknown command: %s", next); + die("unknown command: %s", input.buf); if (input.buf[strlen(cmd->prefix)] != line_termination && input.buf[strlen(cmd->prefix)] != '\0' && input.buf[strlen(cmd->prefix)] != ' ') die("%s: no separator after command", cmd->prefix); - next = cmd->fn(transaction, next, input.buf + input.len); - next++; + /* Read extra lines if NUL-terminated */ + 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 Wed Mar 25 09:54:29 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 11457357 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 67BAD14B4 for ; Wed, 25 Mar 2020 09:54:32 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 196202078A for ; Wed, 25 Mar 2020 09:54:32 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="gSGDDi9b"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="FDOlhJif" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727590AbgCYJyb (ORCPT ); Wed, 25 Mar 2020 05:54:31 -0400 Received: from out5-smtp.messagingengine.com ([66.111.4.29]:51105 "EHLO out5-smtp.messagingengine.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726225AbgCYJya (ORCPT ); Wed, 25 Mar 2020 05:54:30 -0400 Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.nyi.internal (Postfix) with ESMTP id A6DDB5C020A; Wed, 25 Mar 2020 05:54:29 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute3.internal (MEProxy); Wed, 25 Mar 2020 05:54:29 -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=Rn9ffNuhkdXVqVddTmAOF5KVbMn sVFuOQBeok/ITJdk=; b=gSGDDi9bxQxhXbj1KHmXmwT9OkDt7YBf6D2IGUr0GWJ j5cBljqtmYjkx0JHkGJpTcI375DNARbo6xP1F12/cV8P7q9Y0YE1X9ZpDHqHa6b0 rp4jPpk1B3rZdAIg3+pcoI0lClUdEWnHT1GclK2DG/2neif+R2KQsI44udyskDNr o+PaflEfALpccw7eJXIe7GdWfMaBw6f/wdDsCRY1JOXjt4TKtPRQK6tnmoCKXPot 1gEXWzZjFOt2f4VJYiz2+9ScReb9IcGmnGZv19U0b/xRCNB2K3O101l8UcnnwhdI 7emnIdduWo26dAcukLyiD1MDnvdJBAnjGz2RHkQ+90w== 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=Rn9ffN uhkdXVqVddTmAOF5KVbMnsVFuOQBeok/ITJdk=; b=FDOlhJifrE5f/1QE4/alyB h4iImNJNRdLoukrUlpEU3GelsYbFgfSTmw+UTQx1m/aYVewM3UsuJCT587CjDsPt dVllzx5r2Osedi1dLFE2fPGShNyEfQFoV4OAxwGd2AqsBkBTxCF2O9b9hwmI4Lih SHxYbZJsfQ3VgdW0HD/Y/vagAGXFofPzSvAgj9fumT3f52uenonr1QLfszk5IQ9b tnCAgbL0wiM+DddMvuoXiGRF/PS8pEqf37+rTX8TfcGlIdMDhF/qzw5vtwmDYmbZ 3ljGBJEqNOP/jjotMReDAfvAwCJgmpHogMeDUFrFEdDpDgf6nz8TY2VkOKzDhZyQ == X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedugedrudehfedgtdekucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvffukfhfgggtuggjsehgtderredttddvnecuhfhrohhmpefrrghtrhhi tghkucfuthgvihhnhhgrrhguthcuoehpshesphhkshdrihhmqeenucfkphepjeejrddufe drudekhedrjedvnecuvehluhhsthgvrhfuihiivgepkeenucfrrghrrghmpehmrghilhhf rhhomhepphhssehpkhhsrdhimh X-ME-Proxy: Received: from vm-mail.pks.im (x4d0db948.dyn.telefonica.de [77.13.185.72]) by mail.messagingengine.com (Postfix) with ESMTPA id 257DF3280063; Wed, 25 Mar 2020 05:54:29 -0400 (EDT) Received: from localhost (ncase [10.192.0.11]) by vm-mail.pks.im (OpenSMTPD) with ESMTPSA id 7293b864 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 25 Mar 2020 09:54:27 +0000 (UTC) Date: Wed, 25 Mar 2020 10:54:29 +0100 From: Patrick Steinhardt To: git Cc: Christian Couder Subject: [PATCH 9/9] update-ref: implement interactive transaction handling Message-ID: <88c0089bb50bca13efc79a1f8fd42b80286af949.1585129843.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 | 108 ++++++++++++++++++++++--- t/t1400-update-ref.sh | 131 +++++++++++++++++++++++++++++++ 3 files changed, 256 insertions(+), 9 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 f35e3ca5ae..6b870507e0 100644 --- a/builtin/update-ref.c +++ b/builtin/update-ref.c @@ -326,21 +326,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 extra_lines; + enum update_refs_state state; } commands[] = { - { "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; @@ -371,19 +430,50 @@ static void update_refs_stdin(void) input.buf[strlen(cmd->prefix)] != ' ') die("%s: no separator after command", cmd->prefix); - /* Read extra lines if NUL-terminated */ + /* Read extra lines if NUL-terminated, but let commands handle missing ones. */ for (j = 0; line_termination == '\0' && j < cmd->extra_lines; j++) 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