From patchwork Tue Dec 10 02:33:30 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Emily Shaffer X-Patchwork-Id: 11281229 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 B6650112B for ; Tue, 10 Dec 2019 02:33:55 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 919392073D for ; Tue, 10 Dec 2019 02:33:55 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="MN4n6yDi" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726631AbfLJCdy (ORCPT ); Mon, 9 Dec 2019 21:33:54 -0500 Received: from mail-yb1-f202.google.com ([209.85.219.202]:50980 "EHLO mail-yb1-f202.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726509AbfLJCdy (ORCPT ); Mon, 9 Dec 2019 21:33:54 -0500 Received: by mail-yb1-f202.google.com with SMTP id d191so10303935ybc.17 for ; Mon, 09 Dec 2019 18:33:53 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=Zg7COmVjgFoHl1E+QYjacBwUuAGzzhPi5DZOyD0SzJc=; b=MN4n6yDipLq9thdBqajPLVmML2YaSaDfFiRCAzJYYOW6rq2RbKcifzq189OEEFcNB0 T5uymQ6oNcm+rHmZPSthoJyUCOOL6LcMJ6e0gQG0H1uv3YKiPZeIgdrnAD61aE5SO3/d L7CeGDGfPy46JURVbkkWUDMk5nelnomHydUgJbZx+82i/85rrRk6dRLAmeiCnX/ICIqW K7+admKSbgeiH++WRYtlHmAnSws0m4OrzXDprkaImFkbVb4j63sxBALgZ0H+ES7VKD8R nXtE6GzeKeguk4qg4kCLUYGpsvH8qC46OU/EsxzF+5FF0K2WORiVebcjosOnHtWlUK9u rg1Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=Zg7COmVjgFoHl1E+QYjacBwUuAGzzhPi5DZOyD0SzJc=; b=f4C5P11yD2+DTvbN6w6nRnkq5ZtrH1Ah+NUtSdeunwOZZx5PJHHXEqev+AZNPoC0/h +kyIq79JmWbcLEzCEfgYmXhkvhOIL3hADIUhI+CW7y013EEaW6BG6MhD3gR9CJS2x9Rp M80oEGyzbfuqmuEXyc7qFHVcu6cOaen+utdml6klLyY6XyECRc+bs3tbdCadt4GalwRH CCSKOTXrbFUo/MToyTb1hUYNvGRCs/tUauJUXx4g4Lh3gTY2rpSK1CyVRzX5QR4i7cCL 2hGDE65YneusbpA/ULdKjBynlQKyjT8fwSojPgNYlwVCZ4U9I5t+S3xA3sC4N6ik4QkG GHBw== X-Gm-Message-State: APjAAAX1Uk142DAxiR5HLiOwt0Y82mDLnPFNU+kUiNiWt5RrQiYBfq7n gSXzXSnbUW83h53W575/H38qpX3WVfkzhT6yl5EVUREqledYyPYIZTeq40y74R0D1ZP2RWWGKe9 TkGTkU77YFEcNoaAInXMKaDD1RLYZgTuyRQetlVb/fu8jH12i4HB0XrFORfeTzZI6Q4ACtXrnzA == X-Google-Smtp-Source: APXvYqynrB+S62BB28crex/HXIEEr82/VapfqQNOaQgZtwNeMqtpDHZsCSnhDwnf5T6VhZfP3Y2lzZP9M5mJyYJ41p4= X-Received: by 2002:a81:63c4:: with SMTP id x187mr23175389ywb.458.1575945233138; Mon, 09 Dec 2019 18:33:53 -0800 (PST) Date: Mon, 9 Dec 2019 18:33:30 -0800 In-Reply-To: <20191210023335.49987-1-emilyshaffer@google.com> Message-Id: <20191210023335.49987-2-emilyshaffer@google.com> Mime-Version: 1.0 References: <20191210023335.49987-1-emilyshaffer@google.com> X-Mailer: git-send-email 2.24.0.393.g34dc348eaf-goog Subject: [PATCH 1/6] hook: scaffolding for git-hook subcommand From: Emily Shaffer To: git@vger.kernel.org Cc: Emily Shaffer Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org Introduce infrastructure for a new subcommand, git-hook, which will be used to ease config-based hook management. This command will handle parsing configs to compose a list of hooks to run for a given event, as well as adding or modifying hook configs in an interactive fashion. Signed-off-by: Emily Shaffer --- .gitignore | 1 + Documentation/git-hook.txt | 19 +++++++++++++++++++ Makefile | 1 + builtin.h | 1 + builtin/hook.c | 21 +++++++++++++++++++++ git.c | 1 + t/t1360-config-based-hooks.sh | 11 +++++++++++ 7 files changed, 55 insertions(+) create mode 100644 Documentation/git-hook.txt create mode 100644 builtin/hook.c create mode 100755 t/t1360-config-based-hooks.sh diff --git a/.gitignore b/.gitignore index 89b3b79c1a..9ef59b9baa 100644 --- a/.gitignore +++ b/.gitignore @@ -74,6 +74,7 @@ /git-grep /git-hash-object /git-help +/git-hook /git-http-backend /git-http-fetch /git-http-push diff --git a/Documentation/git-hook.txt b/Documentation/git-hook.txt new file mode 100644 index 0000000000..2d50c414cc --- /dev/null +++ b/Documentation/git-hook.txt @@ -0,0 +1,19 @@ +git-hook(1) +=========== + +NAME +---- +git-hook - Manage configured hooks + +SYNOPSIS +-------- +[verse] +'git hook' + +DESCRIPTION +----------- +You can list, add, and modify hooks with this command. + +GIT +--- +Part of the linkgit:git[1] suite diff --git a/Makefile b/Makefile index 58b92af54b..83263505c0 100644 --- a/Makefile +++ b/Makefile @@ -1074,6 +1074,7 @@ BUILTIN_OBJS += builtin/get-tar-commit-id.o BUILTIN_OBJS += builtin/grep.o BUILTIN_OBJS += builtin/hash-object.o BUILTIN_OBJS += builtin/help.o +BUILTIN_OBJS += builtin/hook.o BUILTIN_OBJS += builtin/index-pack.o BUILTIN_OBJS += builtin/init-db.o BUILTIN_OBJS += builtin/interpret-trailers.o diff --git a/builtin.h b/builtin.h index 5cf5df69f7..d4ca2ac9a5 100644 --- a/builtin.h +++ b/builtin.h @@ -173,6 +173,7 @@ int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix); int cmd_grep(int argc, const char **argv, const char *prefix); int cmd_hash_object(int argc, const char **argv, const char *prefix); int cmd_help(int argc, const char **argv, const char *prefix); +int cmd_hook(int argc, const char **argv, const char *prefix); int cmd_index_pack(int argc, const char **argv, const char *prefix); int cmd_init_db(int argc, const char **argv, const char *prefix); int cmd_interpret_trailers(int argc, const char **argv, const char *prefix); diff --git a/builtin/hook.c b/builtin/hook.c new file mode 100644 index 0000000000..b2bbc84d4d --- /dev/null +++ b/builtin/hook.c @@ -0,0 +1,21 @@ +#include "cache.h" + +#include "builtin.h" +#include "parse-options.h" + +static const char * const builtin_hook_usage[] = { + N_("git hook"), + NULL +}; + +int cmd_hook(int argc, const char **argv, const char *prefix) +{ + struct option builtin_hook_options[] = { + OPT_END(), + }; + + argc = parse_options(argc, argv, prefix, builtin_hook_options, + builtin_hook_usage, 0); + + return 0; +} diff --git a/git.c b/git.c index ce6ab0ece2..c8344b9ab7 100644 --- a/git.c +++ b/git.c @@ -513,6 +513,7 @@ static struct cmd_struct commands[] = { { "grep", cmd_grep, RUN_SETUP_GENTLY }, { "hash-object", cmd_hash_object }, { "help", cmd_help }, + { "hook", cmd_hook, RUN_SETUP }, { "index-pack", cmd_index_pack, RUN_SETUP_GENTLY | NO_PARSEOPT }, { "init", cmd_init_db }, { "init-db", cmd_init_db }, diff --git a/t/t1360-config-based-hooks.sh b/t/t1360-config-based-hooks.sh new file mode 100755 index 0000000000..34b0df5216 --- /dev/null +++ b/t/t1360-config-based-hooks.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +test_description='config-managed multihooks, including git-hook command' + +. ./test-lib.sh + +test_expect_success 'git hook command does not crash' ' + git hook +' + +test_done From patchwork Tue Dec 10 02:33:31 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Emily Shaffer X-Patchwork-Id: 11281231 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 D4C18112B for ; Tue, 10 Dec 2019 02:33:57 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id B3CDB2077B for ; Tue, 10 Dec 2019 02:33:57 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="sbVZi3oi" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726668AbfLJCd4 (ORCPT ); Mon, 9 Dec 2019 21:33:56 -0500 Received: from mail-pf1-f202.google.com ([209.85.210.202]:46141 "EHLO mail-pf1-f202.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726509AbfLJCd4 (ORCPT ); Mon, 9 Dec 2019 21:33:56 -0500 Received: by mail-pf1-f202.google.com with SMTP id w127so10476162pfb.13 for ; Mon, 09 Dec 2019 18:33:56 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=7kQygg+M3WrQt4WoU3MrW8wSA25Q/mrUwb7oj8GtMEU=; b=sbVZi3oiR1H5bAdpjcwq2N63yrUFoXVN78SFC/bofQojzGXDkjurnFKvzsCMGlTVlh UrXjRaCN1uv8KKoswwAPU/zwrFPE/K/zw9Bd2JPi0eYl/N053QIOPQCdkf3ZKHiuq54t 2//qw/OR3aPISR1TFezXrB+a1HAzG4kdBnFc6w48VIOd1cxkIfI5t1wgnjpjxK6XJkKD uceffh4WA1DQHpSB1zKFyo6x+oCawg29qSApukfCzoO/rH85HJY+GscNRp6zJ+MydhDp 05WkamHx+KzzrgAw1TZamDerP7fPScrFyxu6+Isq2Xwih21f60CetR72jSrezGTg5mzE fgnw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=7kQygg+M3WrQt4WoU3MrW8wSA25Q/mrUwb7oj8GtMEU=; b=l+cZ1o/2QOABeSM3yD/DSZ1rEF4b++hHCw0fHNqPQBsb70iwR45xm1uMFWIJyjHiRm hOZg7qUE9x8rDhK5lBkJiqEd6rJ8mB++xqtwEXgNZLKy1pHncZDgWZ1btMUY5YROuIme I2C9suqgcxG8uhm6262j7NaLvmKV+ECxqI35pP17Yq2Inez5e7jFXw7RLGsgtE5GU6ux 8GGml2YPBaSH0Vgos8lUJuT41dHyzjX2oBDJ5Nc2bNPJL5TpVg5I62tHIcgCMqct+U1q O0r5OpwRFTAJK9defkczAPgUCCxOoLgYlFoPaONa2cfEFyMvsG2BNpM5VW3z9SERWmQI 9Bvg== X-Gm-Message-State: APjAAAV265hnlBglS9ZjipAf1PMyWBSPlSRUa2CqfioJzlnd4rf+UkR/ +AFyeUEEU8jpoDy6hmWFtD5tM269Y2dHZttMLfUcQMcV7QSrxvq9SbzjCjDk0e7dT/p1CwlnBMv xcGZCYly2hEm2kRa30ndKwBkcTJWVjq9j4iGN3BfI2eSAxfaEToSNGBw4sU/ybMiCAfHKdynAcQ == X-Google-Smtp-Source: APXvYqwkW5muZg5U0uHnbx2YxAL2w1EwQKVyeEnfLwLeI9lXEuJv6riIlW4w4anLnJDBkKZ3S27vxCigpcIapwG98W0= X-Received: by 2002:a63:447:: with SMTP id 68mr22635789pge.364.1575945235732; Mon, 09 Dec 2019 18:33:55 -0800 (PST) Date: Mon, 9 Dec 2019 18:33:31 -0800 In-Reply-To: <20191210023335.49987-1-emilyshaffer@google.com> Message-Id: <20191210023335.49987-3-emilyshaffer@google.com> Mime-Version: 1.0 References: <20191210023335.49987-1-emilyshaffer@google.com> X-Mailer: git-send-email 2.24.0.393.g34dc348eaf-goog Subject: [PATCH 2/6] config: add string mapping for enum config_scope From: Emily Shaffer To: git@vger.kernel.org Cc: Emily Shaffer Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org If a user is interacting with their config files primarily by the 'git config' command, using the location flags (--global, --system, etc) then they may be more interested to see the scope of the config file they are editing, rather than the filepath. Signed-off-by: Emily Shaffer --- config.c | 17 +++++++++++++++++ config.h | 1 + 2 files changed, 18 insertions(+) diff --git a/config.c b/config.c index e7052b3977..a20110e016 100644 --- a/config.c +++ b/config.c @@ -3312,6 +3312,23 @@ enum config_scope current_config_scope(void) return current_parsing_scope; } +const char *config_scope_to_string(enum config_scope scope) +{ + switch (scope) { + case CONFIG_SCOPE_SYSTEM: + return _("system"); + case CONFIG_SCOPE_GLOBAL: + return _("global"); + case CONFIG_SCOPE_REPO: + return _("repo"); + case CONFIG_SCOPE_CMDLINE: + return _("cmdline"); + case CONFIG_SCOPE_UNKNOWN: + default: + return _("unknown"); + } +} + int lookup_config(const char **mapping, int nr_mapping, const char *var) { int i; diff --git a/config.h b/config.h index f0ed464004..612f43acd0 100644 --- a/config.h +++ b/config.h @@ -139,6 +139,7 @@ enum config_scope { }; enum config_scope current_config_scope(void); +const char *config_scope_to_string(enum config_scope); const char *current_config_origin_type(void); const char *current_config_name(void); From patchwork Tue Dec 10 02:33:32 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Emily Shaffer X-Patchwork-Id: 11281233 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 3B038930 for ; Tue, 10 Dec 2019 02:34:00 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 18BF62073D for ; Tue, 10 Dec 2019 02:33:59 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="a4gNJTKC" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726675AbfLJCd7 (ORCPT ); Mon, 9 Dec 2019 21:33:59 -0500 Received: from mail-pf1-f202.google.com ([209.85.210.202]:40744 "EHLO mail-pf1-f202.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726509AbfLJCd6 (ORCPT ); Mon, 9 Dec 2019 21:33:58 -0500 Received: by mail-pf1-f202.google.com with SMTP id d127so10479231pfa.7 for ; Mon, 09 Dec 2019 18:33:58 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=ggZF69UtlBPHcYM+6WWl8faTyBeVGaBUKV8FevVyN8w=; b=a4gNJTKC3LvZpXtDpvE2mJ8EnYWm83+cPq/vuBz1ZD2aIAxOZohFTLDjmycU0h/6jl VZSc+aGeIUq6yWOFbrOHnDWB884U3oT9K7B62josFfHV7Rqt/lqbujdDDjQB7+y0pur0 QQrZ/TZBs4CE6GVyrPafOBQlYvdxvaRVkSCLf+S4pJuPW2qZZWEuDxTTZ/gF3ZcbrKS2 sptLajOk+MY7mAK9CIS3C+L5kUSU/Cqg88dUoZKcgTnsi9L/ekzLxOO4lXdUoWt+pxZQ v/v6yKv8jO04hINE8jspOFJg4FYvH7tPDNPTSUnl+48Rrsz2thMuGjCAZHcMK9MaClZt mjyQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=ggZF69UtlBPHcYM+6WWl8faTyBeVGaBUKV8FevVyN8w=; b=ZU5sSycGUI+1j1VlQLzhm9L8ns0A6gIojgdFKIExgBwpCtfAAecgkOOQrZeCYsDMRu EXGEdEqI2y2hfolk9Xk+5O6P8LzvsxZ8E9Y1jlwLWZ64/n87u2syT58d/+8jfP/KyfEK wH5vrJsI6KvTiD8vRabbCm8ESxYc+S8+lal5L366URUY8l7B+diCCIRpRYz9EfWdxeSQ WBa5IobscxLL99FEMPmKlzXNGFkahgbhBdoIxHLkApAyZRrFAeCN1ke0rMl1IpTMQcV8 z1lfZLl0xRtIoyoaFZpDfiSJkCArfkqnJkCX+Jt3A/xKc+I1tkjNIZvejFWFLagA4L/v zN2w== X-Gm-Message-State: APjAAAWHE6onsAw6vuYeWOj2vyamrxHj6kySQzwr4qwDYqvVx+LzffwF LQ58rGpqkkEAA59/c+P2zuqUUSqhdgwZaprfGQhVI3kIWShg58V2Fu0wtsBh91XHvT5FBfzvh8B tEqvkhYRle0UQ8wNOaedD6af6uIO9U7hzvMEnKgKykRnw1HlrNPG1Xgwl/0G4oCWWlScMU8aobg == X-Google-Smtp-Source: APXvYqzaZ7fFR6mo4rs0BvlePBRpw7NIVLDHp/i0qiAwCXlNWJrZgwQd36w5i3WrEOqjzKjoHD2JqmN1SpsnhWn2x60= X-Received: by 2002:a63:b26:: with SMTP id 38mr21914487pgl.116.1575945237982; Mon, 09 Dec 2019 18:33:57 -0800 (PST) Date: Mon, 9 Dec 2019 18:33:32 -0800 In-Reply-To: <20191210023335.49987-1-emilyshaffer@google.com> Message-Id: <20191210023335.49987-4-emilyshaffer@google.com> Mime-Version: 1.0 References: <20191210023335.49987-1-emilyshaffer@google.com> X-Mailer: git-send-email 2.24.0.393.g34dc348eaf-goog Subject: [PATCH 3/6] hook: add --list mode From: Emily Shaffer To: git@vger.kernel.org Cc: Emily Shaffer Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org Teach 'git hook --list ', which checks the known configs in order to create an ordered list of hooks to run on a given hook event. The hook config format is "hook. = :". This paves the way for multiple hook support; hooks should be run in the order specified by the user in the config, and in the case of an order number collision, configuration order should be used (e.g. global hook 004 will run before repo hook 004). For example: $ grep -A2 "\[hook\]" ~/.gitconfig [hook] pre-commit = 001:~/test.sh pre-commit = 999:~/baz.sh $ grep -A1 "\[hook\]" ~/git/.git/config [hook] pre-commit = 900:~/bar.sh $ ./bin-wrappers/git hook --list pre-commit 001 global ~/test.sh 900 repo ~/bar.sh 999 global ~/baz.sh Signed-off-by: Emily Shaffer --- Documentation/git-hook.txt | 17 +++++++- Makefile | 1 + builtin/hook.c | 54 ++++++++++++++++++++++- hook.c | 81 +++++++++++++++++++++++++++++++++++ hook.h | 14 ++++++ t/t1360-config-based-hooks.sh | 43 ++++++++++++++++++- 6 files changed, 206 insertions(+), 4 deletions(-) create mode 100644 hook.c create mode 100644 hook.h diff --git a/Documentation/git-hook.txt b/Documentation/git-hook.txt index 2d50c414cc..a141884239 100644 --- a/Documentation/git-hook.txt +++ b/Documentation/git-hook.txt @@ -8,12 +8,27 @@ git-hook - Manage configured hooks SYNOPSIS -------- [verse] -'git hook' +'git hook' -l | --list DESCRIPTION ----------- You can list, add, and modify hooks with this command. +This command parses the default configuration files for lines which look like +"hook. = :", e.g. "hook.pre-commit = +010:/path/to/script.sh". In this way, multiple scripts can be run during a +single hook. Hooks are sorted in ascending order by order number; in the event +of an order number conflict, they are sorted in configuration order. + +OPTIONS +------- + +-l:: +--list:: + List the hooks which have been configured for . Hooks appear + in the order they should be run. Output of this command follows the + format ' '. + GIT --- Part of the linkgit:git[1] suite diff --git a/Makefile b/Makefile index 83263505c0..21b3a82208 100644 --- a/Makefile +++ b/Makefile @@ -892,6 +892,7 @@ LIB_OBJS += hashmap.o LIB_OBJS += linear-assignment.o LIB_OBJS += help.o LIB_OBJS += hex.o +LIB_OBJS += hook.o LIB_OBJS += ident.o LIB_OBJS += interdiff.o LIB_OBJS += json-writer.o diff --git a/builtin/hook.c b/builtin/hook.c index b2bbc84d4d..8261302b27 100644 --- a/builtin/hook.c +++ b/builtin/hook.c @@ -1,21 +1,73 @@ #include "cache.h" #include "builtin.h" +#include "config.h" +#include "hook.h" #include "parse-options.h" +#include "strbuf.h" static const char * const builtin_hook_usage[] = { - N_("git hook"), + N_("git hook --list "), NULL }; +enum hook_command { + HOOK_NO_COMMAND = 0, + HOOK_LIST, +}; + +static int print_hook_list(const struct strbuf *hookname) +{ + struct list_head *head, *pos; + struct hook *item; + + head = hook_list(hookname); + + list_for_each(pos, head) { + item = list_entry(pos, struct hook, list); + if (item) + printf("%.3d\t%s\t%s\n", item->order, + config_scope_to_string(item->origin), + item->command.buf); + } + + return 0; +} + int cmd_hook(int argc, const char **argv, const char *prefix) { + enum hook_command command = 0; + struct strbuf hookname = STRBUF_INIT; + struct option builtin_hook_options[] = { + OPT_CMDMODE('l', "list", &command, + N_("list scripts which will be run for "), + HOOK_LIST), OPT_END(), }; argc = parse_options(argc, argv, prefix, builtin_hook_options, builtin_hook_usage, 0); + if (argc < 1) { + usage_msg_opt("a hookname must be provided to operate on.", + builtin_hook_usage, builtin_hook_options); + } + + strbuf_addstr(&hookname, "hook."); + strbuf_addstr(&hookname, argv[0]); + + switch(command) { + case HOOK_LIST: + return print_hook_list(&hookname); + break; + default: + usage_msg_opt("no command given.", builtin_hook_usage, + builtin_hook_options); + } + + clear_hook_list(); + strbuf_release(&hookname); + return 0; } diff --git a/hook.c b/hook.c new file mode 100644 index 0000000000..f8d1109084 --- /dev/null +++ b/hook.c @@ -0,0 +1,81 @@ +#include "cache.h" + +#include "hook.h" +#include "config.h" + +static LIST_HEAD(hook_head); + +void free_hook(struct hook *ptr) +{ + if (ptr) { + strbuf_release(&ptr->command); + free(ptr); + } +} + +static void emplace_hook(struct list_head *pos, int order, const char *command) +{ + struct hook *to_add = malloc(sizeof(struct hook)); + to_add->order = order; + to_add->origin = current_config_scope(); + strbuf_init(&to_add->command, 0); + strbuf_addstr(&to_add->command, command); + + list_add_tail(&to_add->list, pos); +} + +static void remove_hook(struct list_head *to_remove) +{ + struct hook *hook_to_remove = list_entry(to_remove, struct hook, list); + list_del(to_remove); + free_hook(hook_to_remove); +} + +void clear_hook_list() +{ + struct list_head *pos, *tmp; + list_for_each_safe(pos, tmp, &hook_head) + remove_hook(pos); +} + +static int check_config_for_hooks(const char *var, const char *value, void *hookname) +{ + struct list_head *pos, *p; + struct hook *item; + const struct strbuf *hookname_strbuf = hookname; + + if (!strcmp(var, hookname_strbuf->buf)) { + int order = 0; + // TODO this is bad - open to overflows + char command[256]; + int added = 0; + if (!sscanf(value, "%d:%s", &order, command)) + die(_("hook config '%s' doesn't match expected format"), + value); + + list_for_each_safe(pos, p, &hook_head) { + item = list_entry(pos, struct hook, list); + + /* + * the new entry should go just before the first entry + * which has a higher order number than it. + */ + if (item->order > order && !added) { + emplace_hook(pos, order, command); + added = 1; + } + } + + if (!added) + emplace_hook(pos, order, command); + } + + return 0; +} + +struct list_head* hook_list(const struct strbuf* hookname) +{ + git_config(check_config_for_hooks, (void*)hookname); + + return &hook_head; +} diff --git a/hook.h b/hook.h new file mode 100644 index 0000000000..104df4c088 --- /dev/null +++ b/hook.h @@ -0,0 +1,14 @@ +#include "config.h" + +struct hook +{ + struct list_head list; + int order; + enum config_scope origin; + struct strbuf command; +}; + +struct list_head* hook_list(const struct strbuf *hookname); + +void free_hook(struct hook *ptr); +void clear_hook_list(); diff --git a/t/t1360-config-based-hooks.sh b/t/t1360-config-based-hooks.sh index 34b0df5216..1434051db3 100755 --- a/t/t1360-config-based-hooks.sh +++ b/t/t1360-config-based-hooks.sh @@ -4,8 +4,47 @@ test_description='config-managed multihooks, including git-hook command' . ./test-lib.sh -test_expect_success 'git hook command does not crash' ' - git hook +test_expect_success 'git hook rejects commands without a mode' ' + test_must_fail git hook pre-commit +' + + +test_expect_success 'git hook rejects commands without a hookname' ' + test_must_fail git hook --list +' + +test_expect_success 'setup hooks in system, global, and local' ' + git config --add --global hook.pre-commit "010:/path/def" && + git config --add --global hook.pre-commit "999:/path/uvw" && + + git config --add --local hook.pre-commit "100:/path/ghi" && + git config --add --local hook.pre-commit "990:/path/rst" +' + +test_expect_success 'git hook --list orders by order number' ' + cat >expected <<-\EOF && + 010 global /path/def + 100 repo /path/ghi + 990 repo /path/rst + 999 global /path/uvw + EOF + + git hook --list pre-commit >actual && + test_cmp expected actual +' + +test_expect_success 'order number collisions resolved in config order' ' + cat >expected <<-\EOF && + 010 global /path/def + 010 repo /path/abc + 100 repo /path/ghi + 990 repo /path/rst + 999 global /path/uvw + EOF + + git config --add --local hook.pre-commit "010:/path/abc" && + git hook --list pre-commit >actual && + test_cmp expected actual ' test_done From patchwork Tue Dec 10 02:33:33 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Emily Shaffer X-Patchwork-Id: 11281235 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 8914D930 for ; Tue, 10 Dec 2019 02:34:02 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 677462073D for ; Tue, 10 Dec 2019 02:34:02 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="aDfGPglD" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726689AbfLJCeB (ORCPT ); Mon, 9 Dec 2019 21:34:01 -0500 Received: from mail-pg1-f201.google.com ([209.85.215.201]:40183 "EHLO mail-pg1-f201.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726509AbfLJCeB (ORCPT ); Mon, 9 Dec 2019 21:34:01 -0500 Received: by mail-pg1-f201.google.com with SMTP id z12so9761514pgf.7 for ; Mon, 09 Dec 2019 18:34:00 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=K8or5ZeKpAf6ZAbE/hDuC3yP5yGtul5JFSNDQJlJ44c=; b=aDfGPglDRkTxbdyR8PPurABCtyhX9fu9HjuP4qcq0rWJ2SDs4sb0iBwvZEHcDibRhx AHVLMutbSro8aOWeefacGg56uq0KIbPA00UQGOjfqjJUbg/kWOcZ91SZ7AFiNtaOXxW3 04t5P6FW+DncxUwD6ZWyU9XS7e5xTXmjOnJXskCp14d9mn3IJWKocrPi6vwTJFkwpGo4 Cv3gMcp0+Lor/vgktfRmPeR6FdiQ/7YySF4b0zRvgaYDwZ7ufBWuI0dtkdjCxNGr2qpZ fyRl2SXiI40d3gukWNZYX2Z5vwGxQjLryMR6foQZbwLaXTaE/i27ciZNJK0AG3ynuAsR kFrg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=K8or5ZeKpAf6ZAbE/hDuC3yP5yGtul5JFSNDQJlJ44c=; b=gOlIgu42gnftbmeRpyZ+Y1VwHrbGr6bfCz9hyJwc2H4XaXEUymumQtKbQXY3Leqp5R 3jlfj+XTu2QtYFN9/OwV28XCQkBi9U2EAWKyj+56hsynEz4Li8uruVBG30DYWx+VZoMV NFUR1WCvaisRxza0H3tSaFH4AiY3yzZWcf9vQ3hBwsylK/qeB38+juCWfdqvrtWFH/sL csXAgKhbFhl4iqn5LVxTjBxugdFLuCUSEKWYAgzATymbP8fUMqLL52bdXBKcgguAfWig 4ZwZBwjR7NhDAFNyslsIbbW/b/e/oma7bAgrk6aWXoIAE8GHrjO5L+kdYakfFeALSwD6 ywGw== X-Gm-Message-State: APjAAAWp7GlpRqjhuOlWY/Ki5c2RNj/4dbYIAIKbaeWKs5uq8N5eEQEi N4RNVfpEVOBMroIZYg+Fwi3uqI7eRfTDAg+UM7NMbMzIsoWUWiwaDIVogblVXqNqMiIps2pK3ZV vuOHoPgAz/wzCgyJm7IFTsAZ2RJ/IXsZAIM0Blfrp8aDO/BDMJnNRsKrg0Ih2ptzNoGxrT7sFeQ == X-Google-Smtp-Source: APXvYqwdesb/UQy4Y++n5RYlzzoLZ2KCfYB2+VfGlDftcLVhKtJrrXJQrivkbCreGu4TZYexSI/vw9NIeRvaUoK90S0= X-Received: by 2002:a63:cc02:: with SMTP id x2mr22428641pgf.114.1575945240167; Mon, 09 Dec 2019 18:34:00 -0800 (PST) Date: Mon, 9 Dec 2019 18:33:33 -0800 In-Reply-To: <20191210023335.49987-1-emilyshaffer@google.com> Message-Id: <20191210023335.49987-5-emilyshaffer@google.com> Mime-Version: 1.0 References: <20191210023335.49987-1-emilyshaffer@google.com> X-Mailer: git-send-email 2.24.0.393.g34dc348eaf-goog Subject: [PATCH 4/6] hook: support reordering of hook list From: Emily Shaffer To: git@vger.kernel.org Cc: Emily Shaffer Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org It's possible that in most cases a user wants to run pre-commit hook 'A', but in exactly one repo that user wants to run pre-commit hook 'A' first instead. Teach 'git hook' to support this by allowing a user to specify a new order number for a hook after the initial hook has been specified. For example: $ grep -A2 "\[hook\]" ~/.gitconfig [hook] pre-commit = 001:~/test.sh pre-commit = 999:~/baz.sh $ grep -A2 "\[hook\]" ~/git/.git/config [hook] pre-commit = 900:~/bar.sh pre-commit = 050:~/baz.sh $ ./bin-wrappers/git hook --list pre-commit 001 global ~/test.sh 050 repo ~/baz.sh 900 repo ~/bar.sh In the above example, '~/baz.sh' is provided in the global config with order position 999. Then, in the local config, that order is overridden to 050. Instead of running ~/baz.sh twice (at order 050 and at order 999), only run it once, in the position specified last in config order. Signed-off-by: Emily Shaffer --- Documentation/git-hook.txt | 8 ++++++++ hook.c | 7 +++++++ t/t1360-config-based-hooks.sh | 14 ++++++++++++++ 3 files changed, 29 insertions(+) diff --git a/Documentation/git-hook.txt b/Documentation/git-hook.txt index a141884239..0f7115f826 100644 --- a/Documentation/git-hook.txt +++ b/Documentation/git-hook.txt @@ -20,6 +20,14 @@ This command parses the default configuration files for lines which look like single hook. Hooks are sorted in ascending order by order number; in the event of an order number conflict, they are sorted in configuration order. +The order number of a hook can be changed at a more local scope, e.g.: + + git config --add --global hook.pre-commit "001:/foo.sh" + git config --add --local hook.pre-commit "005:/foo.sh" + +When the order number is respecified this way, the previously specified hook +configuration is overridden. + OPTIONS ------- diff --git a/hook.c b/hook.c index f8d1109084..a7dcd18a2e 100644 --- a/hook.c +++ b/hook.c @@ -64,6 +64,13 @@ static int check_config_for_hooks(const char *var, const char *value, void *hook emplace_hook(pos, order, command); added = 1; } + + /* + * if the command already exists, this entry should be + * replacing it. + */ + if (!strcmp(item->command.buf, command)) + remove_hook(pos); } if (!added) diff --git a/t/t1360-config-based-hooks.sh b/t/t1360-config-based-hooks.sh index 1434051db3..1af43ef18d 100755 --- a/t/t1360-config-based-hooks.sh +++ b/t/t1360-config-based-hooks.sh @@ -47,4 +47,18 @@ test_expect_success 'order number collisions resolved in config order' ' test_cmp expected actual ' +test_expect_success 'adding a command with a different number reorders list' ' + cat >expected <<-\EOF && + 010 repo /path/abc + 050 repo /path/def + 100 repo /path/ghi + 990 repo /path/rst + 999 global /path/uvw + EOF + + git config --add --local hook.pre-commit "050:/path/def" && + git hook --list pre-commit >actual && + test_cmp expected actual +' + test_done From patchwork Tue Dec 10 02:33:34 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Emily Shaffer X-Patchwork-Id: 11281237 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 ADDF1112B for ; Tue, 10 Dec 2019 02:34:04 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 8C88B2077B for ; Tue, 10 Dec 2019 02:34:04 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="LJkB88cB" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726718AbfLJCeD (ORCPT ); Mon, 9 Dec 2019 21:34:03 -0500 Received: from mail-pl1-f201.google.com ([209.85.214.201]:39963 "EHLO mail-pl1-f201.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726509AbfLJCeD (ORCPT ); Mon, 9 Dec 2019 21:34:03 -0500 Received: by mail-pl1-f201.google.com with SMTP id o12so8298136pll.7 for ; Mon, 09 Dec 2019 18:34:03 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=Bb82FN8P4glPGoUSEAdIcE8asLCT95m8hDLYehq9zV0=; b=LJkB88cBlPulERyI2SD1s6g/jxFwUs44uEXO2Do/jYDcUBmtLrMidk/yf5dp+PK3mt kRap1hDnD+hEHTz5RTJvBPsH9j18dRrRCohMk3r8KfnVPPKCKR6jGnXHkJ9yjtkX5GSg nLSsdLg8gow0B91IucDBvmIofw8HeTCkOQqEuTa5OSejNX7v4oCqONa8jIsNuyncKDs0 QtX/AkBgnL3iB9kNi8pifWa/1BoXrSOw1reiLUAaR8vSs2tGocYxYF01FXUx6K2QfD2K uJ4WA9OCp0uQVkvxh3FJ5x5QKiaABLxgHhd6XMv1d3/xtw7OC6FcNLvYy+DqtCIilgPw ti+g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=Bb82FN8P4glPGoUSEAdIcE8asLCT95m8hDLYehq9zV0=; b=RgBwGtgauA6LJJvpEcxpA1EBc5qZxzPuZdw+nXDISFMY+TcHEC+Z9Gw0OLMQvwpYmG iJNEGsXZHik1uI6g55T35AcZLaROLl8ufi8ExoR7Grv5Ai+lyMbmGtyIMBUT1WawUfoD hSwebITnOHpDdJo4ACoSDhDJpUtWWy3CbF2TYmf+MPXt6fGpMgrBV5FD1tTmOY/Fd7nd TdMf7cBdc5GLvy6edU/ti4aBYKbba2UJSK2ftPT8N/gtxgXCedcFeY+p9XdPQ/sf2c41 TD6RA2GjCm4qjbLkQs2X4oxdc9Txnc4doScucbK2Gk5pZGOWJiSQDdL6ac8y0XqRn6Av 0RoQ== X-Gm-Message-State: APjAAAW65sEECXvNxngCypld0ttqd4jGFISDjsTedw3M0RRNsiK34K/R 3Z8HY2GV/JIa9iNPkMJmJd0wCbk6oR35fv760FTLQ39cIHCabEdIsUpBtveJvWwJKiTGjyKTusm IgbT/buxUNL3OU16gYeBl3ACfC0eTTqzoo8V36Kh4UyS5xjxmwnMjk7w5drGahg8TWnmMODvTiw == X-Google-Smtp-Source: APXvYqy5EFoVWQRXn8HklfvAOZfw+Moce6K8XOYOkoDUlVQRenjo2fUWEwRzpnjuwIFDxx7n3Ebvz1k+R1aWdO+cxso= X-Received: by 2002:a63:ed49:: with SMTP id m9mr21814147pgk.304.1575945242566; Mon, 09 Dec 2019 18:34:02 -0800 (PST) Date: Mon, 9 Dec 2019 18:33:34 -0800 In-Reply-To: <20191210023335.49987-1-emilyshaffer@google.com> Message-Id: <20191210023335.49987-6-emilyshaffer@google.com> Mime-Version: 1.0 References: <20191210023335.49987-1-emilyshaffer@google.com> X-Mailer: git-send-email 2.24.0.393.g34dc348eaf-goog Subject: [PATCH 5/6] hook: remove prior hook with '---' From: Emily Shaffer To: git@vger.kernel.org Cc: Emily Shaffer Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org It's possible a user may want to run a hook for nearly every repo, except for one. Rather than requiring the user to specify the hook locally in all but one repo, teach 'git hook' how to interpret config lines intended to remove hooks specified earlier during the config parse. This means a user can specify such a hook at the system or global level and override it at the local level. For example: $ grep -A2 "\[hook\]" ~/.gitconfig [hook] pre-commit = 001:~/test.sh pre-commit = 999:~/baz.sh $ grep -A2 "\[hook\]" ~/git/.git/config [hook] pre-commit = 900:~/bar.sh pre-commit = ---:~/baz.sh $ ./bin-wrappers/git hook --list pre-commit 001 global ~/test.sh 900 repo ~/bar.sh Signed-off-by: Emily Shaffer --- Documentation/git-hook.txt | 8 ++++++++ hook.c | 15 ++++++++++----- t/t1360-config-based-hooks.sh | 13 +++++++++++++ 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/Documentation/git-hook.txt b/Documentation/git-hook.txt index 0f7115f826..b4a992d43f 100644 --- a/Documentation/git-hook.txt +++ b/Documentation/git-hook.txt @@ -28,6 +28,14 @@ The order number of a hook can be changed at a more local scope, e.g.: When the order number is respecified this way, the previously specified hook configuration is overridden. +A hook specified at a more global scope can be removed by specifying "---" +instead of an order number, e.g.: + + git config --add --global hook.pre-commit "001:/foo.sh" + git config --add --local hook.pre-commit "---:/foo.sh" + +When the hook is removed in this way, `/foo.sh` will not be run at all. + OPTIONS ------- diff --git a/hook.c b/hook.c index a7dcd18a2e..e7afa140c8 100644 --- a/hook.c +++ b/hook.c @@ -49,9 +49,14 @@ static int check_config_for_hooks(const char *var, const char *value, void *hook // TODO this is bad - open to overflows char command[256]; int added = 0; - if (!sscanf(value, "%d:%s", &order, command)) - die(_("hook config '%s' doesn't match expected format"), - value); + int remove = 0; + if (!sscanf(value, "%d:%s", &order, command)) { + if (sscanf(value, "---:%s", command)) + remove = 1; + else + die(_("hook config '%s' doesn't match expected format"), + value); + } list_for_each_safe(pos, p, &hook_head) { item = list_entry(pos, struct hook, list); @@ -60,7 +65,7 @@ static int check_config_for_hooks(const char *var, const char *value, void *hook * the new entry should go just before the first entry * which has a higher order number than it. */ - if (item->order > order && !added) { + if (item->order > order && !added && !remove) { emplace_hook(pos, order, command); added = 1; } @@ -73,7 +78,7 @@ static int check_config_for_hooks(const char *var, const char *value, void *hook remove_hook(pos); } - if (!added) + if (!added && !remove) emplace_hook(pos, order, command); } diff --git a/t/t1360-config-based-hooks.sh b/t/t1360-config-based-hooks.sh index 1af43ef18d..66e70ae222 100755 --- a/t/t1360-config-based-hooks.sh +++ b/t/t1360-config-based-hooks.sh @@ -61,4 +61,17 @@ test_expect_success 'adding a command with a different number reorders list' ' test_cmp expected actual ' +test_expect_success 'remove a command with "---:/path/to/cmd"' ' + cat >expected <<-\EOF && + 010 repo /path/abc + 050 repo /path/def + 100 repo /path/ghi + 990 repo /path/rst + EOF + + git config --add --local hook.pre-commit "---:/path/uvw" && + git hook --list pre-commit >actual && + test_cmp expected actual +' + test_done From patchwork Tue Dec 10 02:33:35 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Emily Shaffer X-Patchwork-Id: 11281239 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 8CECD112B for ; Tue, 10 Dec 2019 02:34:07 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 6B2912073D for ; Tue, 10 Dec 2019 02:34:07 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="R5jzTwD4" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726743AbfLJCeG (ORCPT ); Mon, 9 Dec 2019 21:34:06 -0500 Received: from mail-yw1-f73.google.com ([209.85.161.73]:47233 "EHLO mail-yw1-f73.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726509AbfLJCeG (ORCPT ); Mon, 9 Dec 2019 21:34:06 -0500 Received: by mail-yw1-f73.google.com with SMTP id j9so13319846ywg.14 for ; Mon, 09 Dec 2019 18:34:05 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=L4/lhw0eWd7OzgLDjeTG7MAEG4lKOXjksggmyh8Tb5k=; b=R5jzTwD4SPNhTEGoLY8Exs1foYGONL5uTz1cykWhmOSMr/vfg8bS3uORWABLWyB4Rt OiPQMiYfgsWjvFYzE5LbziBMCeqzcDJAP6GGMtjp0vDxBXBqXUD1n1YApzE7bNiL/M/j JE1ECqiiVwomo6+oc55bcw1B7JIlhFbMLeq3N0y/cO5jFJk/EtYhHZlenFLVSIKNVoqd fW2vPjdJcd9hBWjE+832nGnCUat/fx+I5q9SG9T2KCadiak1U+vieBWO/as7RD85uFVs NgbK0dhgdOKmN+ofla8cUsGkZbyLCjcaTaGz3obNZZLJiBqiFHK3CbEh7/KFf3z1cAtT jpTQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=L4/lhw0eWd7OzgLDjeTG7MAEG4lKOXjksggmyh8Tb5k=; b=Yl0pBgCmHS1S9KdXVzDVCF4nJ/+p4T5LzlUKjXHPPGv9N6KWg11Ui71q0TmC4duL/L N7S/7qud3U/koTrc18qqJczqdkoTyPDL3ZcVeEl+zWCQ+wWGNk6YBfk917Ni3hxwfREG TAgp7xkUR1I61JHSopu8hDAzbH9JelNVc2JocJpLwXoW/d4ZdRIr8y1uG9kisDbda8gL 9fv89RrkrueVgiB+Vg6y59T/767MQIsWZndpSN3EU8Yp/Lvfsp/1vHUogSlatPPXa01O z1CNQR+mVPe1JEdTgaVKsq5jfmoqDCFoaqbOgeZeIGW+C8ZpPBEnI+lYPMzDTn0H+BB2 23Uw== X-Gm-Message-State: APjAAAV12+BSTIZrcoU/SYZi+nd9g8xX75AmvliFKAqMkOt947IlDM6c nIKdno7+S261oBL01bu+wez3ZuSmuSe/DvDkhlK1Qzzis63u4uOXdom+pNlleJHcUUznVWkTsXf JYoS0gPZSAB7y7WYxSOkiQr2rWVCl/ula0OldNXlU8TuO4b/gUvQnl0B5F4XhC+y7VjE4xMATnQ == X-Google-Smtp-Source: APXvYqz8c/UOxhdyw8yJ7D7EwUnoWafOiT/IRD99A25NzFMWlkCHY3HLmaON6Vz2BERxt7F6Q2VXbt8nyTecytVYpT8= X-Received: by 2002:a81:af5f:: with SMTP id x31mr24108915ywj.264.1575945245151; Mon, 09 Dec 2019 18:34:05 -0800 (PST) Date: Mon, 9 Dec 2019 18:33:35 -0800 In-Reply-To: <20191210023335.49987-1-emilyshaffer@google.com> Message-Id: <20191210023335.49987-7-emilyshaffer@google.com> Mime-Version: 1.0 References: <20191210023335.49987-1-emilyshaffer@google.com> X-Mailer: git-send-email 2.24.0.393.g34dc348eaf-goog Subject: [PATCH 6/6] hook: teach --porcelain mode From: Emily Shaffer To: git@vger.kernel.org Cc: Emily Shaffer Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org It might be desirable - for a user script, or a scripted Git command - to run the appropriate set of hooks from outside of the compiled Git binary. So, teach --porcelain in a way that enables the following: git hook --list --porcelain pre-commit | xargs -I% sh "%" Signed-off-by: Emily Shaffer --- Documentation/git-hook.txt | 5 ++++- builtin/hook.c | 19 +++++++++++++------ t/t1360-config-based-hooks.sh | 12 ++++++++++++ 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/Documentation/git-hook.txt b/Documentation/git-hook.txt index b4a992d43f..34276f5bce 100644 --- a/Documentation/git-hook.txt +++ b/Documentation/git-hook.txt @@ -8,7 +8,7 @@ git-hook - Manage configured hooks SYNOPSIS -------- [verse] -'git hook' -l | --list +'git hook' -l | --list [--porcelain] DESCRIPTION ----------- @@ -45,6 +45,9 @@ OPTIONS in the order they should be run. Output of this command follows the format ' '. +--porcelain:: + Print in a machine-readable format suitable for scripting. + GIT --- Part of the linkgit:git[1] suite diff --git a/builtin/hook.c b/builtin/hook.c index 8261302b27..b76dd3ad8f 100644 --- a/builtin/hook.c +++ b/builtin/hook.c @@ -16,7 +16,7 @@ enum hook_command { HOOK_LIST, }; -static int print_hook_list(const struct strbuf *hookname) +static int print_hook_list(const struct strbuf *hookname, int porcelain) { struct list_head *head, *pos; struct hook *item; @@ -25,10 +25,14 @@ static int print_hook_list(const struct strbuf *hookname) list_for_each(pos, head) { item = list_entry(pos, struct hook, list); - if (item) - printf("%.3d\t%s\t%s\n", item->order, - config_scope_to_string(item->origin), - item->command.buf); + if (item) { + if (porcelain) + printf("%s\n", item->command.buf); + else + printf("%.3d\t%s\t%s\n", item->order, + config_scope_to_string(item->origin), + item->command.buf); + } } return 0; @@ -38,11 +42,14 @@ int cmd_hook(int argc, const char **argv, const char *prefix) { enum hook_command command = 0; struct strbuf hookname = STRBUF_INIT; + int porcelain = 0; struct option builtin_hook_options[] = { OPT_CMDMODE('l', "list", &command, N_("list scripts which will be run for "), HOOK_LIST), + OPT_BOOL(0, "porcelain", &porcelain, + N_("display in machine parseable format")), OPT_END(), }; @@ -59,7 +66,7 @@ int cmd_hook(int argc, const char **argv, const char *prefix) switch(command) { case HOOK_LIST: - return print_hook_list(&hookname); + return print_hook_list(&hookname, porcelain); break; default: usage_msg_opt("no command given.", builtin_hook_usage, diff --git a/t/t1360-config-based-hooks.sh b/t/t1360-config-based-hooks.sh index 66e70ae222..6f16ea1dd8 100755 --- a/t/t1360-config-based-hooks.sh +++ b/t/t1360-config-based-hooks.sh @@ -33,6 +33,18 @@ test_expect_success 'git hook --list orders by order number' ' test_cmp expected actual ' +test_expect_success 'git hook --list --porcelain' ' + cat >expected <<-\EOF && + /path/def + /path/ghi + /path/rst + /path/uvw + EOF + + git hook --list --porcelain pre-commit >actual && + test_cmp expected actual +' + test_expect_success 'order number collisions resolved in config order' ' cat >expected <<-\EOF && 010 global /path/def