From patchwork Wed Nov 6 09:59:28 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Passaro via GitGitGadget X-Patchwork-Id: 11229921 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 3CACF112B for ; Wed, 6 Nov 2019 10:00:29 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 0710F218AE for ; Wed, 6 Nov 2019 10:00:29 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Sg8VFSJs" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731656AbfKFJ7y (ORCPT ); Wed, 6 Nov 2019 04:59:54 -0500 Received: from mail-wm1-f65.google.com ([209.85.128.65]:34958 "EHLO mail-wm1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727560AbfKFJ7y (ORCPT ); Wed, 6 Nov 2019 04:59:54 -0500 Received: by mail-wm1-f65.google.com with SMTP id 8so2609434wmo.0 for ; Wed, 06 Nov 2019 01:59:50 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=8ItaMLWPuiDh0xwOy8VHn052gcTcGh76NSKNNuJiI7E=; b=Sg8VFSJs2LuetjLzpnQWPYIOaXP5qPJK6eT6ok7VSDHz41GdT9gTz+iFh7F4Zkpeo7 vLPNwnFItyfXDH99nEhYkjkN9XqjWM2cY9/kQAY0yytnZQCnutfWV9P5piwovCTi2MSS F/HldBM/O8I+cGmPw2RGnuXtYSFYx20oX7SKB9hBpouGS/vz/L4ZgsQzHJJEgPGPp4Kf gFoDSwe0gZ+bK4sQ6FASR+7KPp8ZarKdSJ0sKgbcQ5lSuJHrkQ7+xwGS0Uu9ReaJAP9V xMEa7peERtNUo3hvwfKRtoft1hFUULe0AUrWRyHBXiv3V8/D7MSbSFvXMdxuJIwMOLxQ wV7w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=8ItaMLWPuiDh0xwOy8VHn052gcTcGh76NSKNNuJiI7E=; b=NzChnMZZOsUh8Rr7NjlxQxt3R6NUVcInzhJG4FmP/Mnp3kI6ZusVHYW3+F4DZ+FdgR hjUyi4JLHnZPuzvUgc1PFa8iFItnr/zGF7FAaKlPu5x6oulRezRaLm7al3ExStkTMWxp Y0tS19gF85oN9Pxzj+AZWcD6pUUln7QfDM3JZi4zNGxLFawvFMS6OW7pb6pYEsu9OIW5 ubncF1df8BvT3WkA1RBU65GwuDnnPmF91NKJu9xCdAvJ2MnG7LH9MAJe/weiUOwbLklA CPVUG7v0+CqxfiynS5nSHL2XJN0ziiKobe26vxsyycPJPDnwh7z1YiI5N+IvCkdKQoSh 9Ahw== X-Gm-Message-State: APjAAAX/TFrZ0qTrd02l3vwsxNNmeZQmsEdujZM1MR/QWjGBVBoJgBpX fitARhD9zn/EZL0JK0OYqfz4hZk7 X-Google-Smtp-Source: APXvYqyeCmGDuqg8+Hu1yFTlQq+3WOitdKaJlPVQKawBOrZM1vSDOqpPK2AunTe0MiU2d9AytIdRWA== X-Received: by 2002:a05:600c:2389:: with SMTP id m9mr1653665wma.65.1573034389608; Wed, 06 Nov 2019 01:59:49 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id v81sm2403287wmg.4.2019.11.06.01.59.49 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 06 Nov 2019 01:59:49 -0800 (PST) Message-Id: <6cd5f753155886e88c24b5a936aedcdf252c7e27.1573034387.git.gitgitgadget@gmail.com> In-Reply-To: References: From: "Heba Waly via GitGitGadget" Date: Wed, 06 Nov 2019 09:59:28 +0000 Subject: [PATCH v2 01/20] diff: move doc to diff.h and diffcore.h Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Heba Waly , Junio C Hamano , Heba Waly Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Heba Waly Move the documentation from Documentation/technical/api-diff.txt to both diff.h and diffcore.h as it's easier for the developers to find the usage information beside the code instead of looking for it in another doc file. Also documentation/technical/api-diff.txt is removed because the information it has is now redundant and it'll be hard to keep it up to date and synchronized with the documentation in the header files. There are three members documented in the doc file that weren't found in the header files, assuming the doc wasn't up to date and the members no longer exist: touched_flags, COLOR_DIFF_WORDS and QUIET. Signed-off-by: Heba Waly --- Documentation/technical/api-diff.txt | 174 --------------------------- diff.h | 127 +++++++++++++++++++ diffcore.h | 32 +++++ 3 files changed, 159 insertions(+), 174 deletions(-) delete mode 100644 Documentation/technical/api-diff.txt diff --git a/Documentation/technical/api-diff.txt b/Documentation/technical/api-diff.txt deleted file mode 100644 index 30fc0e9c93..0000000000 --- a/Documentation/technical/api-diff.txt +++ /dev/null @@ -1,174 +0,0 @@ -diff API -======== - -The diff API is for programs that compare two sets of files (e.g. two -trees, one tree and the index) and present the found difference in -various ways. The calling program is responsible for feeding the API -pairs of files, one from the "old" set and the corresponding one from -"new" set, that are different. The library called through this API is -called diffcore, and is responsible for two things. - -* finding total rewrites (`-B`), renames (`-M`) and copies (`-C`), and - changes that touch a string (`-S`), as specified by the caller. - -* outputting the differences in various formats, as specified by the - caller. - -Calling sequence ----------------- - -* Prepare `struct diff_options` to record the set of diff options, and - then call `repo_diff_setup()` to initialize this structure. This - sets up the vanilla default. - -* Fill in the options structure to specify desired output format, rename - detection, etc. `diff_opt_parse()` can be used to parse options given - from the command line in a way consistent with existing git-diff - family of programs. - -* Call `diff_setup_done()`; this inspects the options set up so far for - internal consistency and make necessary tweaking to it (e.g. if - textual patch output was asked, recursive behaviour is turned on); - the callback set_default in diff_options can be used to tweak this more. - -* As you find different pairs of files, call `diff_change()` to feed - modified files, `diff_addremove()` to feed created or deleted files, - or `diff_unmerge()` to feed a file whose state is 'unmerged' to the - API. These are thin wrappers to a lower-level `diff_queue()` function - that is flexible enough to record any of these kinds of changes. - -* Once you finish feeding the pairs of files, call `diffcore_std()`. - This will tell the diffcore library to go ahead and do its work. - -* Calling `diff_flush()` will produce the output. - - -Data structures ---------------- - -* `struct diff_filespec` - -This is the internal representation for a single file (blob). It -records the blob object name (if known -- for a work tree file it -typically is a NUL SHA-1), filemode and pathname. This is what the -`diff_addremove()`, `diff_change()` and `diff_unmerge()` synthesize and -feed `diff_queue()` function with. - -* `struct diff_filepair` - -This records a pair of `struct diff_filespec`; the filespec for a file -in the "old" set (i.e. preimage) is called `one`, and the filespec for a -file in the "new" set (i.e. postimage) is called `two`. A change that -represents file creation has NULL in `one`, and file deletion has NULL -in `two`. - -A `filepair` starts pointing at `one` and `two` that are from the same -filename, but `diffcore_std()` can break pairs and match component -filespecs with other filespecs from a different filepair to form new -filepair. This is called 'rename detection'. - -* `struct diff_queue` - -This is a collection of filepairs. Notable members are: - -`queue`:: - - An array of pointers to `struct diff_filepair`. This - dynamically grows as you add filepairs; - -`alloc`:: - - The allocated size of the `queue` array; - -`nr`:: - - The number of elements in the `queue` array. - - -* `struct diff_options` - -This describes the set of options the calling program wants to affect -the operation of diffcore library with. - -Notable members are: - -`output_format`:: - The output format used when `diff_flush()` is run. - -`context`:: - Number of context lines to generate in patch output. - -`break_opt`, `detect_rename`, `rename-score`, `rename_limit`:: - Affects the way detection logic for complete rewrites, renames - and copies. - -`abbrev`:: - Number of hexdigits to abbreviate raw format output to. - -`pickaxe`:: - A constant string (can and typically does contain newlines to - look for a block of text, not just a single line) to filter out - the filepairs that do not change the number of strings contained - in its preimage and postimage of the diff_queue. - -`flags`:: - This is mostly a collection of boolean options that affects the - operation, but some do not have anything to do with the diffcore - library. - -`touched_flags`:: - Records whether a flag has been changed due to user request - (rather than just set/unset by default). - -`set_default`:: - Callback which allows tweaking the options in diff_setup_done(). - -BINARY, TEXT;; - Affects the way how a file that is seemingly binary is treated. - -FULL_INDEX;; - Tells the patch output format not to use abbreviated object - names on the "index" lines. - -FIND_COPIES_HARDER;; - Tells the diffcore library that the caller is feeding unchanged - filepairs to allow copies from unmodified files be detected. - -COLOR_DIFF;; - Output should be colored. - -COLOR_DIFF_WORDS;; - Output is a colored word-diff. - -NO_INDEX;; - Tells diff-files that the input is not tracked files but files - in random locations on the filesystem. - -ALLOW_EXTERNAL;; - Tells output routine that it is Ok to call user specified patch - output routine. Plumbing disables this to ensure stable output. - -QUIET;; - Do not show any output. - -REVERSE_DIFF;; - Tells the library that the calling program is feeding the - filepairs reversed; `one` is two, and `two` is one. - -EXIT_WITH_STATUS;; - For communication between the calling program and the options - parser; tell the calling program to signal the presence of - difference using program exit code. - -HAS_CHANGES;; - Internal; used for optimization to see if there is any change. - -SILENT_ON_REMOVE;; - Affects if diff-files shows removed files. - -RECURSIVE, TREE_IN_RECURSIVE;; - Tells if tree traversal done by tree-diff should recursively - descend into a tree object pair that are different in preimage - and postimage set. - -(JC) diff --git a/diff.h b/diff.h index 7f8f024feb..86d7871618 100644 --- a/diff.h +++ b/diff.h @@ -9,6 +9,49 @@ #include "object.h" #include "oidset.h" +/** + * The diff API is for programs that compare two sets of files (e.g. two trees, + * one tree and the index) and present the found difference in various ways. + * The calling program is responsible for feeding the API pairs of files, one + * from the "old" set and the corresponding one from "new" set, that are + * different. + * The library called through this API is called diffcore, and is responsible + * for two things. + * + * - finding total rewrites (`-B`), renames (`-M`) and copies (`-C`), and + * changes that touch a string (`-S`), as specified by the caller. + * + * - outputting the differences in various formats, as specified by the caller. + * + * Calling sequence + * ---------------- + * + * - Prepare `struct diff_options` to record the set of diff options, and then + * call `repo_diff_setup()` to initialize this structure. This sets up the + * vanilla default. + * + * - Fill in the options structure to specify desired output format, rename + * detection, etc. `diff_opt_parse()` can be used to parse options given + * from the command line in a way consistent with existing git-diff family + * of programs. + * + * - Call `diff_setup_done()`; this inspects the options set up so far for + * internal consistency and make necessary tweaking to it (e.g. if textual + * patch output was asked, recursive behaviour is turned on); the callback + * set_default in diff_options can be used to tweak this more. + * + * - As you find different pairs of files, call `diff_change()` to feed + * modified files, `diff_addremove()` to feed created or deleted files, or + * `diff_unmerge()` to feed a file whose state is 'unmerged' to the API. + * These are thin wrappers to a lower-level `diff_queue()` function that is + * flexible enough to record any of these kinds of changes. + * + * - Once you finish feeding the pairs of files, call `diffcore_std()`. + * This will tell the diffcore library to go ahead and do its work. + * + * - Calling `diff_flush()` will produce the output. + */ + struct combine_diff_path; struct commit; struct diff_filespec; @@ -65,21 +108,66 @@ typedef struct strbuf *(*diff_prefix_fn_t)(struct diff_options *opt, void *data) #define DIFF_FLAGS_INIT { 0 } struct diff_flags { + + /** + * Tells if tree traversal done by tree-diff should recursively descend + * into a tree object pair that are different in preimage and postimage set. + */ unsigned recursive; unsigned tree_in_recursive; + + /* Affects the way how a file that is seemingly binary is treated. */ unsigned binary; unsigned text; + + /** + * Tells the patch output format not to use abbreviated object names on the + * "index" lines. + */ unsigned full_index; + + /* Affects if diff-files shows removed files. */ unsigned silent_on_remove; + + /** + * Tells the diffcore library that the caller is feeding unchanged + * filepairs to allow copies from unmodified files be detected. + */ unsigned find_copies_harder; + unsigned follow_renames; unsigned rename_empty; + + /* Internal; used for optimization to see if there is any change. */ unsigned has_changes; + unsigned quick; + + /** + * Tells diff-files that the input is not tracked files but files in random + * locations on the filesystem. + */ unsigned no_index; + + /** + * Tells output routine that it is Ok to call user specified patch output + * routine. Plumbing disables this to ensure stable output. + */ unsigned allow_external; + + /** + * For communication between the calling program and the options parser; + * tell the calling program to signal the presence of difference using + * program exit code. + */ unsigned exit_with_status; + + /** + * Tells the library that the calling program is feeding the filepairs + * reversed; `one` is two, and `two` is one. + */ unsigned reverse_diff; + unsigned check_failed; unsigned relative_name; unsigned ignore_submodules; @@ -131,36 +219,72 @@ enum diff_submodule_format { DIFF_SUBMODULE_INLINE_DIFF }; +/** + * the set of options the calling program wants to affect the operation of + * diffcore library with. + */ struct diff_options { const char *orderfile; + + /** + * A constant string (can and typically does contain newlines to look for + * a block of text, not just a single line) to filter out the filepairs + * that do not change the number of strings contained in its preimage and + * postimage of the diff_queue. + */ const char *pickaxe; + const char *single_follow; const char *a_prefix, *b_prefix; const char *line_prefix; size_t line_prefix_length; + + /** + * collection of boolean options that affects the operation, but some do + * not have anything to do with the diffcore library. + */ struct diff_flags flags; /* diff-filter bits */ unsigned int filter; int use_color; + + /* Number of context lines to generate in patch output. */ int context; + int interhunkcontext; + + /* Affects the way detection logic for complete rewrites, renames and + * copies. + */ int break_opt; int detect_rename; + int irreversible_delete; int skip_stat_unmatch; int line_termination; + + /* The output format used when `diff_flush()` is run. */ int output_format; + unsigned pickaxe_opts; + + /* Affects the way detection logic for complete rewrites, renames and + * copies. + */ int rename_score; int rename_limit; + int needed_rename_limit; int degraded_cc_to_c; int show_rename_progress; int dirstat_permille; int setup; + + /* Number of hexdigits to abbreviate raw format output to. */ int abbrev; + int ita_invisible_in_index; /* white-space error highlighting */ #define WSEH_NEW (1<<12) @@ -192,6 +316,7 @@ struct diff_options { /* to support internal diff recursion by --follow hack*/ int found_follow; + /* Callback which allows tweaking the options in diff_setup_done(). */ void (*set_default)(struct diff_options *); FILE *file; @@ -245,6 +370,7 @@ void diff_emit_submodule_error(struct diff_options *o, const char *err); void diff_emit_submodule_pipethrough(struct diff_options *o, const char *line, int len); +/* Output should be colored. */ enum color_diff { DIFF_RESET = 0, DIFF_CONTEXT = 1, @@ -270,6 +396,7 @@ enum color_diff { DIFF_FILE_OLD_BOLD = 21, DIFF_FILE_NEW_BOLD = 22, }; + const char *diff_get_color(int diff_use_color, enum color_diff ix); #define diff_get_color_opt(o, ix) \ diff_get_color((o)->use_color, ix) diff --git a/diffcore.h b/diffcore.h index b651061c0e..7c07347e42 100644 --- a/diffcore.h +++ b/diffcore.h @@ -28,6 +28,12 @@ struct userdiff_driver; #define MINIMUM_BREAK_SIZE 400 /* do not break a file smaller than this */ +/** + * the internal representation for a single file (blob). It records the blob + * object name (if known -- for a work tree file it typically is a NUL SHA-1), + * filemode and pathname. This is what the `diff_addremove()`, `diff_change()` + * and `diff_unmerge()` synthesize and feed `diff_queue()` function with. + */ struct diff_filespec { struct object_id oid; char *path; @@ -66,6 +72,17 @@ void diff_free_filespec_data(struct diff_filespec *); void diff_free_filespec_blob(struct diff_filespec *); int diff_filespec_is_binary(struct repository *, struct diff_filespec *); +/** + * This records a pair of `struct diff_filespec`; the filespec for a file in + * the "old" set (i.e. preimage) is called `one`, and the filespec for a file + * in the "new" set (i.e. postimage) is called `two`. A change that represents + * file creation has NULL in `one`, and file deletion has NULL in `two`. + * + * A `filepair` starts pointing at `one` and `two` that are from the same + * filename, but `diffcore_std()` can break pairs and match component filespecs + * with other filespecs from a different filepair to form new filepair. This is + * called 'rename detection'. + */ struct diff_filepair { struct diff_filespec *one; struct diff_filespec *two; @@ -77,6 +94,7 @@ struct diff_filepair { unsigned done_skip_stat_unmatch : 1; unsigned skip_stat_unmatch_result : 1; }; + #define DIFF_PAIR_UNMERGED(p) ((p)->is_unmerged) #define DIFF_PAIR_RENAME(p) ((p)->renamed_pair) @@ -94,11 +112,25 @@ void diff_free_filepair(struct diff_filepair *); int diff_unmodified_pair(struct diff_filepair *); +/** + * This is a collection of filepairs. Notable members are: + * + * - `queue`: + * An array of pointers to `struct diff_filepair`. This dynamically grows as + * you add filepairs; + * + * - `alloc`: + * The allocated size of the `queue` array; + * + * - `nr`: + * The number of elements in the `queue` array. + */ struct diff_queue_struct { struct diff_filepair **queue; int alloc; int nr; }; + #define DIFF_QUEUE_CLEAR(q) \ do { \ (q)->queue = NULL; \ From patchwork Wed Nov 6 09:59:29 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Passaro via GitGitGadget X-Patchwork-Id: 11229893 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 223CE1864 for ; Wed, 6 Nov 2019 10:00:03 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id EABD7217F4 for ; Wed, 6 Nov 2019 10:00:02 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="jZiBcTRO" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731658AbfKFJ7y (ORCPT ); Wed, 6 Nov 2019 04:59:54 -0500 Received: from mail-wr1-f50.google.com ([209.85.221.50]:39858 "EHLO mail-wr1-f50.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728633AbfKFJ7y (ORCPT ); Wed, 6 Nov 2019 04:59:54 -0500 Received: by mail-wr1-f50.google.com with SMTP id a11so24943074wra.6 for ; Wed, 06 Nov 2019 01:59:51 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=C4tdvHrsbIUd/BqwlbGvevZdwEQqmIVmLeZz7+YyZvE=; b=jZiBcTROsQAZX/V7HkeGEveumyCKwTCb8D4wS+kUmbQBWpDJuKVTQW0+b4Cb4BPIVB D+GC3no24xobo8b5y1B+bLE5evhrdTWRIIcM0GBqF/ootPoMTYvgbhdp7m6ENRsp3Tnp +SGomv2/Srxic/Nj63KZk/+lAyERy7UTfVQlmJ9XQniTdyJS5WWRZekH0DPWGRy1iknN Xg3kX14SJRfU0cvPjg0HbQNp+ppeZtFsGXZeX2yRwuMC5PbdFTPaFri46pv3IamDumfA vjEyhN4xR+Yu9zrwQJeElGJJPEU6XHUx7MQFj8Fmc3CiHKeyJl0Ek8i9++S5/i0BW6wf s+3w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=C4tdvHrsbIUd/BqwlbGvevZdwEQqmIVmLeZz7+YyZvE=; b=QV5oeXB3mYVUf7KmtN6rIPJO8BDE8QDi+d8/aKOAH+Rp9YSesUW4avBhC9w1p/rNQr Oy3woquYR62pK5LTt9sxfNjFcor5l8v9GHLyP3K0K85fqy/nE0V2NK539XVX4DMLEYtj epzHOhEw899vgOMYwBoSQX5+f4Es0tl2w4Nx0YqLiwp+MWvyxavQ6BZ3BqirtZKlK1YX F4LWdCEiDY6i/yN993R/EeFf9JWPVvJjnDnyG1lKP1oreA6RSDJOtwTZXMc3KDU4jLdX GZDjEnccHrEJ7W9veUSuvA5MACVB9A6Nb0Eexyy5pw3MdqBT6Z90KDEG9lBxwWM84TzR 5Vqg== X-Gm-Message-State: APjAAAX4bwrhspYdfDKcaPkdE60Iyb3w3n3DYScdCTdyCix5rNgFoTZp /TS+t4htwBpSY8Ax4Bt6WBOnpwAP X-Google-Smtp-Source: APXvYqx+H6Sic3i4Xb6sXFAKIu5nhC/ms8yzXBN4QKu748ba7FcyNn9f0AajmaLWH6zTOcX2UloSDg== X-Received: by 2002:adf:e30d:: with SMTP id b13mr1665992wrj.137.1573034390241; Wed, 06 Nov 2019 01:59:50 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id v16sm25051608wrc.84.2019.11.06.01.59.49 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 06 Nov 2019 01:59:49 -0800 (PST) Message-Id: In-Reply-To: References: From: "Heba Waly via GitGitGadget" Date: Wed, 06 Nov 2019 09:59:29 +0000 Subject: [PATCH v2 02/20] dir: move doc to dir.h Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Heba Waly , Junio C Hamano , Heba Waly Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Heba Waly Move the documentation from Documentation/technical/api-directory-listing.txt to dir.h as it's easier for the developers to find the usage information beside the code instead of looking for it in another doc file. Also documentation/technical/api-directory-listing.txt is removed because the information it has is now redundant and it'll be hard to keep it up to date and synchronized with the documentation in the header files. Signed-off-by: Heba Waly --- .../technical/api-directory-listing.txt | 130 ------------------ dir.h | 118 +++++++++++++++- 2 files changed, 113 insertions(+), 135 deletions(-) delete mode 100644 Documentation/technical/api-directory-listing.txt diff --git a/Documentation/technical/api-directory-listing.txt b/Documentation/technical/api-directory-listing.txt deleted file mode 100644 index 76b6e4f71b..0000000000 --- a/Documentation/technical/api-directory-listing.txt +++ /dev/null @@ -1,130 +0,0 @@ -directory listing API -===================== - -The directory listing API is used to enumerate paths in the work tree, -optionally taking `.git/info/exclude` and `.gitignore` files per -directory into account. - -Data structure --------------- - -`struct dir_struct` structure is used to pass directory traversal -options to the library and to record the paths discovered. A single -`struct dir_struct` is used regardless of whether or not the traversal -recursively descends into subdirectories. - -The notable options are: - -`exclude_per_dir`:: - - The name of the file to be read in each directory for excluded - files (typically `.gitignore`). - -`flags`:: - - A bit-field of options: - -`DIR_SHOW_IGNORED`::: - - Return just ignored files in `entries[]`, not untracked - files. This flag is mutually exclusive with - `DIR_SHOW_IGNORED_TOO`. - -`DIR_SHOW_IGNORED_TOO`::: - - Similar to `DIR_SHOW_IGNORED`, but return ignored files in - `ignored[]` in addition to untracked files in - `entries[]`. This flag is mutually exclusive with - `DIR_SHOW_IGNORED`. - -`DIR_KEEP_UNTRACKED_CONTENTS`::: - - Only has meaning if `DIR_SHOW_IGNORED_TOO` is also set; if this is set, the - untracked contents of untracked directories are also returned in - `entries[]`. - -`DIR_SHOW_IGNORED_TOO_MODE_MATCHING`::: - - Only has meaning if `DIR_SHOW_IGNORED_TOO` is also set; if - this is set, returns ignored files and directories that match - an exclude pattern. If a directory matches an exclude pattern, - then the directory is returned and the contained paths are - not. A directory that does not match an exclude pattern will - not be returned even if all of its contents are ignored. In - this case, the contents are returned as individual entries. -+ -If this is set, files and directories that explicitly match an ignore -pattern are reported. Implicitly ignored directories (directories that -do not match an ignore pattern, but whose contents are all ignored) -are not reported, instead all of the contents are reported. - -`DIR_COLLECT_IGNORED`::: - - Special mode for git-add. Return ignored files in `ignored[]` and - untracked files in `entries[]`. Only returns ignored files that match - pathspec exactly (no wildcards). Does not recurse into ignored - directories. - -`DIR_SHOW_OTHER_DIRECTORIES`::: - - Include a directory that is not tracked. - -`DIR_HIDE_EMPTY_DIRECTORIES`::: - - Do not include a directory that is not tracked and is empty. - -`DIR_NO_GITLINKS`::: - - If set, recurse into a directory that looks like a Git - directory. Otherwise it is shown as a directory. - -The result of the enumeration is left in these fields: - -`entries[]`:: - - An array of `struct dir_entry`, each element of which describes - a path. - -`nr`:: - - The number of members in `entries[]` array. - -`alloc`:: - - Internal use; keeps track of allocation of `entries[]` array. - -`ignored[]`:: - - An array of `struct dir_entry`, used for ignored paths with the - `DIR_SHOW_IGNORED_TOO` and `DIR_COLLECT_IGNORED` flags. - -`ignored_nr`:: - - The number of members in `ignored[]` array. - -Calling sequence ----------------- - -Note: index may be looked at for .gitignore files that are CE_SKIP_WORKTREE -marked. If you to exclude files, make sure you have loaded index first. - -* Prepare `struct dir_struct dir` and clear it with `memset(&dir, 0, - sizeof(dir))`. - -* To add single exclude pattern, call `add_pattern_list()` and then - `add_pattern()`. - -* To add patterns from a file (e.g. `.git/info/exclude`), call - `add_patterns_from_file()` , and/or set `dir.exclude_per_dir`. A - short-hand function `setup_standard_excludes()` can be used to set - up the standard set of exclude settings. - -* Set options described in the Data Structure section above. - -* Call `read_directory()`. - -* Use `dir.entries[]`. - -* Call `clear_directory()` when none of the contained elements are no longer in use. - -(JC) diff --git a/dir.h b/dir.h index 2fbdef014f..1b41d29c07 100644 --- a/dir.h +++ b/dir.h @@ -1,11 +1,43 @@ #ifndef DIR_H #define DIR_H -/* See Documentation/technical/api-directory-listing.txt */ - #include "cache.h" #include "strbuf.h" +/** + * The directory listing API is used to enumerate paths in the work tree, + * optionally taking `.git/info/exclude` and `.gitignore` files per directory + * into account. + */ + +/** + * Calling sequence + * ---------------- + * + * Note: index may be looked at for .gitignore files that are CE_SKIP_WORKTREE + * marked. If you to exclude files, make sure you have loaded index first. + * + * - Prepare `struct dir_struct dir` and clear it with `memset(&dir, 0, + * sizeof(dir))`. + * + * - To add single exclude pattern, call `add_pattern_list()` and then + * `add_pattern()`. + * + * - To add patterns from a file (e.g. `.git/info/exclude`), call + * `add_patterns_from_file()` , and/or set `dir.exclude_per_dir`. A + * short-hand function `setup_standard_excludes()` can be used to set + * up the standard set of exclude settings. + * + * - Set options described in the Data Structure section above. + * + * - Call `read_directory()`. + * + * - Use `dir.entries[]`. + * + * - Call `clear_directory()` when none of the contained elements are no longer in use. + * + */ + struct dir_entry { unsigned int len; char name[FLEX_ARRAY]; /* more */ @@ -144,25 +176,101 @@ struct untracked_cache { unsigned int use_fsmonitor : 1; }; +/** + * pass directory traversal options to the library and to record the paths + * discovered. A single `struct dir_struct` is used regardless of whether or + * not the traversal recursively descends into subdirectories. + */ struct dir_struct { - int nr, alloc; - int ignored_nr, ignored_alloc; + + /* The number of members in `entries[]` array. */ + int nr; + + /* Internal use; keeps track of allocation of `entries[]` array.*/ + int alloc; + + /* The number of members in `ignored[]` array. */ + int ignored_nr; + + int ignored_alloc; + + /* bit-field of options */ enum { + + /** + * Return just ignored files in `entries[]`, not untracked files. + * This flag is mutually exclusive with `DIR_SHOW_IGNORED_TOO`. + */ DIR_SHOW_IGNORED = 1<<0, + + /* Include a directory that is not tracked. */ DIR_SHOW_OTHER_DIRECTORIES = 1<<1, + + /* Do not include a directory that is not tracked and is empty. */ DIR_HIDE_EMPTY_DIRECTORIES = 1<<2, + + /** + * If set, recurse into a directory that looks like a Git directory. + * Otherwise it is shown as a directory. + */ DIR_NO_GITLINKS = 1<<3, + + /** + * Special mode for git-add. Return ignored files in `ignored[]` and + * untracked files in `entries[]`. Only returns ignored files that match + * pathspec exactly (no wildcards). Does not recurse into ignored + * directories. + */ DIR_COLLECT_IGNORED = 1<<4, + + /** + * Similar to `DIR_SHOW_IGNORED`, but return ignored files in + * `ignored[]` in addition to untracked files in `entries[]`. + * This flag is mutually exclusive with `DIR_SHOW_IGNORED`. + */ DIR_SHOW_IGNORED_TOO = 1<<5, + DIR_COLLECT_KILLED_ONLY = 1<<6, + + /** + * Only has meaning if `DIR_SHOW_IGNORED_TOO` is also set; if this is + * set, the untracked contents of untracked directories are also + * returned in `entries[]`. + */ DIR_KEEP_UNTRACKED_CONTENTS = 1<<7, + + /** + * Only has meaning if `DIR_SHOW_IGNORED_TOO` is also set; if this is + * set, returns ignored files and directories that match an exclude + * pattern. If a directory matches an exclude pattern, then the + * directory is returned and the contained paths are not. A directory + * that does not match an exclude pattern will not be returned even if + * all of its contents are ignored. In this case, the contents are + * returned as individual entries. + * + * If this is set, files and directories that explicitly match an ignore + * pattern are reported. Implicitly ignored directories (directories that + * do not match an ignore pattern, but whose contents are all ignored) + * are not reported, instead all of the contents are reported. + */ DIR_SHOW_IGNORED_TOO_MODE_MATCHING = 1<<8, + DIR_SKIP_NESTED_GIT = 1<<9 } flags; + + /* An array of `struct dir_entry`, each element of which describes a path. */ struct dir_entry **entries; + + /** + * used for ignored paths with the `DIR_SHOW_IGNORED_TOO` and + * `DIR_COLLECT_IGNORED` flags. + */ struct dir_entry **ignored; - /* Exclude info */ + /** + * The name of the file to be read in each directory for excluded files + * (typically `.gitignore`). + */ const char *exclude_per_dir; /* From patchwork Wed Nov 6 09:59:30 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Passaro via GitGitGadget X-Patchwork-Id: 11229887 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 1D1C5112B for ; Wed, 6 Nov 2019 10:00:00 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id DB9A0217F4 for ; Wed, 6 Nov 2019 09:59:59 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="NUajwj9H" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731717AbfKFJ77 (ORCPT ); Wed, 6 Nov 2019 04:59:59 -0500 Received: from mail-wm1-f66.google.com ([209.85.128.66]:56096 "EHLO mail-wm1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731644AbfKFJ7z (ORCPT ); Wed, 6 Nov 2019 04:59:55 -0500 Received: by mail-wm1-f66.google.com with SMTP id m17so2582512wmi.5 for ; Wed, 06 Nov 2019 01:59:52 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=maRAJuup5abJ1hJXrBJ5YMG/weYvOZoneGLFTTC2A8E=; b=NUajwj9HNlpxpf/8x7nZShaCEmDQS+ISkgqQMvgh6JKgIFXhfdUoKzg2FAb+df4OsO 9UH2KlnZsxgMAZ5/3jG8H9F41odOert1L9/s2LzOdVG9PPZdWvDrkI9UmXR7RfU+lwPN KoSXcjpEBFPhrJNcGzDw746HMdFhSC9D+1msYG4PqZcpK1VeMh+sFtKBIfnyNur/JbwO +QJ139yb7xqDTpUpr3UyPVAKCt1uxgr4RWo/z3RrCk5xPJ2VoUDVBHZToZaPLomrHLH5 RXpmSGhdvU8LOe/Oyv4uGFzeMCPMrCDZyi5ks5GvWVejAm0nZ6K3d+8G5MME7o+LotqH 6Z6Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=maRAJuup5abJ1hJXrBJ5YMG/weYvOZoneGLFTTC2A8E=; b=I7/prDdeaCzyyVdETVmRNlMSWCIey2eh7vS68ljBx6HYowClT+/fobFEAw91ir4g+e wY/QyHt0ShvEH1u7x0xJuaa4iftBa97d5zMBBagFInuzTMvFCu5/B9YYG2vmEik6yqFe kIQUGhLkVs0dn0xNUWf+MnxvTVg6HYPhmAG6fAon87ssf18USPtOs4WKNts4VrMaMXhh Hr2VgkO0V0liX9YJy3bi8jUkgkSbD2BjRDrjO7hNdF1JzyGShFisWAOuiiJiElE7wB/k zB3SKvKjpR8WH+oFjsmGvhU3hwiAC5MGYNd56rjHAXss1OxUHPepKqFgbWFi3d+PMomd 4Z4A== X-Gm-Message-State: APjAAAXbUXnpyAtlxIUr8GtC0XU5+3iwSWvwGCdSt2IrZ+9ccPN7uISI esLA5w8uIPveBUaPmHEeq4/fTlUj X-Google-Smtp-Source: APXvYqzGDCtYGUApF9loRm8gT+rpeBjPhRvzk5hsA7jhV9o0NGOf1gWaNRW8Cw6kJvijyyayXtrwjg== X-Received: by 2002:a1c:6885:: with SMTP id d127mr1570665wmc.64.1573034391192; Wed, 06 Nov 2019 01:59:51 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id g5sm2491524wmf.37.2019.11.06.01.59.50 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 06 Nov 2019 01:59:50 -0800 (PST) Message-Id: In-Reply-To: References: From: "Heba Waly via GitGitGadget" Date: Wed, 06 Nov 2019 09:59:30 +0000 Subject: [PATCH v2 03/20] graph: move doc to graph.h and graph.c Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Heba Waly , Junio C Hamano , Heba Waly Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Heba Waly Move the documentation from Documentation/technical/api-history-graph.txt to graph.h and graph.c as it's easier for the developers to find the usage information beside the code instead of looking for it in another doc file. The graph library was already well documented, so few comments were added to both graph.h and graph.c Also documentation/technical/api-history-graph.txt is removed because the information it has is now redundant and it'll be hard to keep it up to date and synchronized with the documentation in the header file. Signed-off-by: Heba Waly --- Documentation/technical/api-history-graph.txt | 173 ------------------ graph.c | 1 + graph.h | 121 ++++++++++++ 3 files changed, 122 insertions(+), 173 deletions(-) delete mode 100644 Documentation/technical/api-history-graph.txt diff --git a/Documentation/technical/api-history-graph.txt b/Documentation/technical/api-history-graph.txt deleted file mode 100644 index d0d1707c8c..0000000000 --- a/Documentation/technical/api-history-graph.txt +++ /dev/null @@ -1,173 +0,0 @@ -history graph API -================= - -The graph API is used to draw a text-based representation of the commit -history. The API generates the graph in a line-by-line fashion. - -Functions ---------- - -Core functions: - -* `graph_init()` creates a new `struct git_graph` - -* `graph_update()` moves the graph to a new commit. - -* `graph_next_line()` outputs the next line of the graph into a strbuf. It - does not add a terminating newline. - -* `graph_padding_line()` outputs a line of vertical padding in the graph. It - is similar to `graph_next_line()`, but is guaranteed to never print the line - containing the current commit. Where `graph_next_line()` would print the - commit line next, `graph_padding_line()` prints a line that simply extends - all branch lines downwards one row, leaving their positions unchanged. - -* `graph_is_commit_finished()` determines if the graph has output all lines - necessary for the current commit. If `graph_update()` is called before all - lines for the current commit have been printed, the next call to - `graph_next_line()` will output an ellipsis, to indicate that a portion of - the graph was omitted. - -The following utility functions are wrappers around `graph_next_line()` and -`graph_is_commit_finished()`. They always print the output to stdout. -They can all be called with a NULL graph argument, in which case no graph -output will be printed. - -* `graph_show_commit()` calls `graph_next_line()` and - `graph_is_commit_finished()` until one of them return non-zero. This prints - all graph lines up to, and including, the line containing this commit. - Output is printed to stdout. The last line printed does not contain a - terminating newline. - -* `graph_show_oneline()` calls `graph_next_line()` and prints the result to - stdout. The line printed does not contain a terminating newline. - -* `graph_show_padding()` calls `graph_padding_line()` and prints the result to - stdout. The line printed does not contain a terminating newline. - -* `graph_show_remainder()` calls `graph_next_line()` until - `graph_is_commit_finished()` returns non-zero. Output is printed to stdout. - The last line printed does not contain a terminating newline. Returns 1 if - output was printed, and 0 if no output was necessary. - -* `graph_show_strbuf()` prints the specified strbuf to stdout, prefixing all - lines but the first with a graph line. The caller is responsible for - ensuring graph output for the first line has already been printed to stdout. - (This can be done with `graph_show_commit()` or `graph_show_oneline()`.) If - a NULL graph is supplied, the strbuf is printed as-is. - -* `graph_show_commit_msg()` is similar to `graph_show_strbuf()`, but it also - prints the remainder of the graph, if more lines are needed after the strbuf - ends. It is better than directly calling `graph_show_strbuf()` followed by - `graph_show_remainder()` since it properly handles buffers that do not end in - a terminating newline. The output printed by `graph_show_commit_msg()` will - end in a newline if and only if the strbuf ends in a newline. - -Data structure --------------- -`struct git_graph` is an opaque data type used to store the current graph -state. - -Calling sequence ----------------- - -* Create a `struct git_graph` by calling `graph_init()`. When using the - revision walking API, this is done automatically by `setup_revisions()` if - the '--graph' option is supplied. - -* Use the revision walking API to walk through a group of contiguous commits. - The `get_revision()` function automatically calls `graph_update()` each time - it is invoked. - -* For each commit, call `graph_next_line()` repeatedly, until - `graph_is_commit_finished()` returns non-zero. Each call to - `graph_next_line()` will output a single line of the graph. The resulting - lines will not contain any newlines. `graph_next_line()` returns 1 if the - resulting line contains the current commit, or 0 if this is merely a line - needed to adjust the graph before or after the current commit. This return - value can be used to determine where to print the commit summary information - alongside the graph output. - -Limitations ------------ - -* `graph_update()` must be called with commits in topological order. It should - not be called on a commit if it has already been invoked with an ancestor of - that commit, or the graph output will be incorrect. - -* `graph_update()` must be called on a contiguous group of commits. If - `graph_update()` is called on a particular commit, it should later be called - on all parents of that commit. Parents must not be skipped, or the graph - output will appear incorrect. -+ -`graph_update()` may be used on a pruned set of commits only if the parent list -has been rewritten so as to include only ancestors from the pruned set. - -* The graph API does not currently support reverse commit ordering. In - order to implement reverse ordering, the graphing API needs an - (efficient) mechanism to find the children of a commit. - -Sample usage ------------- - ------------- -struct commit *commit; -struct git_graph *graph = graph_init(opts); - -while ((commit = get_revision(opts)) != NULL) { - while (!graph_is_commit_finished(graph)) - { - struct strbuf sb; - int is_commit_line; - - strbuf_init(&sb, 0); - is_commit_line = graph_next_line(graph, &sb); - fputs(sb.buf, stdout); - - if (is_commit_line) - log_tree_commit(opts, commit); - else - putchar(opts->diffopt.line_termination); - } -} ------------- - -Sample output -------------- - -The following is an example of the output from the graph API. This output does -not include any commit summary information--callers are responsible for -outputting that information, if desired. - ------------- -* -* -* -|\ -* | -| | * -| \ \ -| \ \ -*-. \ \ -|\ \ \ \ -| | * | | -| | | | | * -| | | | | * -| | | | | * -| | | | | |\ -| | | | | | * -| * | | | | | -| | | | | * \ -| | | | | |\ | -| | | | * | | | -| | | | * | | | -* | | | | | | | -| |/ / / / / / -|/| / / / / / -* | | | | | | -|/ / / / / / -* | | | | | -| | | | | * -| | | | |/ -| | | | * ------------- diff --git a/graph.c b/graph.c index f53135485f..eab3af1dc7 100644 --- a/graph.c +++ b/graph.c @@ -34,6 +34,7 @@ static void graph_padding_line(struct git_graph *graph, struct strbuf *sb); * handle directly. It is assumed that this is the same file handle as the * file specified by the graph diff options. This is necessary so that * graph_show_strbuf can be called even with a NULL graph. + * If a NULL graph is supplied, the strbuf is printed as-is. */ static void graph_show_strbuf(struct git_graph *graph, FILE *file, diff --git a/graph.h b/graph.h index af623390b6..8313e293c7 100644 --- a/graph.h +++ b/graph.h @@ -2,6 +2,103 @@ #define GRAPH_H #include "diff.h" +/** + * The graph API is used to draw a text-based representation of the commit + * history. The API generates the graph in a line-by-line fashion. + * + * Calling sequence + * ---------------- + * + * - Create a `struct git_graph` by calling `graph_init()`. When using the + * revision walking API, this is done automatically by `setup_revisions()` if + * the '--graph' option is supplied. + * + * - Use the revision walking API to walk through a group of contiguous commits. + * The `get_revision()` function automatically calls `graph_update()` each time + * it is invoked. + * + * - For each commit, call `graph_next_line()` repeatedly, until + * `graph_is_commit_finished()` returns non-zero. Each call to + * `graph_next_line()` will output a single line of the graph. The resulting + * lines will not contain any newlines. `graph_next_line()` returns 1 if the + * resulting line contains the current commit, or 0 if this is merely a line + * needed to adjust the graph before or after the current commit. This return + * value can be used to determine where to print the commit summary information + * alongside the graph output. + * + * Limitations + * ----------- + * - Check the graph_update() function for its limitations. + * + * - The graph API does not currently support reverse commit ordering. In + * order to implement reverse ordering, the graphing API needs an + * (efficient) mechanism to find the children of a commit. + * + * Sample usage + * ------------ + * + * ------------ + * struct commit *commit; + * struct git_graph *graph = graph_init(opts); + * + * while ((commit = get_revision(opts)) != NULL) { + * while (!graph_is_commit_finished(graph)) + * { + * struct strbuf sb; + * int is_commit_line; + * + * strbuf_init(&sb, 0); + * is_commit_line = graph_next_line(graph, &sb); + * fputs(sb.buf, stdout); + * + * if (is_commit_line) + * log_tree_commit(opts, commit); + * else + * putchar(opts->diffopt.line_termination); + * } + * } + * ------------ + * Sample output + * ------------- + * + * The following is an example of the output from the graph API. This output does + * not include any commit summary information--callers are responsible for + * outputting that information, if desired. + * ------------ + * * + * * + * * + * |\ + * * | + * | | * + * | \ \ + * | \ \ + * *-. \ \ + * |\ \ \ \ + * | | * | | + * | | | | | * + * | | | | | * + * | | | | | * + * | | | | | |\ + * | | | | | | * + * | * | | | | | + * | | | | | * \ + * | | | | | |\ | + * | | | | * | | | + * | | | | * | | | + * * | | | | | | | + * | |/ / / / / / + * |/| / / / / / + * * | | | | | | + * |/ / / / / / + * * | | | | | + * | | | | | * + * | | | | |/ + * | | | | * + * ------------ + * + */ + /* A graph is a pointer to this opaque structure */ struct git_graph; @@ -50,6 +147,21 @@ struct git_graph *graph_init(struct rev_info *opt); * If graph_update() is called before graph_is_commit_finished() returns 1, * the next call to graph_next_line() will output an ellipsis ("...") * to indicate that a portion of the graph is missing. + * + * Limitations: + * ----------- + * + * - `graph_update()` must be called with commits in topological order. It should + * not be called on a commit if it has already been invoked with an ancestor of + * that commit, or the graph output will be incorrect. + * + * - `graph_update()` must be called on a contiguous group of commits. If + * `graph_update()` is called on a particular commit, it should later be called + * on all parents of that commit. Parents must not be skipped, or the graph + * output will appear incorrect. + * + * - `graph_update()` may be used on a pruned set of commits only if the parent list + * has been rewritten so as to include only ancestors from the pruned set. */ void graph_update(struct git_graph *graph, struct commit *commit); @@ -62,6 +174,10 @@ void graph_update(struct git_graph *graph, struct commit *commit); * for this commit. If 0 is returned, graph_next_line() may still be * called without calling graph_update(), and it will merely output * appropriate "vertical padding" in the graph. + * + * If `graph_update()` is called before all lines for the current commit have + * been printed, the next call to `graph_next_line()` will output an ellipsis, + * to indicate that a portion of the graph was omitted. */ int graph_is_commit_finished(struct git_graph const *graph); @@ -112,6 +228,7 @@ void graph_show_padding(struct git_graph *graph); /* * If the graph is non-NULL, print the rest of the history graph for this * commit to stdout. Does not print a terminating newline on the last line. + * Returns 1 if output was printed, and 0 if no output was necessary. */ int graph_show_remainder(struct git_graph *graph); @@ -121,6 +238,10 @@ int graph_show_remainder(struct git_graph *graph); * This is similar to graph_show_strbuf(), but it always prints the * remainder of the graph. * + * It is better than directly calling `graph_show_strbuf()` followed by + * `graph_show_remainder()` since it properly handles buffers that do not end in + * a terminating newline. + * * If the strbuf ends with a newline, the output printed by * graph_show_commit_msg() will end with a newline. If the strbuf is * missing a terminating newline (including if it is empty), the output From patchwork Wed Nov 6 09:59:31 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: John Passaro via GitGitGadget X-Patchwork-Id: 11229877 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 CAD5F1864 for ; Wed, 6 Nov 2019 09:59:56 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 9E909217F4 for ; Wed, 6 Nov 2019 09:59:56 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="qxG9OOFB" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731674AbfKFJ7z (ORCPT ); Wed, 6 Nov 2019 04:59:55 -0500 Received: from mail-wr1-f54.google.com ([209.85.221.54]:46427 "EHLO mail-wr1-f54.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731633AbfKFJ7z (ORCPT ); Wed, 6 Nov 2019 04:59:55 -0500 Received: by mail-wr1-f54.google.com with SMTP id b3so19197099wrs.13 for ; Wed, 06 Nov 2019 01:59:52 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=l+G+CT1y7qK/D1o75uyZKmNHTTdKCF7Is/TbxG8nHdQ=; b=qxG9OOFBIhugWSo1uCztPwSiyU2nH+BQqdiElKQv3Aap5wlqCbedfbuHsYZRxLF0zi wbo+qWE4KQpJacuy3pkIGad3wVGWvR71N2iQ3784Wb4ltt/b5GELkuwKaUpuzmVhlWJG ey+z6WQkVo/EF6s4Co6M4Wd44SNSB3d0TO40JVOuxTwmuaEKjqkO0ROzCiWwHBUyEcev pm278WWK4VQrFJX+XrhgynhZsget87wzK+N2VNAAvvq6piVWYHUCY/XPP9zexljFHYPT O3+yEOo9Garc5zQco/uw9vA/uoHt24/FNBeENxvWx6wB6zz3q4WVHaqkbjFrJHt/qf9X us1w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=l+G+CT1y7qK/D1o75uyZKmNHTTdKCF7Is/TbxG8nHdQ=; b=TLNqGrNPZNAxHarkCnQ4QDJynVo7wPGj+FEER8oBXG0iVvWTIeaNolIU+GCV50E8Dd E/Z/uTuLU51CZHv25TchD4/IUKpdIPln5j1XWJBM+A+HvfBzGgmt25Lqv/Rtt9WpzQ2y VZ+IfP8NyMY4R8pR53w7gSa1vn7lRkrVnEx9UE7+OdBcX9Sn1l7zCxUicXsi/eDk82Fb lmNHS3FVZdkit9ojKmjjiLXF+j2JjgQJFOBkWauOlSP5cKthmODuzCqI2JfEVXc0AM0N xClrDgPl/8A30Ef18eYox2mV9mdXQviUc6n3tBpdbnXwS8C53jQUFI80q00AIgy+5WFd 1LdA== X-Gm-Message-State: APjAAAUagfudztqKk8HEZoE6D14iisdjjkkiuFRHSHjflEMBteEWPBDw 3UgioXkHRzMhduKB3WO3hVQ4j6mp X-Google-Smtp-Source: APXvYqw1MRb8nB7u1x+zjGsDydldWVeiz9AdHj0oO1J0MfTKyihX7hNGZO6LD2FmawX5QZW58Hj0rQ== X-Received: by 2002:a5d:4d4a:: with SMTP id a10mr1883854wru.35.1573034391861; Wed, 06 Nov 2019 01:59:51 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id l18sm27262124wrn.48.2019.11.06.01.59.51 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 06 Nov 2019 01:59:51 -0800 (PST) Message-Id: In-Reply-To: References: From: "Heba Waly via GitGitGadget" Date: Wed, 06 Nov 2019 09:59:31 +0000 Subject: [PATCH v2 04/20] merge: move doc to ll-merge.h Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Heba Waly , Junio C Hamano , Heba Waly Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Heba Waly Move the related documentation from Documentation/technical/api-merge.txt to ll-merge.h as it's easier for the developers to find the usage information beside the code instead of looking for it in another doc file. Only the ll-merge related doc is removed from documentation/technical/api-merge.txt because this information will be redundant and it'll be hard to keep it up to date and synchronized with the documentation in ll-merge.h. Signed-off-by: Heba Waly --- Documentation/technical/api-merge.txt | 72 +------------------------- ll-merge.h | 73 ++++++++++++++++++++++++++- 2 files changed, 74 insertions(+), 71 deletions(-) diff --git a/Documentation/technical/api-merge.txt b/Documentation/technical/api-merge.txt index 9dc1bed768..487d4d83ff 100644 --- a/Documentation/technical/api-merge.txt +++ b/Documentation/technical/api-merge.txt @@ -28,77 +28,9 @@ and `diff.c` for examples. * `struct ll_merge_options` -This describes the set of options the calling program wants to affect -the operation of a low-level (single file) merge. Some options: - -`virtual_ancestor`:: - Behave as though this were part of a merge between common - ancestors in a recursive merge. - If a helper program is specified by the - `[merge ""] recursive` configuration, it will - be used (see linkgit:gitattributes[5]). - -`variant`:: - Resolve local conflicts automatically in favor - of one side or the other (as in 'git merge-file' - `--ours`/`--theirs`/`--union`). Can be `0`, - `XDL_MERGE_FAVOR_OURS`, `XDL_MERGE_FAVOR_THEIRS`, or - `XDL_MERGE_FAVOR_UNION`. - -`renormalize`:: - Resmudge and clean the "base", "theirs" and "ours" files - before merging. Use this when the merge is likely to have - overlapped with a change in smudge/clean or end-of-line - normalization rules. +Check ll-merge.h for details. Low-level (single file) merge ----------------------------- -`ll_merge`:: - - Perform a three-way single-file merge in core. This is - a thin wrapper around `xdl_merge` that takes the path and - any merge backend specified in `.gitattributes` or - `.git/info/attributes` into account. Returns 0 for a - clean merge. - -Calling sequence: - -* Prepare a `struct ll_merge_options` to record options. - If you have no special requests, skip this and pass `NULL` - as the `opts` parameter to use the default options. - -* Allocate an mmbuffer_t variable for the result. - -* Allocate and fill variables with the file's original content - and two modified versions (using `read_mmfile`, for example). - -* Call `ll_merge()`. - -* Read the merged content from `result_buf.ptr` and `result_buf.size`. - -* Release buffers when finished. A simple - `free(ancestor.ptr); free(ours.ptr); free(theirs.ptr); - free(result_buf.ptr);` will do. - -If the modifications do not merge cleanly, `ll_merge` will return a -nonzero value and `result_buf` will generally include a description of -the conflict bracketed by markers such as the traditional `<<<<<<<` -and `>>>>>>>`. - -The `ancestor_label`, `our_label`, and `their_label` parameters are -used to label the different sides of a conflict if the merge driver -supports this. - -Everything else ---------------- - -Talk about and merge_file(): - - - merge_trees() to merge with rename detection - - merge_recursive() for ancestor consolidation - - try_merge_command() for other strategies - - conflict format - - merge options - -(Daniel, Miklos, Stephan, JC) +Check ll-merge.h for details. diff --git a/ll-merge.h b/ll-merge.h index e78973dd55..dd8a775da7 100644 --- a/ll-merge.h +++ b/ll-merge.h @@ -7,16 +7,87 @@ #include "xdiff/xdiff.h" +/** + * + * Calling sequence: + * ---------------- + * + * - Prepare a `struct ll_merge_options` to record options. + * If you have no special requests, skip this and pass `NULL` + * as the `opts` parameter to use the default options. + * + * - Allocate an mmbuffer_t variable for the result. + * + * - Allocate and fill variables with the file's original content + * and two modified versions (using `read_mmfile`, for example). + * + * - Call `ll_merge()`. + * + * - Read the merged content from `result_buf.ptr` and `result_buf.size`. + * + * - Release buffers when finished. A simple + * `free(ancestor.ptr); free(ours.ptr); free(theirs.ptr); + * free(result_buf.ptr);` will do. + * + * If the modifications do not merge cleanly, `ll_merge` will return a + * nonzero value and `result_buf` will generally include a description of + * the conflict bracketed by markers such as the traditional `<<<<<<<` + * and `>>>>>>>`. + * + * The `ancestor_label`, `our_label`, and `their_label` parameters are + * used to label the different sides of a conflict if the merge driver + * supports this. + */ + + struct index_state; +/** + * This describes the set of options the calling program wants to affect + * the operation of a low-level (single file) merge. + */ struct ll_merge_options { + + /** + * Behave as though this were part of a merge between common ancestors in + * a recursive merge (merges of binary files may need to be handled + * differently in such cases, for example). If a helper program is + * specified by the `[merge ""] recursive` configuration, it will + * be used. + */ unsigned virtual_ancestor : 1; - unsigned variant : 2; /* favor ours, favor theirs, or union merge */ + + /** + * Resolve local conflicts automatically in favor of one side or the other + * (as in 'git merge-file' `--ours`/`--theirs`/`--union`). Can be `0`, + * `XDL_MERGE_FAVOR_OURS`, `XDL_MERGE_FAVOR_THEIRS`, + * or `XDL_MERGE_FAVOR_UNION`. + */ + unsigned variant : 2; + + /** + * Resmudge and clean the "base", "theirs" and "ours" files before merging. + * Use this when the merge is likely to have overlapped with a change in + * smudge/clean or end-of-line normalization rules. + */ unsigned renormalize : 1; + + /** + * Increase the length of conflict markers so that nested conflicts +  * can be differentiated. + */ unsigned extra_marker_size; + + /* Extra xpparam_t flags as defined in xdiff/xdiff.h. */ long xdl_opts; }; +/** + * Perform a three-way single-file merge in core. This is a thin wrapper + * around `xdl_merge` that takes the path and any merge backend specified in + * `.gitattributes` or `.git/info/attributes` into account. + * Returns 0 for a clean merge. + */ int ll_merge(mmbuffer_t *result_buf, const char *path, mmfile_t *ancestor, const char *ancestor_label, From patchwork Wed Nov 6 09:59:32 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Passaro via GitGitGadget X-Patchwork-Id: 11229879 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 615A0112B for ; Wed, 6 Nov 2019 09:59:57 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 362D5217F4 for ; Wed, 6 Nov 2019 09:59:57 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="ZXz2TOUC" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731680AbfKFJ74 (ORCPT ); Wed, 6 Nov 2019 04:59:56 -0500 Received: from mail-wr1-f42.google.com ([209.85.221.42]:46418 "EHLO mail-wr1-f42.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725856AbfKFJ7z (ORCPT ); Wed, 6 Nov 2019 04:59:55 -0500 Received: by mail-wr1-f42.google.com with SMTP id b3so19197156wrs.13 for ; Wed, 06 Nov 2019 01:59:53 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=xXawFyU7upXqvr/vbNOTWiN1EjDFS8qw9umHTjSIxS0=; b=ZXz2TOUCl5rZx4Sz1fpFPNidMLvCY1hibdMDyFFSkfv0C1Qc/cSPLxS9pEExLuSLv0 /z4eeOVjTd0BpJlSziXje68/Alu51FldLgctmixlfSLCb5K+gkDhrxiSrr+14EnrfJBk TdIDP3dLP668OnOb7bMsJMNN+gsmGivtBzisJbeeWDjzZgD2IFkxM9HKP+K8mTs2A1Rb h7fo7tJXrMmKXXgxH73dxruBbEYf9W6QTNzYSW/H70GLWd4/4PB2xZpD5qF43qxFeSko jpBNkhJyOjgod8uiDNBAEH4FE3E+abLqgnPCcv5VFKjNSD534fP08PZ5II17EbUwMpkS EG8Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=xXawFyU7upXqvr/vbNOTWiN1EjDFS8qw9umHTjSIxS0=; b=FJz0wMfXiC/6qGYSthiZAwlJHvOaO0gRE+OT85HRCqVVTIi6bE2esjRwAa4d0zsDZr Fz+rL/8R2F4HJzcNIEw5EtDMgDKxTIZFQaMTYMrRPLvlS5KwiYw1LGf3YNkxlajT5nRk Mx86lN0m/2/PNfSlKf0NNla/yFtQbTb4yYfQ0UkBvu/6v9Z0+GIxlr6V7apF2SwN0Jgw Jr7DBNFrmw17yCX6V07LafBf/IZ9JFEtrACPfYMOQvd5zegPA18iSZUGyGGkHOHLDp1T p/ShXPSaYb7FrhYCZaDnvD5bb3seqycnwloePvNAkPUP0F0PVMgJENNd5lvE99xdYdoi RoEw== X-Gm-Message-State: APjAAAWjxYcrBBM/0l8EPe1UkWu5rW4ioVyrgbIz98pxIiD+0kUlJd16 BCKb/Ln1YhFG7dExqu9XgJeBdpWJ X-Google-Smtp-Source: APXvYqzjN8jnXILNPzPSmKMRkfM+8VG51ytjnzB6wuUOA2xMut+eWWpElyMw/DzjABfBMTs83px5XQ== X-Received: by 2002:a5d:4dd2:: with SMTP id f18mr1743153wru.4.1573034392682; Wed, 06 Nov 2019 01:59:52 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id m13sm2266657wmc.41.2019.11.06.01.59.52 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 06 Nov 2019 01:59:52 -0800 (PST) Message-Id: In-Reply-To: References: From: "Heba Waly via GitGitGadget" Date: Wed, 06 Nov 2019 09:59:32 +0000 Subject: [PATCH v2 05/20] sha1-array: move doc to sha1-array.h Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Heba Waly , Junio C Hamano , Heba Waly Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Heba Waly Move the documentation from Documentation/technical/api-oid-array.txt to sha1-array.h as it's easier for the developers to find the usage information beside the code instead of looking for it in another doc file. Also documentation/technical/api-oid-array.txt is removed because the information it has is now redundant and it'll be hard to keep it up to date and synchronized with the documentation in the header file. Signed-off-by: Heba Waly --- Documentation/technical/api-oid-array.txt | 90 ----------------------- sha1-array.h | 80 ++++++++++++++++++++ 2 files changed, 80 insertions(+), 90 deletions(-) delete mode 100644 Documentation/technical/api-oid-array.txt diff --git a/Documentation/technical/api-oid-array.txt b/Documentation/technical/api-oid-array.txt deleted file mode 100644 index c97428c2c3..0000000000 --- a/Documentation/technical/api-oid-array.txt +++ /dev/null @@ -1,90 +0,0 @@ -oid-array API -============== - -The oid-array API provides storage and manipulation of sets of object -identifiers. The emphasis is on storage and processing efficiency, -making them suitable for large lists. Note that the ordering of items is -not preserved over some operations. - -Data Structures ---------------- - -`struct oid_array`:: - - A single array of object IDs. This should be initialized by - assignment from `OID_ARRAY_INIT`. The `oid` member contains - the actual data. The `nr` member contains the number of items in - the set. The `alloc` and `sorted` members are used internally, - and should not be needed by API callers. - -Functions ---------- - -`oid_array_append`:: - Add an item to the set. The object ID will be placed at the end of - the array (but note that some operations below may lose this - ordering). - -`oid_array_lookup`:: - Perform a binary search of the array for a specific object ID. - If found, returns the offset (in number of elements) of the - object ID. If not found, returns a negative integer. If the array - is not sorted, this function has the side effect of sorting it. - -`oid_array_clear`:: - Free all memory associated with the array and return it to the - initial, empty state. - -`oid_array_for_each`:: - Iterate over each element of the list, executing the callback - function for each one. Does not sort the list, so any custom - hash order is retained. If the callback returns a non-zero - value, the iteration ends immediately and the callback's - return is propagated; otherwise, 0 is returned. - -`oid_array_for_each_unique`:: - Iterate over each unique element of the list in sorted order, - but otherwise behave like `oid_array_for_each`. If the array - is not sorted, this function has the side effect of sorting - it. - -`oid_array_filter`:: - Apply the callback function `want` to each entry in the array, - retaining only the entries for which the function returns true. - Preserve the order of the entries that are retained. - -Examples --------- - ------------------------------------------ -int print_callback(const struct object_id *oid, - void *data) -{ - printf("%s\n", oid_to_hex(oid)); - return 0; /* always continue */ -} - -void some_func(void) -{ - struct sha1_array hashes = OID_ARRAY_INIT; - struct object_id oid; - - /* Read objects into our set */ - while (read_object_from_stdin(oid.hash)) - oid_array_append(&hashes, &oid); - - /* Check if some objects are in our set */ - while (read_object_from_stdin(oid.hash)) { - if (oid_array_lookup(&hashes, &oid) >= 0) - printf("it's in there!\n"); - - /* - * Print the unique set of objects. We could also have - * avoided adding duplicate objects in the first place, - * but we would end up re-sorting the array repeatedly. - * Instead, this will sort once and then skip duplicates - * in linear time. - */ - oid_array_for_each_unique(&hashes, print_callback, NULL); -} ------------------------------------------ diff --git a/sha1-array.h b/sha1-array.h index 55d016c4bf..dc1bca9c9a 100644 --- a/sha1-array.h +++ b/sha1-array.h @@ -1,6 +1,52 @@ #ifndef SHA1_ARRAY_H #define SHA1_ARRAY_H +/** + * The API provides storage and manipulation of sets of object identifiers. + * The emphasis is on storage and processing efficiency, making them suitable + * for large lists. Note that the ordering of items is not preserved over some + * operations. + * + * Examples + * -------- + * ----------------------------------------- + * int print_callback(const struct object_id *oid, + * void *data) + * { + * printf("%s\n", oid_to_hex(oid)); + * return 0; // always continue + * } + * + * void some_func(void) + * { + * struct sha1_array hashes = OID_ARRAY_INIT; + * struct object_id oid; + * + * // Read objects into our set + * while (read_object_from_stdin(oid.hash)) + * oid_array_append(&hashes, &oid); + * + * // Check if some objects are in our set + * while (read_object_from_stdin(oid.hash)) { + * if (oid_array_lookup(&hashes, &oid) >= 0) + * printf("it's in there!\n"); + * + * // Print the unique set of objects. We could also have + * // avoided adding duplicate objects in the first place, + * // but we would end up re-sorting the array repeatedly. + * // Instead, this will sort once and then skip duplicates + * // in linear time. + * + * oid_array_for_each_unique(&hashes, print_callback, NULL); + * } + */ + +/** + * A single array of object IDs. This should be initialized by assignment from + * `OID_ARRAY_INIT`. The `oid` member contains the actual data. The `nr` member + * contains the number of items in the set. The `alloc` and `sorted` members + * are used internally, and should not be needed by API callers. + */ struct oid_array { struct object_id *oid; int nr; @@ -10,18 +56,52 @@ struct oid_array { #define OID_ARRAY_INIT { NULL, 0, 0, 0 } +/** + * Add an item to the set. The object ID will be placed at the end of the array + * (but note that some operations below may lose this ordering). + */ void oid_array_append(struct oid_array *array, const struct object_id *oid); + +/** + * Perform a binary search of the array for a specific object ID. If found, + * returns the offset (in number of elements) of the object ID. If not found, + * returns a negative integer. If the array is not sorted, this function has + * the side effect of sorting it. + */ int oid_array_lookup(struct oid_array *array, const struct object_id *oid); + +/** + * Free all memory associated with the array and return it to the initial, + * empty state. + */ void oid_array_clear(struct oid_array *array); typedef int (*for_each_oid_fn)(const struct object_id *oid, void *data); +/** + * Iterate over each element of the list, executing the callback function for + * each one. Does not sort the list, so any custom hash order is retained. + * If the callback returns a non-zero value, the iteration ends immediately + * and the callback's return is propagated; otherwise, 0 is returned. + */ int oid_array_for_each(struct oid_array *array, for_each_oid_fn fn, void *data); + +/** + * Iterate over each unique element of the list in sorted order, but otherwise + * behave like `oid_array_for_each`. If the array is not sorted, this function + * has the side effect of sorting it. + */ int oid_array_for_each_unique(struct oid_array *array, for_each_oid_fn fn, void *data); + +/** + * Apply the callback function `want` to each entry in the array, retaining + * only the entries for which the function returns true. Preserve the order + * of the entries that are retained. + */ void oid_array_filter(struct oid_array *array, for_each_oid_fn want, void *cbdata); From patchwork Wed Nov 6 09:59:33 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Passaro via GitGitGadget X-Patchwork-Id: 11229881 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 94BE71864 for ; Wed, 6 Nov 2019 09:59:58 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 6962A217F4 for ; Wed, 6 Nov 2019 09:59:58 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="lTU5cDpO" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731685AbfKFJ75 (ORCPT ); Wed, 6 Nov 2019 04:59:57 -0500 Received: from mail-wr1-f50.google.com ([209.85.221.50]:44158 "EHLO mail-wr1-f50.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731647AbfKFJ74 (ORCPT ); Wed, 6 Nov 2019 04:59:56 -0500 Received: by mail-wr1-f50.google.com with SMTP id f2so16050768wrs.11 for ; Wed, 06 Nov 2019 01:59:54 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=12WZXDvSSSFUqF+tPHhMpooqo/fLyKCbw1DKsKakPTE=; b=lTU5cDpO66GBNmv9cipOFGdlUabclqtGVF6kzNUSh8QE0q/3GDwrWQCGjFZjIpLDre 4bBdM/2Rfr1nRT5KaZb15me8r7nK/A1CJ9GXjmpgZHvZZPHOraOIs4ilmQUqUbBmqZy/ MrbHdIIHbLIimwuv76+qfhQ8fzX7gXvF+LlTmjMKbpDalIbgMs/D8d2vWJWesWRwbjHz jXg10gUMC4GVGNxyTCScibgYKIRAYQZToj+tQrgvbs74dSy1kX2PeL56gCM3VMvXVY5L CwqM3lu1ezSDuCfHtPxdOELEvQG72/DVcmVZR3m9mapRffadNPZzcMx3eOSf1P5m2IMV vGSQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=12WZXDvSSSFUqF+tPHhMpooqo/fLyKCbw1DKsKakPTE=; b=PCX+t6LsKwbCNpqJMuc2SDIwAGPEuIwK749kBvsTv6BCS6tB9gHjSkPu26bxOGqmJB GiNCxfKuskEYhp4/gUO5dXc8zIRar4w3rveTCpgBlcO/I0Kk4ncAsWHOuMM0IERvZxQ2 rAbP+1bKQaBf7mcszhe7b/waj+eIRGzGjnvvWPfsMfyn46wy4lQSbf0V+4LA4brIPQ2X J8Fa4gIA6eRK/wThvH50MZ8/mj/XvBjdF2eXuOooGnTjZO767Wqtds7oGpCl9qfgsjXe qqzAO1fWg0fTyegbYvTYtazWl1HvL36ALKcEfxNWiyvN+ftAnDud3tmcHHa5pofpz99X rNMw== X-Gm-Message-State: APjAAAX1PHFBS52he8c9dbAMUOS2QuZMASFWOiQiuMc4FhavSyPg6Wz1 HIegx4LwFsxA7PyTYjnEkxyeQ/DL X-Google-Smtp-Source: APXvYqzVxErq60qcOERGuj4mS1mQd6nSb1mTV8By9zUwDJM2r8DTJ3fcB3Owbxg4HHgwOTlQoA/rkw== X-Received: by 2002:adf:e712:: with SMTP id c18mr1706227wrm.127.1573034393510; Wed, 06 Nov 2019 01:59:53 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id v9sm22226493wrs.95.2019.11.06.01.59.52 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 06 Nov 2019 01:59:52 -0800 (PST) Message-Id: In-Reply-To: References: From: "Heba Waly via GitGitGadget" Date: Wed, 06 Nov 2019 09:59:33 +0000 Subject: [PATCH v2 06/20] remote: move doc to remote.h and refspec.h Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Heba Waly , Junio C Hamano , Heba Waly Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Heba Waly Move the documentation from Documentation/technical/api-remote.txt to remote.h and refspec.h as it's easier for the developers to find the usage information beside the code instead of looking for it in another doc file. N.B. The doc for both push and fetch members of the remote struct aren't moved because they are out of date, as the members were changed from arrays of rspecs to struct refspec 2 years ago. Also documentation/technical/api-remote.txt is removed because the information it has is now redundant and it'll be hard to keep it up to date and synchronized with the documentation in the header file. Signed-off-by: Heba Waly --- Documentation/technical/api-remote.txt | 127 ------------------------- refspec.h | 16 ++++ remote.h | 57 ++++++++++- 3 files changed, 70 insertions(+), 130 deletions(-) delete mode 100644 Documentation/technical/api-remote.txt diff --git a/Documentation/technical/api-remote.txt b/Documentation/technical/api-remote.txt deleted file mode 100644 index f10941b2e8..0000000000 --- a/Documentation/technical/api-remote.txt +++ /dev/null @@ -1,127 +0,0 @@ -Remotes configuration API -========================= - -The API in remote.h gives access to the configuration related to -remotes. It handles all three configuration mechanisms historically -and currently used by Git, and presents the information in a uniform -fashion. Note that the code also handles plain URLs without any -configuration, giving them just the default information. - -struct remote -------------- - -`name`:: - - The user's nickname for the remote - -`url`:: - - An array of all of the url_nr URLs configured for the remote - -`pushurl`:: - - An array of all of the pushurl_nr push URLs configured for the remote - -`push`:: - - An array of refspecs configured for pushing, with - push_refspec being the literal strings, and push_refspec_nr - being the quantity. - -`fetch`:: - - An array of refspecs configured for fetching, with - fetch_refspec being the literal strings, and fetch_refspec_nr - being the quantity. - -`fetch_tags`:: - - The setting for whether to fetch tags (as a separate rule from - the configured refspecs); -1 means never to fetch tags, 0 - means to auto-follow tags based on the default heuristic, 1 - means to always auto-follow tags, and 2 means to fetch all - tags. - -`receivepack`, `uploadpack`:: - - The configured helper programs to run on the remote side, for - Git-native protocols. - -`http_proxy`:: - - The proxy to use for curl (http, https, ftp, etc.) URLs. - -`http_proxy_authmethod`:: - - The method used for authenticating against `http_proxy`. - -struct remotes can be found by name with remote_get(), and iterated -through with for_each_remote(). remote_get(NULL) will return the -default remote, given the current branch and configuration. - -struct refspec --------------- - -A struct refspec holds the parsed interpretation of a refspec. If it -will force updates (starts with a '+'), force is true. If it is a -pattern (sides end with '*') pattern is true. src and dest are the -two sides (including '*' characters if present); if there is only one -side, it is src, and dst is NULL; if sides exist but are empty (i.e., -the refspec either starts or ends with ':'), the corresponding side is -"". - -An array of strings can be parsed into an array of struct refspecs -using parse_fetch_refspec() or parse_push_refspec(). - -remote_find_tracking(), given a remote and a struct refspec with -either src or dst filled out, will fill out the other such that the -result is in the "fetch" specification for the remote (note that this -evaluates patterns and returns a single result). - -struct branch -------------- - -Note that this may end up moving to branch.h - -struct branch holds the configuration for a branch. It can be looked -up with branch_get(name) for "refs/heads/{name}", or with -branch_get(NULL) for HEAD. - -It contains: - -`name`:: - - The short name of the branch. - -`refname`:: - - The full path for the branch ref. - -`remote_name`:: - - The name of the remote listed in the configuration. - -`merge_name`:: - - An array of the "merge" lines in the configuration. - -`merge`:: - - An array of the struct refspecs used for the merge lines. That - is, merge[i]->dst is a local tracking ref which should be - merged into this branch by default. - -`merge_nr`:: - - The number of merge configurations - -branch_has_merge_config() returns true if the given branch has merge -configuration given. - -Other stuff ------------ - -There is other stuff in remote.h that is related, in general, to the -process of interacting with remotes. - -(Daniel Barkalow) diff --git a/refspec.h b/refspec.h index 9b6e64a824..3f2bd4aaa5 100644 --- a/refspec.h +++ b/refspec.h @@ -20,6 +20,22 @@ struct refspec_item { #define REFSPEC_INIT_FETCH { .fetch = REFSPEC_FETCH } #define REFSPEC_INIT_PUSH { .fetch = REFSPEC_PUSH } +/** + * A struct refspec holds the parsed interpretation of a refspec. If it will + * force updates (starts with a '+'), force is true. If it is a pattern + * (sides end with '*') pattern is true. src and dest are the two sides + * (including '*' characters if present); if there is only one side, it is src, + * and dst is NULL; if sides exist but are empty (i.e., the refspec either + * starts or ends with ':'), the corresponding side is "". + * + * An array of strings can be parsed into an array of struct refspecs using + * parse_fetch_refspec() or parse_push_refspec(). + * + * remote_find_tracking(), given a remote and a struct refspec with either src + * or dst filled out, will fill out the other such that the result is in the + * "fetch" specification for the remote (note that this evaluates patterns and + * returns a single result). + */ struct refspec { struct refspec_item *items; int alloc; diff --git a/remote.h b/remote.h index 0e1d2b245b..2277426199 100644 --- a/remote.h +++ b/remote.h @@ -6,6 +6,14 @@ #include "hashmap.h" #include "refspec.h" +/** + * The API gives access to the configuration related to remotes. It handles + * all three configuration mechanisms historically and currently used by Git, + * and presents the information in a uniform fashion. Note that the code also + * handles plain URLs without any configuration, giving them just the default + * information. + */ + enum { REMOTE_UNCONFIGURED = 0, REMOTE_CONFIG, @@ -16,16 +24,22 @@ enum { struct remote { struct hashmap_entry ent; + /* The user's nickname for the remote */ const char *name; + int origin, configured_in_repo; const char *foreign_vcs; + /* An array of all of the url_nr URLs configured for the remote */ const char **url; + int url_nr; int url_alloc; + /* An array of all of the pushurl_nr push URLs configured for the remote */ const char **pushurl; + int pushurl_nr; int pushurl_alloc; @@ -34,32 +48,47 @@ struct remote { struct refspec fetch; /* + * The setting for whether to fetch tags (as a separate rule from the + * configured refspecs); * -1 to never fetch tags * 0 to auto-follow tags on heuristic (default) * 1 to always auto-follow tags * 2 to always fetch tags */ int fetch_tags; + int skip_default_update; int mirror; int prune; int prune_tags; + /** + * The configured helper programs to run on the remote side, for + * Git-native protocols. + */ const char *receivepack; const char *uploadpack; - /* - * for curl remotes only - */ + /* The proxy to use for curl (http, https, ftp, etc.) URLs. */ char *http_proxy; + + /* The method used for authenticating against `http_proxy`. */ char *http_proxy_authmethod; }; +/** + * struct remotes can be found by name with remote_get(). + * remote_get(NULL) will return the default remote, given the current branch + * and configuration. + */ struct remote *remote_get(const char *name); + struct remote *pushremote_get(const char *name); int remote_is_configured(struct remote *remote, int in_repo); typedef int each_remote_fn(struct remote *remote, void *priv); + +/* iterate through struct remotes */ int for_each_remote(each_remote_fn fn, void *priv); int remote_has_url(struct remote *remote, const char *url); @@ -194,16 +223,36 @@ struct ref *get_remote_ref(const struct ref *remote_refs, const char *name); */ int remote_find_tracking(struct remote *remote, struct refspec_item *refspec); +/** + * struct branch holds the configuration for a branch. It can be looked up with + * branch_get(name) for "refs/heads/{name}", or with branch_get(NULL) for HEAD. + */ struct branch { + + /* The short name of the branch. */ const char *name; + + /* The full path for the branch ref. */ const char *refname; + /* The name of the remote listed in the configuration. */ const char *remote_name; + const char *pushremote_name; + /* An array of the "merge" lines in the configuration. */ const char **merge_name; + + /** + * An array of the struct refspecs used for the merge lines. That is, + * merge[i]->dst is a local tracking ref which should be merged into this + * branch by default. + */ struct refspec_item **merge; + + /* The number of merge configurations */ int merge_nr; + int merge_alloc; const char *push_tracking_ref; @@ -215,7 +264,9 @@ const char *pushremote_for_branch(struct branch *branch, int *explicit); const char *remote_ref_for_branch(struct branch *branch, int for_push, int *explicit); +/* returns true if the given branch has merge configuration given. */ int branch_has_merge_config(struct branch *branch); + int branch_merge_matches(struct branch *, int n, const char *); /** From patchwork Wed Nov 6 09:59:34 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Passaro via GitGitGadget X-Patchwork-Id: 11229889 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 885611864 for ; Wed, 6 Nov 2019 10:00:00 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 668F52173B for ; Wed, 6 Nov 2019 10:00:00 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="b+/bMPRt" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731724AbfKFJ77 (ORCPT ); Wed, 6 Nov 2019 04:59:59 -0500 Received: from mail-wm1-f47.google.com ([209.85.128.47]:38903 "EHLO mail-wm1-f47.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725856AbfKFJ76 (ORCPT ); Wed, 6 Nov 2019 04:59:58 -0500 Received: by mail-wm1-f47.google.com with SMTP id z19so2579519wmk.3 for ; Wed, 06 Nov 2019 01:59:55 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=bIQFN7Giyzj0Cp3ZhrwOhNDIUw+bJ062AZKqqcec2l0=; b=b+/bMPRtJiX91D7SOsYQltNtohrxUm3DaNFS6wg5xW+UbiqqgZ1InT8YZcmho4qCkE paukusb25YaQOirq2hoWp1NDmyR7OsYta/u2XLGXIBLIDgqUnsZn2XPJb7JgegQq5G6r /FYA3r3g79GyTTdgIhEhzHt+g37XH+C6qL2K172JMp2NFsYNLbOO0xQVD0nQCWpPyOLk RFiaQia8tZVX83zezENQ9o4a1YteEjGUWAJRw3wsuwh4FqgBSwyjM30a9RiNbxot08i6 5iwr1zRQtHvR2qouo+CMzVbVmXHDTvlplMBsAS6SxCtIDpm6tKtANWcBFNhMdWB3BL1e pe5w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=bIQFN7Giyzj0Cp3ZhrwOhNDIUw+bJ062AZKqqcec2l0=; b=mdhrX2NqsibYe+Nq5NS3RSzY8lfn4fRNFZs3Zjdk7f27W5AtBSTRtTKPiuacocenFV 4qalhP3TCrUj/kY52aIHWP6TOP/4W0NfB4ctprCgZYFtSztPp0vUmnyUwkmRi9W7zsj/ wBdJ6wDIWX0jLm37PtkxnEeeklp+s+Q4hhWudk3ImnWCdvLMnB7LI4tO6Vc8iCl1YE9Y b850oTCkUwj6LFSPwZbnOcQabdfjsMwkINUUyuAHtw8riLqJneWyNUNFSsdmM7p4b2mI 6TrYZEwM/tihzfTgWQEfnmolGMmF8Q/P+v+xoswne+MZCAwNrh/rqtCL8BkCOTeG54Ix nkwg== X-Gm-Message-State: APjAAAVyXQjrOeXv8EzdjJL0e4SRilS1Ffg7fhmB1IZqvZ8TzcHREP6R Hna3Q66IL08OL8x/AiIbOECRNzM2 X-Google-Smtp-Source: APXvYqxqE1fmqrdc3/7RGi24+i4QxnfygwJCrfxNVrYU3UpyDpRX02CaSpA8nESlVqkZzcK0/WI9KQ== X-Received: by 2002:a1c:a942:: with SMTP id s63mr1599727wme.5.1573034394154; Wed, 06 Nov 2019 01:59:54 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id d2sm2249792wmd.2.2019.11.06.01.59.53 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 06 Nov 2019 01:59:53 -0800 (PST) Message-Id: <24d0765df9891560bb14d127832292abaae5a9bf.1573034387.git.gitgitgadget@gmail.com> In-Reply-To: References: From: "Heba Waly via GitGitGadget" Date: Wed, 06 Nov 2019 09:59:34 +0000 Subject: [PATCH v2 07/20] refs: move doc to refs.h Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Heba Waly , Junio C Hamano , Heba Waly Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Heba Waly Move the documentation from Documentation/technical/api-ref-iteration.txt to refs.h as it's easier for the developers to find the usage information beside the code instead of looking for it in another doc file. Also documentation/technical/api-ref-iteration.txt is removed because the information it has is now redundant and it'll be hard to keep it up to date and synchronized with the documentation in the header file. Signed-off-by: Heba Waly --- Documentation/technical/api-ref-iteration.txt | 78 ------------------- refs.h | 51 ++++++++++++ 2 files changed, 51 insertions(+), 78 deletions(-) delete mode 100644 Documentation/technical/api-ref-iteration.txt diff --git a/Documentation/technical/api-ref-iteration.txt b/Documentation/technical/api-ref-iteration.txt deleted file mode 100644 index ad9d019ff9..0000000000 --- a/Documentation/technical/api-ref-iteration.txt +++ /dev/null @@ -1,78 +0,0 @@ -ref iteration API -================= - - -Iteration of refs is done by using an iterate function which will call a -callback function for every ref. The callback function has this -signature: - - int handle_one_ref(const char *refname, const struct object_id *oid, - int flags, void *cb_data); - -There are different kinds of iterate functions which all take a -callback of this type. The callback is then called for each found ref -until the callback returns nonzero. The returned value is then also -returned by the iterate function. - -Iteration functions -------------------- - -* `head_ref()` just iterates the head ref. - -* `for_each_ref()` iterates all refs. - -* `for_each_ref_in()` iterates all refs which have a defined prefix and - strips that prefix from the passed variable refname. - -* `for_each_tag_ref()`, `for_each_branch_ref()`, `for_each_remote_ref()`, - `for_each_replace_ref()` iterate refs from the respective area. - -* `for_each_glob_ref()` iterates all refs that match the specified glob - pattern. - -* `for_each_glob_ref_in()` the previous and `for_each_ref_in()` combined. - -* Use `refs_` API for accessing submodules. The submodule ref store could - be obtained with `get_submodule_ref_store()`. - -* `for_each_rawref()` can be used to learn about broken ref and symref. - -* `for_each_reflog()` iterates each reflog file. - -Submodules ----------- - -If you want to iterate the refs of a submodule you first need to add the -submodules object database. You can do this by a code-snippet like -this: - - const char *path = "path/to/submodule" - if (add_submodule_odb(path)) - die("Error submodule '%s' not populated.", path); - -`add_submodule_odb()` will return zero on success. If you -do not do this you will get an error for each ref that it does not point -to a valid object. - -Note: As a side-effect of this you cannot safely assume that all -objects you lookup are available in superproject. All submodule objects -will be available the same way as the superprojects objects. - -Example: --------- - ----- -static int handle_remote_ref(const char *refname, - const unsigned char *sha1, int flags, void *cb_data) -{ - struct strbuf *output = cb_data; - strbuf_addf(output, "%s\n", refname); - return 0; -} - -... - - struct strbuf output = STRBUF_INIT; - for_each_remote_ref(handle_remote_ref, &output); - printf("%s", output.buf); ----- diff --git a/refs.h b/refs.h index 730d05ad91..545029c6d8 100644 --- a/refs.h +++ b/refs.h @@ -310,19 +310,35 @@ int refs_for_each_branch_ref(struct ref_store *refs, int refs_for_each_remote_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data); +/* just iterates the head ref. */ int head_ref(each_ref_fn fn, void *cb_data); + +/* iterates all refs. */ int for_each_ref(each_ref_fn fn, void *cb_data); + +/** + * iterates all refs which have a defined prefix and strips that prefix from + * the passed variable refname. + */ int for_each_ref_in(const char *prefix, each_ref_fn fn, void *cb_data); + int refs_for_each_fullref_in(struct ref_store *refs, const char *prefix, each_ref_fn fn, void *cb_data, unsigned int broken); int for_each_fullref_in(const char *prefix, each_ref_fn fn, void *cb_data, unsigned int broken); + +/** + * iterate refs from the respective area. + */ int for_each_tag_ref(each_ref_fn fn, void *cb_data); int for_each_branch_ref(each_ref_fn fn, void *cb_data); int for_each_remote_ref(each_ref_fn fn, void *cb_data); int for_each_replace_ref(struct repository *r, each_repo_ref_fn fn, void *cb_data); + +/* iterates all refs that match the specified glob pattern. */ int for_each_glob_ref(each_ref_fn fn, const char *pattern, void *cb_data); + int for_each_glob_ref_in(each_ref_fn fn, const char *pattern, const char *prefix, void *cb_data); @@ -791,6 +807,41 @@ int reflog_expire(const char *refname, const struct object_id *oid, int ref_storage_backend_exists(const char *name); struct ref_store *get_main_ref_store(struct repository *r); + +/** + * Submodules + * ---------- + * + * If you want to iterate the refs of a submodule you first need to add the + * submodules object database. You can do this by a code-snippet like + * this: + * + * const char *path = "path/to/submodule" + * if (add_submodule_odb(path)) + * die("Error submodule '%s' not populated.", path); + * + * `add_submodule_odb()` will return zero on success. If you + * do not do this you will get an error for each ref that it does not point + * to a valid object. + * + * Note: As a side-effect of this you cannot safely assume that all + * objects you lookup are available in superproject. All submodule objects + * will be available the same way as the superprojects objects. + * + * Example: + * -------- + * + * ---- + * static int handle_remote_ref(const char *refname, + * const unsigned char *sha1, int flags, void *cb_data) + * { + * struct strbuf *output = cb_data; + * strbuf_addf(output, "%s\n", refname); + * return 0; + * } + * + */ + /* * Return the ref_store instance for the specified submodule. For the * main repository, use submodule==NULL; such a call cannot fail. For From patchwork Wed Nov 6 09:59:35 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Passaro via GitGitGadget X-Patchwork-Id: 11229891 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 B25BA112B for ; Wed, 6 Nov 2019 10:00:02 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 85195217F4 for ; Wed, 6 Nov 2019 10:00:02 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="a3kCbdMd" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731176AbfKFJ76 (ORCPT ); Wed, 6 Nov 2019 04:59:58 -0500 Received: from mail-wm1-f42.google.com ([209.85.128.42]:55902 "EHLO mail-wm1-f42.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731672AbfKFJ75 (ORCPT ); Wed, 6 Nov 2019 04:59:57 -0500 Received: by mail-wm1-f42.google.com with SMTP id m17so2582691wmi.5 for ; Wed, 06 Nov 2019 01:59:55 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=CIlb7vhgvVx3vjpkNksrPt/9jqhoDqOBOGxQUnA8eKA=; b=a3kCbdMdel2E++WLDThR3rKHbFxfymjJ1E9kZgvGj1ojHTyJZc7CRLyGCf+NXk/EsG toNradz0FTHA2uY968VgklwXTRWiw+1dvSH0o1gS7j/pZvtXhpXAPTKIESaKb5soU+0z eNUsO/tqk0L8PvX2TFV8Uvj2ydbx93702G0MFBhREjjVSMsuDSoyiYKGgoV6I+3D/Hbs lw2ZkOzKOW7oNmol6fFiMCzKvCmmr+pLIxMV1NIwmp/Njzeu/DFz1ZJCgY/GfQoxhpqL ye2JFusFdbnFZTpsucKLnRkxH93Lh65yav28/dHcG54pPnl4a2JPdE9GhBPdNZcQtReb BcIg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=CIlb7vhgvVx3vjpkNksrPt/9jqhoDqOBOGxQUnA8eKA=; b=XwSu3UOCKB4ZZajwAbDsHIaHSb8uUrSb7GMlW065rxZFM3zd+vNg5d+VtEoaapjCHH 8WAK/ouzX8BIy6XAs4aP6p3e05CLlR2eO3AtwDNkbXEwFRdAalrFPfmIfAxZusgp4HnN O6cJEhOotBGHju1SYwCqMuYJ/5PcckqoaozUmByOdzrX5ZwEZIdoY1AdHFucgHu8K1pm vLgLab8jpOxqJPF1Qa9ez09iEMnznd90IEt6PvXcwy2Lk5MpZgpFaHa6rUegSHgPcVU9 NMDyX7i2iEPHleflmlzqDv3E0MRb/dbd+k5PAPxfi3z/sQr114Qvbgtod6OYGpgTpMCY dYKw== X-Gm-Message-State: APjAAAV1bRnLMdylwwWhC9UkTHXPHd8fnQKWB8k6CO8TPbzO6RdT1iEJ VFGfTKspYhAx3KBqBXUMn7rYKIIc X-Google-Smtp-Source: APXvYqwNvTWPkfppZirpbsNYXmqfQuHgAjH6O8lwVcad5JZldvJE+d4sJ9nezyjzt6f55BkDe2AXMA== X-Received: by 2002:a7b:c94f:: with SMTP id i15mr1723399wml.31.1573034394738; Wed, 06 Nov 2019 01:59:54 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id 11sm2279253wmb.34.2019.11.06.01.59.54 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 06 Nov 2019 01:59:54 -0800 (PST) Message-Id: <4ea49f76c7ffe662aa593830f5e70303a4f30dc4.1573034387.git.gitgitgadget@gmail.com> In-Reply-To: References: From: "Heba Waly via GitGitGadget" Date: Wed, 06 Nov 2019 09:59:35 +0000 Subject: [PATCH v2 08/20] attr: move doc to attr.h Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Heba Waly , Junio C Hamano , Heba Waly Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Heba Waly Move the documentation from Documentation/technical/api-gitattributes.txt to attr.h as it's easier for the developers to find the usage information beside the code instead of looking for it in another doc file. Also documentation/technical/api-gitattributes.txt is removed because the information it has is now redundant and it'll be hard to keep it up to date and synchronized with the documentation in the header file. Signed-off-by: Heba Waly --- Documentation/technical/api-gitattributes.txt | 154 ------------------ attr.h | 141 +++++++++++++++- 2 files changed, 134 insertions(+), 161 deletions(-) delete mode 100644 Documentation/technical/api-gitattributes.txt diff --git a/Documentation/technical/api-gitattributes.txt b/Documentation/technical/api-gitattributes.txt deleted file mode 100644 index 45f0df600f..0000000000 --- a/Documentation/technical/api-gitattributes.txt +++ /dev/null @@ -1,154 +0,0 @@ -gitattributes API -================= - -gitattributes mechanism gives a uniform way to associate various -attributes to set of paths. - - -Data Structure --------------- - -`struct git_attr`:: - - An attribute is an opaque object that is identified by its name. - Pass the name to `git_attr()` function to obtain the object of - this type. The internal representation of this structure is - of no interest to the calling programs. The name of the - attribute can be retrieved by calling `git_attr_name()`. - -`struct attr_check_item`:: - - This structure represents one attribute and its value. - -`struct attr_check`:: - - This structure represents a collection of `attr_check_item`. - It is passed to `git_check_attr()` function, specifying the - attributes to check, and receives their values. - - -Attribute Values ----------------- - -An attribute for a path can be in one of four states: Set, Unset, -Unspecified or set to a string, and `.value` member of `struct -attr_check_item` records it. There are three macros to check these: - -`ATTR_TRUE()`:: - - Returns true if the attribute is Set for the path. - -`ATTR_FALSE()`:: - - Returns true if the attribute is Unset for the path. - -`ATTR_UNSET()`:: - - Returns true if the attribute is Unspecified for the path. - -If none of the above returns true, `.value` member points at a string -value of the attribute for the path. - - -Querying Specific Attributes ----------------------------- - -* Prepare `struct attr_check` using attr_check_initl() - function, enumerating the names of attributes whose values you are - interested in, terminated with a NULL pointer. Alternatively, an - empty `struct attr_check` can be prepared by calling - `attr_check_alloc()` function and then attributes you want to - ask about can be added to it with `attr_check_append()` - function. - -* Call `git_check_attr()` to check the attributes for the path. - -* Inspect `attr_check` structure to see how each of the - attribute in the array is defined for the path. - - -Example -------- - -To see how attributes "crlf" and "ident" are set for different paths. - -. Prepare a `struct attr_check` with two elements (because - we are checking two attributes): - ------------- -static struct attr_check *check; -static void setup_check(void) -{ - if (check) - return; /* already done */ - check = attr_check_initl("crlf", "ident", NULL); -} ------------- - -. Call `git_check_attr()` with the prepared `struct attr_check`: - ------------- - const char *path; - - setup_check(); - git_check_attr(path, check); ------------- - -. Act on `.value` member of the result, left in `check->items[]`: - ------------- - const char *value = check->items[0].value; - - if (ATTR_TRUE(value)) { - The attribute is Set, by listing only the name of the - attribute in the gitattributes file for the path. - } else if (ATTR_FALSE(value)) { - The attribute is Unset, by listing the name of the - attribute prefixed with a dash - for the path. - } else if (ATTR_UNSET(value)) { - The attribute is neither set nor unset for the path. - } else if (!strcmp(value, "input")) { - If none of ATTR_TRUE(), ATTR_FALSE(), or ATTR_UNSET() is - true, the value is a string set in the gitattributes - file for the path by saying "attr=value". - } else if (... other check using value as string ...) { - ... - } ------------- - -To see how attributes in argv[] are set for different paths, only -the first step in the above would be different. - ------------- -static struct attr_check *check; -static void setup_check(const char **argv) -{ - check = attr_check_alloc(); - while (*argv) { - struct git_attr *attr = git_attr(*argv); - attr_check_append(check, attr); - argv++; - } -} ------------- - - -Querying All Attributes ------------------------ - -To get the values of all attributes associated with a file: - -* Prepare an empty `attr_check` structure by calling - `attr_check_alloc()`. - -* Call `git_all_attrs()`, which populates the `attr_check` - with the attributes attached to the path. - -* Iterate over the `attr_check.items[]` array to examine - the attribute names and values. The name of the attribute - described by an `attr_check.items[]` object can be retrieved via - `git_attr_name(check->items[i].attr)`. (Please note that no items - will be returned for unset attributes, so `ATTR_UNSET()` will return - false for all returned `attr_check.items[]` objects.) - -* Free the `attr_check` struct by calling `attr_check_free()`. diff --git a/attr.h b/attr.h index b0378bfe5f..404548f028 100644 --- a/attr.h +++ b/attr.h @@ -1,9 +1,121 @@ #ifndef ATTR_H #define ATTR_H +/** + * gitattributes mechanism gives a uniform way to associate various attributes + * to set of paths. + * + * + * Querying Specific Attributes + * ---------------------------- + * + * - Prepare `struct attr_check` using attr_check_initl() function, enumerating + * the names of attributes whose values you are interested in, terminated with + * a NULL pointer. Alternatively, an empty `struct attr_check` can be + * prepared by calling `attr_check_alloc()` function and then attributes you + * want to ask about can be added to it with `attr_check_append()` function. + * + * - Call `git_check_attr()` to check the attributes for the path. + * + * - Inspect `attr_check` structure to see how each of the attribute in the + * array is defined for the path. + * + * + * Example + * ------- + * + * To see how attributes "crlf" and "ident" are set for different paths. + * + * - Prepare a `struct attr_check` with two elements (because we are checking + * two attributes): + * + * ------------ + * static struct attr_check *check; + * static void setup_check(void) + * { + * if (check) + * return; // already done + * check = attr_check_initl("crlf", "ident", NULL); + * } + * ------------ + * + * - Call `git_check_attr()` with the prepared `struct attr_check`: + * + * ------------ + * const char *path; + * + * setup_check(); + * git_check_attr(path, check); + * ------------ + * + * - Act on `.value` member of the result, left in `check->items[]`: + * + * ------------ + * const char *value = check->items[0].value; + * + * if (ATTR_TRUE(value)) { + * The attribute is Set, by listing only the name of the + * attribute in the gitattributes file for the path. + * } else if (ATTR_FALSE(value)) { + * The attribute is Unset, by listing the name of the + * attribute prefixed with a dash - for the path. + * } else if (ATTR_UNSET(value)) { + * The attribute is neither set nor unset for the path. + * } else if (!strcmp(value, "input")) { + * If none of ATTR_TRUE(), ATTR_FALSE(), or ATTR_UNSET() is + * true, the value is a string set in the gitattributes + * file for the path by saying "attr=value". + * } else if (... other check using value as string ...) { + * ... + * } + * ------------ + * + * To see how attributes in argv[] are set for different paths, only + * the first step in the above would be different. + * + * ------------ + * static struct attr_check *check; + * static void setup_check(const char **argv) + * { + * check = attr_check_alloc(); + * while (*argv) { + * struct git_attr *attr = git_attr(*argv); + * attr_check_append(check, attr); + * argv++; + * } + * } + * ------------ + * + * + * Querying All Attributes + * ----------------------- + * + * To get the values of all attributes associated with a file: + * + * - Prepare an empty `attr_check` structure by calling `attr_check_alloc()`. + * + * - Call `git_all_attrs()`, which populates the `attr_check` with the + * attributes attached to the path. + * + * - Iterate over the `attr_check.items[]` array to examine the attribute + * names and values. The name of the attribute described by an + * `attr_check.items[]` object can be retrieved via + * `git_attr_name(check->items[i].attr)`. (Please note that no items will be + * returned for unset attributes, so `ATTR_UNSET()` will return false for all + * returned `attr_check.items[]` objects.) + * + * - Free the `attr_check` struct by calling `attr_check_free()`. + */ + struct index_state; -/* An attribute is a pointer to this opaque structure */ +/** + * An attribute is an opaque object that is identified by its name. Pass the + * name to `git_attr()` function to obtain the object of this type. + * The internal representation of this structure is of no interest to the + * calling programs. The name of the attribute can be retrieved by calling + * `git_attr_name()`. + */ struct git_attr; /* opaque structures used internally for attribute collection */ @@ -21,21 +133,36 @@ const struct git_attr *git_attr(const char *); extern const char git_attr__true[]; extern const char git_attr__false[]; -/* For public to check git_attr_check results */ +/** + * Attribute Values + * ---------------- + * + * An attribute for a path can be in one of four states: Set, Unset, Unspecified + * or set to a string, and `.value` member of `struct attr_check_item` records + * it. The three macros check these, if none of them returns true, `.value` + * member points at a string value of the attribute for the path. + */ + +/* Returns true if the attribute is Set for the path. */ #define ATTR_TRUE(v) ((v) == git_attr__true) + +/* Returns true if the attribute is Unset for the path. */ #define ATTR_FALSE(v) ((v) == git_attr__false) + +/* Returns true if the attribute is Unspecified for the path. */ #define ATTR_UNSET(v) ((v) == NULL) -/* - * Send one or more git_attr_check to git_check_attrs(), and - * each 'value' member tells what its value is. - * Unset one is returned as NULL. - */ +/* This structure represents one attribute and its value. */ struct attr_check_item { const struct git_attr *attr; const char *value; }; +/** + * This structure represents a collection of `attr_check_item`. It is passed to + * `git_check_attr()` function, specifying the attributes to check, and + * receives their values. + */ struct attr_check { int nr; int alloc; From patchwork Wed Nov 6 09:59:36 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Passaro via GitGitGadget X-Patchwork-Id: 11229885 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 AA2321864 for ; Wed, 6 Nov 2019 09:59:59 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 7E1B72173B for ; Wed, 6 Nov 2019 09:59:59 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="GjnDiuwX" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731712AbfKFJ76 (ORCPT ); Wed, 6 Nov 2019 04:59:58 -0500 Received: from mail-wr1-f51.google.com ([209.85.221.51]:43638 "EHLO mail-wr1-f51.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731633AbfKFJ75 (ORCPT ); Wed, 6 Nov 2019 04:59:57 -0500 Received: by mail-wr1-f51.google.com with SMTP id n1so24961820wra.10 for ; Wed, 06 Nov 2019 01:59:56 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=/r3LV3ig26h2jE3K96c9klAmXlWRTCzKv5xNU6JF0nQ=; b=GjnDiuwXlla6PCIaFaATl9ATfc70CFeXjNMSmhNkvvB1J6fxYXff++QYPnSpdkhc2E 7V8sPys7QR6+go1nyLXRVkobtxts3mmZ8/qFEdjtWmd2+BLw4Z6keh7E5qGIGCOsRxw3 J2+sR0qTb12MEBVARrX1xW7qnNO3oHxI5fj7Vn4P6IvvNKaX8PI8MLH7NGefA4nvLXK+ 68TOrq0D7ZvBJY96JljxL+uTX4iJa0QWJmxGdN18UVo8pQxyNQS3lXzrd/9XkqXp9nOd 1B1YNCQt85dTFt5/5C2+N2zfFe5rl/dtmrLA4kIQDquWIH/0YpwdOjlCpUtiKfphq5u2 1Mqw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=/r3LV3ig26h2jE3K96c9klAmXlWRTCzKv5xNU6JF0nQ=; b=sSM6egg4NmxtTHNOn3MzLYOYazAVrgYRbDslGtbcLgm+d5GsYmn/cQMX5W+MtfosM0 rkxqLElGOUVqRqZ7/bgYpLoQYrSpEHuzvDWwFV/RSqLXptGScHTLslWIy0NKwk9E21HW /Am7746AltcVDBLUIKd9nMGkjCwRHd/oZfmARSnVFlGwQba5TzznyVaFzG6fugE5tcnN x+knjhdEeufAmaLGx2t+9JHQVDLykzEJMIB6F+/rvRKCcHjx38UQXJZWW5Zfej6bX0u8 Zk1wphmC1GpltJY8abQGu4eeldctx676EoE4uuXzAzaPINJWzn7wAv1ZOkvUzxMi2EnV gXYw== X-Gm-Message-State: APjAAAWb+hlurJPSFwv7OMaRO9LIObdp0TvBNLMTBxRMhOmSXfxP51lh XSoJK3EjCxh3Pu/VuuXkLaxlAvSd X-Google-Smtp-Source: APXvYqxK3PUtQRuaxWV9iYmtxckYtQS54yRsYffgwMdi8VY1iqZ9Wld5h6iophfskeK6mgQRWh5D/g== X-Received: by 2002:adf:fec7:: with SMTP id q7mr1804360wrs.267.1573034395331; Wed, 06 Nov 2019 01:59:55 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id w4sm2225537wmk.29.2019.11.06.01.59.54 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 06 Nov 2019 01:59:54 -0800 (PST) Message-Id: In-Reply-To: References: From: "Heba Waly via GitGitGadget" Date: Wed, 06 Nov 2019 09:59:36 +0000 Subject: [PATCH v2 09/20] revision: move doc to revision.h Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Heba Waly , Junio C Hamano , Heba Waly Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Heba Waly Move the documentation from Documentation/technical/api-revision-walking.txt to revision.h as it's easier for the developers to find the usage information beside the code instead of looking for it in another doc file. Also documentation/technical/api-revision-walking.txt is removed because the information it has is now redundant and it'll be hard to keep it up to date and synchronized with the documentation in the header file. Signed-off-by: Heba Waly --- .../technical/api-revision-walking.txt | 72 ------------------- revision.h | 59 +++++++++++++++ 2 files changed, 59 insertions(+), 72 deletions(-) delete mode 100644 Documentation/technical/api-revision-walking.txt diff --git a/Documentation/technical/api-revision-walking.txt b/Documentation/technical/api-revision-walking.txt deleted file mode 100644 index 03f9ea6ac4..0000000000 --- a/Documentation/technical/api-revision-walking.txt +++ /dev/null @@ -1,72 +0,0 @@ -revision walking API -==================== - -The revision walking API offers functions to build a list of revisions -and then iterate over that list. - -Calling sequence ----------------- - -The walking API has a given calling sequence: first you need to -initialize a rev_info structure, then add revisions to control what kind -of revision list do you want to get, finally you can iterate over the -revision list. - -Functions ---------- - -`repo_init_revisions`:: - - Initialize a rev_info structure with default values. The third - parameter may be NULL or can be prefix path, and then the `.prefix` - variable will be set to it. This is typically the first function you - want to call when you want to deal with a revision list. After calling - this function, you are free to customize options, like set - `.ignore_merges` to 0 if you don't want to ignore merges, and so on. See - `revision.h` for a complete list of available options. - -`add_pending_object`:: - - This function can be used if you want to add commit objects as revision - information. You can use the `UNINTERESTING` object flag to indicate if - you want to include or exclude the given commit (and commits reachable - from the given commit) from the revision list. -+ -NOTE: If you have the commits as a string list then you probably want to -use setup_revisions(), instead of parsing each string and using this -function. - -`setup_revisions`:: - - Parse revision information, filling in the `rev_info` structure, and - removing the used arguments from the argument list. Returns the number - of arguments left that weren't recognized, which are also moved to the - head of the argument list. The last parameter is used in case no - parameter given by the first two arguments. - -`prepare_revision_walk`:: - - Prepares the rev_info structure for a walk. You should check if it - returns any error (non-zero return code) and if it does not, you can - start using get_revision() to do the iteration. - -`get_revision`:: - - Takes a pointer to a `rev_info` structure and iterates over it, - returning a `struct commit *` each time you call it. The end of the - revision list is indicated by returning a NULL pointer. - -`reset_revision_walk`:: - - Reset the flags used by the revision walking api. You can use - this to do multiple sequential revision walks. - -Data structures ---------------- - -Talk about , things like: - -* two diff_options, one for path limiting, another for output; -* remaining functions; - -(Linus, JC, Dscho) diff --git a/revision.h b/revision.h index 4134dc6029..983ffc0f12 100644 --- a/revision.h +++ b/revision.h @@ -9,6 +9,19 @@ #include "diff.h" #include "commit-slab-decl.h" +/** + * The revision walking API offers functions to build a list of revisions + * and then iterate over that list. + * + * Calling sequence + * ---------------- + * + * The walking API has a given calling sequence: first you need to initialize + * a rev_info structure, then add revisions to control what kind of revision + * list do you want to get, finally you can iterate over the revision list. + * + */ + /* Remember to update object flag allocation in object.h */ #define SEEN (1u<<0) #define UNINTERESTING (1u<<1) @@ -306,11 +319,29 @@ struct setup_revision_opt { #ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS #define init_revisions(revs, prefix) repo_init_revisions(the_repository, revs, prefix) #endif + +/** + * Initialize a rev_info structure with default values. The third parameter may + * be NULL or can be prefix path, and then the `.prefix` variable will be set + * to it. This is typically the first function you want to call when you want + * to deal with a revision list. After calling this function, you are free to + * customize options, like set `.ignore_merges` to 0 if you don't want to + * ignore merges, and so on. + */ void repo_init_revisions(struct repository *r, struct rev_info *revs, const char *prefix); + +/** + * Parse revision information, filling in the `rev_info` structure, and + * removing the used arguments from the argument list. Returns the number + * of arguments left that weren't recognized, which are also moved to the + * head of the argument list. The last parameter is used in case no + * parameter given by the first two arguments. + */ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct setup_revision_opt *); + void parse_revision_opt(struct rev_info *revs, struct parse_opt_ctx_t *ctx, const struct option *options, const char * const usagestr[]); @@ -319,9 +350,26 @@ void parse_revision_opt(struct rev_info *revs, struct parse_opt_ctx_t *ctx, int handle_revision_arg(const char *arg, struct rev_info *revs, int flags, unsigned revarg_opt); +/** + * Reset the flags used by the revision walking api. You can use this to do + * multiple sequential revision walks. + */ void reset_revision_walk(void); + +/** + * Prepares the rev_info structure for a walk. You should check if it returns + * any error (non-zero return code) and if it does not, you can start using + * get_revision() to do the iteration. + */ int prepare_revision_walk(struct rev_info *revs); + +/** + * Takes a pointer to a `rev_info` structure and iterates over it, returning a + * `struct commit *` each time you call it. The end of the revision list is + * indicated by returning a NULL pointer. + */ struct commit *get_revision(struct rev_info *revs); + char *get_revision_mark(const struct rev_info *revs, const struct commit *commit); void put_revision_mark(const struct rev_info *revs, @@ -333,8 +381,19 @@ void mark_trees_uninteresting_sparse(struct repository *r, struct oidset *trees) void show_object_with_name(FILE *, struct object *, const char *); +/** + * This function can be used if you want to add commit objects as revision + * information. You can use the `UNINTERESTING` object flag to indicate if + * you want to include or exclude the given commit (and commits reachable + * from the given commit) from the revision list. + * + * NOTE: If you have the commits as a string list then you probably want to + * use setup_revisions(), instead of parsing each string and using this + * function. + */ void add_pending_object(struct rev_info *revs, struct object *obj, const char *name); + void add_pending_oid(struct rev_info *revs, const char *name, const struct object_id *oid, unsigned int flags); From patchwork Wed Nov 6 09:59:37 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Passaro via GitGitGadget X-Patchwork-Id: 11229909 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 C165C112B for ; Wed, 6 Nov 2019 10:00:19 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 951632173B for ; Wed, 6 Nov 2019 10:00:19 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="MQZ128OT" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731756AbfKFKAD (ORCPT ); Wed, 6 Nov 2019 05:00:03 -0500 Received: from mail-wr1-f54.google.com ([209.85.221.54]:44168 "EHLO mail-wr1-f54.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731647AbfKFKAA (ORCPT ); Wed, 6 Nov 2019 05:00:00 -0500 Received: by mail-wr1-f54.google.com with SMTP id f2so16050895wrs.11 for ; Wed, 06 Nov 2019 01:59:56 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=WlammgDF0L+1RNwpwU1Hv0Eo8cOXgnk5/hW7BCWo5IU=; b=MQZ128OTvg0kjtAmgeYhPuaW6kqbY+HqCm+LFepmlYnRQru1k18e9qHtIGmvTcnoOm lz6XGVM3U1qoLTpp1Bb4GP1oqOBy/2FWbT5W+L6GVJFL3UgzCp56kXsjnQeNEsVOx26R Th14wax93AaiZ8oIqVMnoHH6I7hzrHVvk3GK8ktlDZKmKkT8gQYk/cU1ocNCI2+jsxP8 G6CtWXpOPxMQNiJSyuUPQfD8v0exc6T7Hh9kWHk5m/zqi6+afU4iAED8xsyRs98KyML9 kFFG1Tc4QdQwEAi1/9GxNFCq+ZJ1VGJDIAL7D5EcOwEAeB0Y6q0PxcXCgz3xibWE/ejF WIhQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=WlammgDF0L+1RNwpwU1Hv0Eo8cOXgnk5/hW7BCWo5IU=; b=A1ADJRWCBpa4H/y62A/BXfbSr2M2oQW36D5ergvThXBqiQK4P09q/g/JeXAAPyYi9H aHzj7a54VysbkZq4+QmuawOiaYVhlQVR6Xrh6bV6QtJaYwKMtnz5upS3l2fBZVZh9uGQ TaT94Md8+rHd1hnIxnQGdbQuLECl/m13VkJljZIPwPLDeqQqSsdlTCniArgBp5vgeU+i u6LSlJM5wrn1BOb4PjrqmBkFLnyCW1vxCBrhfwgK0mCSAZYBRk17ezDLUGOcb2jtbDZa KjW5tOBDIpT+uq5J2xsfUVctklricveiVM1ogZEBSeNTyRZF71N58JysNDiew8Qzfr4x VgQw== X-Gm-Message-State: APjAAAWmtxytCEKHFx2nR0v5U6SRRUt59Pw0wDejTo+Yv0jxyuVwYwYY EvtUyAmLXj+g6rJz3znFCznIa44K X-Google-Smtp-Source: APXvYqyNyd2IMxIk6yej9KoxliVgVjhrvxtPN/U6ahH40vKPXDdlEYk85PvXlGC91e3HyUClRgCv3A== X-Received: by 2002:a05:6000:12d1:: with SMTP id l17mr1731980wrx.261.1573034395913; Wed, 06 Nov 2019 01:59:55 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id r19sm27626641wrr.47.2019.11.06.01.59.55 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 06 Nov 2019 01:59:55 -0800 (PST) Message-Id: In-Reply-To: References: From: "Heba Waly via GitGitGadget" Date: Wed, 06 Nov 2019 09:59:37 +0000 Subject: [PATCH v2 10/20] pathspec: move doc to pathspec.h Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Heba Waly , Junio C Hamano , Heba Waly Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Heba Waly Move the documentation from Documentation/technical/api-setup.txt to pathspec.h as it's easier for the developers to find the usage information beside the code instead of looking for it in another doc file. Also documentation/technical/api-setup.txt is removed because the information it has is now redundant and it'll be hard to keep it up to date and synchronized with the documentation in the header file. Signed-off-by: Heba Waly --- Documentation/technical/api-setup.txt | 47 --------------------------- pathspec.h | 34 ++++++++++++++++++- 2 files changed, 33 insertions(+), 48 deletions(-) delete mode 100644 Documentation/technical/api-setup.txt diff --git a/Documentation/technical/api-setup.txt b/Documentation/technical/api-setup.txt deleted file mode 100644 index eb1fa9853e..0000000000 --- a/Documentation/technical/api-setup.txt +++ /dev/null @@ -1,47 +0,0 @@ -setup API -========= - -Talk about - -* setup_git_directory() -* setup_git_directory_gently() -* is_inside_git_dir() -* is_inside_work_tree() -* setup_work_tree() - -(Dscho) - -Pathspec --------- - -See glossary-context.txt for the syntax of pathspec. In memory, a -pathspec set is represented by "struct pathspec" and is prepared by -parse_pathspec(). This function takes several arguments: - -- magic_mask specifies what features that are NOT supported by the - following code. If a user attempts to use such a feature, - parse_pathspec() can reject it early. - -- flags specifies other things that the caller wants parse_pathspec to - perform. - -- prefix and args come from cmd_* functions - -parse_pathspec() helps catch unsupported features and reject them -politely. At a lower level, different pathspec-related functions may -not support the same set of features. Such pathspec-sensitive -functions are guarded with GUARD_PATHSPEC(), which will die in an -unfriendly way when an unsupported feature is requested. - -The command designers are supposed to make sure that GUARD_PATHSPEC() -never dies. They have to make sure all unsupported features are caught -by parse_pathspec(), not by GUARD_PATHSPEC. grepping GUARD_PATHSPEC() -should give the designers all pathspec-sensitive codepaths and what -features they support. - -A similar process is applied when a new pathspec magic is added. The -designer lifts the GUARD_PATHSPEC restriction in the functions that -support the new magic. At the same time (s)he has to make sure this -new feature will be caught at parse_pathspec() in commands that cannot -handle the new magic in some cases. grepping parse_pathspec() should -help. diff --git a/pathspec.h b/pathspec.h index 1c18a2c90c..0fbd7a051d 100644 --- a/pathspec.h +++ b/pathspec.h @@ -22,6 +22,10 @@ struct index_state; #define PATHSPEC_ONESTAR 1 /* the pathspec pattern satisfies GFNM_ONESTAR */ +/** + * In memory, a pathspec set is represented by "struct pathspec" and is + * prepared by parse_pathspec(). + */ struct pathspec { int nr; unsigned int has_wildcard:1; @@ -73,18 +77,46 @@ struct pathspec { */ #define PATHSPEC_LITERAL_PATH (1<<6) -/* +/** * Given command line arguments and a prefix, convert the input to * pathspec. die() if any magic in magic_mask is used. * * Any arguments used are copied. It is safe for the caller to modify * or free 'prefix' and 'args' after calling this function. + * + * - magic_mask specifies what features that are NOT supported by the following + * code. If a user attempts to use such a feature, parse_pathspec() can reject + * it early. + * + * - flags specifies other things that the caller wants parse_pathspec to + * perform. + * + * - prefix and args come from cmd_* functions + * + * parse_pathspec() helps catch unsupported features and reject them politely. + * At a lower level, different pathspec-related functions may not support the + * same set of features. Such pathspec-sensitive functions are guarded with + * GUARD_PATHSPEC(), which will die in an unfriendly way when an unsupported + * feature is requested. + * + * The command designers are supposed to make sure that GUARD_PATHSPEC() never + * dies. They have to make sure all unsupported features are caught by + * parse_pathspec(), not by GUARD_PATHSPEC. grepping GUARD_PATHSPEC() should + * give the designers all pathspec-sensitive codepaths and what features they + * support. + * + * A similar process is applied when a new pathspec magic is added. The designer + * lifts the GUARD_PATHSPEC restriction in the functions that support the new + * magic. At the same time (s)he has to make sure this new feature will be + * caught at parse_pathspec() in commands that cannot handle the new magic in + * some cases. grepping parse_pathspec() should help. */ void parse_pathspec(struct pathspec *pathspec, unsigned magic_mask, unsigned flags, const char *prefix, const char **args); + void copy_pathspec(struct pathspec *dst, const struct pathspec *src); void clear_pathspec(struct pathspec *); From patchwork Wed Nov 6 09:59:38 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Passaro via GitGitGadget X-Patchwork-Id: 11229917 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 E32791864 for ; Wed, 6 Nov 2019 10:00:27 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id BD7EB21929 for ; Wed, 6 Nov 2019 10:00:27 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="J9d4XuGX" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731736AbfKFKA1 (ORCPT ); Wed, 6 Nov 2019 05:00:27 -0500 Received: from mail-wm1-f46.google.com ([209.85.128.46]:54244 "EHLO mail-wm1-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731713AbfKFKAA (ORCPT ); Wed, 6 Nov 2019 05:00:00 -0500 Received: by mail-wm1-f46.google.com with SMTP id x4so2606818wmi.3 for ; Wed, 06 Nov 2019 01:59:57 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=C8GBxdLoF5Xz2AERpIWZpzuVBkkny6L685nRw2Wwj+0=; b=J9d4XuGXmPsD/JGAJar3oY56JH+cArspO/7mAtbJm8KKoL+yGrRwJhvcZLSV/pg3OD AMUu+Rf/jiZRo+dbXiSnGZ6TFT69L+vy8d0qAcUqleistEUkWJrfIV2EYDYom+M8PVc5 /nY3MudLr3meTlcmcLNl1snZoXqa7KFNLt1e7la6euJGHVmg6xF5uK1029ncjf8jLrl/ cz6tbyEQlIAoofGB7Vh/feu6HjxJOmBl70bk+HR2t4QsmO29aljoXxBabdbdOSYjLWtr yC+l3D7RJ0uod1pCP/TGUhcqq5izBptvwAC8cV2zhjl9fqij/l/17Twb1FRD85umkXea my2g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=C8GBxdLoF5Xz2AERpIWZpzuVBkkny6L685nRw2Wwj+0=; b=YHhMsufyVLMOx/rNNXOaKyqxNkZ7m42MF73c3iKjcGM7GKg+5Frp8XyIrM8Llmin2j zOm9OHpXA8cXM2cYZf8nVp+pszkpGGdWpIG014bznaLoHIPGHnUnT2Q1V+RZn/MBOb6D YHcRnuEvJi25XxY1EjS1MjeuLdyiTAv8O28rzxi6z4SmUjyhmmE28bkUShC3Y5/Pni0G F3kqDD2cIdPB2Ia84twTLPmzW3yiR8UiWGHrLYZWXqrTjqRCmjx/7kdeK+jkPjq2D/iI ksZm9F3IK0wxIqdvNCZk6LkivC1j+9rvvq/TtHaigjeEeoU/MjTJm7iiglmE2Cm5Etvz qZJA== X-Gm-Message-State: APjAAAW3UGjn2E4+HvGYcAamMkgvHicFSX2E6BfhRYLSJC8oF+KahZEO yXLlpnKuS6XavoVI8bSkaQxrCRPH X-Google-Smtp-Source: APXvYqw0Pvoas7BXZqXjDcr1wM7EVy++72pg27Qarm67DNOTufzSNlgroebbYbC+Z1sNFHwgg4se0g== X-Received: by 2002:a7b:cd0b:: with SMTP id f11mr1734128wmj.26.1573034396716; Wed, 06 Nov 2019 01:59:56 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id b3sm2558093wmh.17.2019.11.06.01.59.56 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 06 Nov 2019 01:59:56 -0800 (PST) Message-Id: <3499b99538425f9605fead842c10bc63238f94b9.1573034387.git.gitgitgadget@gmail.com> In-Reply-To: References: From: "Heba Waly via GitGitGadget" Date: Wed, 06 Nov 2019 09:59:38 +0000 Subject: [PATCH v2 11/20] sigchain: move doc to sigchain.h Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Heba Waly , Junio C Hamano , Heba Waly Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Heba Waly Move the documentation from Documentation/technical/api-sigchain.txt to sigchain.h as it's easier for the developers to find the usage information beside the code instead of looking for it in another doc file. Also documentation/technical/api-sigchain.txt is removed because the information it has is now redundant and it'll be hard to keep it up to date and synchronized with the documentation in the header file. Signed-off-by: Heba Waly --- Documentation/technical/api-sigchain.txt | 41 ----------------------- sigchain.h | 42 ++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 41 deletions(-) delete mode 100644 Documentation/technical/api-sigchain.txt diff --git a/Documentation/technical/api-sigchain.txt b/Documentation/technical/api-sigchain.txt deleted file mode 100644 index 9e1189ef01..0000000000 --- a/Documentation/technical/api-sigchain.txt +++ /dev/null @@ -1,41 +0,0 @@ -sigchain API -============ - -Code often wants to set a signal handler to clean up temporary files or -other work-in-progress when we die unexpectedly. For multiple pieces of -code to do this without conflicting, each piece of code must remember -the old value of the handler and restore it either when: - - 1. The work-in-progress is finished, and the handler is no longer - necessary. The handler should revert to the original behavior - (either another handler, SIG_DFL, or SIG_IGN). - - 2. The signal is received. We should then do our cleanup, then chain - to the next handler (or die if it is SIG_DFL). - -Sigchain is a tiny library for keeping a stack of handlers. Your handler -and installation code should look something like: - ------------------------------------------- - void clean_foo_on_signal(int sig) - { - clean_foo(); - sigchain_pop(sig); - raise(sig); - } - - void other_func() - { - sigchain_push_common(clean_foo_on_signal); - mess_up_foo(); - clean_foo(); - } ------------------------------------------- - -Handlers are given the typedef of sigchain_fun. This is the same type -that is given to signal() or sigaction(). It is perfectly reasonable to -push SIG_DFL or SIG_IGN onto the stack. - -You can sigchain_push and sigchain_pop individual signals. For -convenience, sigchain_push_common will push the handler onto the stack -for many common signals. diff --git a/sigchain.h b/sigchain.h index 138b20f54b..a990f18cf6 100644 --- a/sigchain.h +++ b/sigchain.h @@ -1,12 +1,54 @@ #ifndef SIGCHAIN_H #define SIGCHAIN_H +/** + * Code often wants to set a signal handler to clean up temporary files or + * other work-in-progress when we die unexpectedly. For multiple pieces of + * code to do this without conflicting, each piece of code must remember + * the old value of the handler and restore it either when: + * + * 1. The work-in-progress is finished, and the handler is no longer + * necessary. The handler should revert to the original behavior + * (either another handler, SIG_DFL, or SIG_IGN). + * + * 2. The signal is received. We should then do our cleanup, then chain + * to the next handler (or die if it is SIG_DFL). + * + * Sigchain is a tiny library for keeping a stack of handlers. Your handler + * and installation code should look something like: + * + * ------------------------------------------ + * void clean_foo_on_signal(int sig) + * { + * clean_foo(); + * sigchain_pop(sig); + * raise(sig); + * } + * + * void other_func() + * { + * sigchain_push_common(clean_foo_on_signal); + * mess_up_foo(); + * clean_foo(); + * } + * ------------------------------------------ + * + */ + +/** + * Handlers are given the typedef of sigchain_fun. This is the same type + * that is given to signal() or sigaction(). It is perfectly reasonable to + * push SIG_DFL or SIG_IGN onto the stack. + */ typedef void (*sigchain_fun)(int); +/* You can sigchain_push and sigchain_pop individual signals. */ int sigchain_push(int sig, sigchain_fun f); int sigchain_pop(int sig); +/* push the handler onto the stack for many common signals. */ void sigchain_push_common(sigchain_fun f); + void sigchain_pop_common(void); #endif /* SIGCHAIN_H */ From patchwork Wed Nov 6 09:59:39 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Passaro via GitGitGadget X-Patchwork-Id: 11229919 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 6F0211575 for ; Wed, 6 Nov 2019 10:00:27 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 4CB5E217F4 for ; Wed, 6 Nov 2019 10:00:27 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="WOzhr0hG" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731679AbfKFKA0 (ORCPT ); Wed, 6 Nov 2019 05:00:26 -0500 Received: from mail-wm1-f49.google.com ([209.85.128.49]:40384 "EHLO mail-wm1-f49.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731691AbfKFKAA (ORCPT ); Wed, 6 Nov 2019 05:00:00 -0500 Received: by mail-wm1-f49.google.com with SMTP id f3so2555361wmc.5 for ; Wed, 06 Nov 2019 01:59:58 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=BGFDMznWg+rixa5vEZllxFnPLKaJJ0SXa/3bQPF5IPY=; b=WOzhr0hGZavTqukW5aMf2KI+KJ+R12Of08HB+ryy1mNyXCSHSGVS8hAEwRIgWFaIDc BUr3t5yeadIOveQw1SZiIZ16fdbQRdRFW1XwYWh5Q3ewOIoKrG75mvJ4G0owGp+9srjC CEfgqgQROvRGipnq966H4647T9apxxP2g6NFSEcFZwxQ00YuOmnsM7SlQPf6eLoFb0q8 MyPqS2ssN6QhDJEkHtx6vtqN4YDiwEIWWIQ7E4RaFtQIPHO7vypRZ7AxfofrbsLMZJAJ oLmEvvTAJVpnYnOaW0Dl0/k4wSmVMDHZza5WERAe4CpAsfAp00451zlGJKl91XmgJfdZ L+Tw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=BGFDMznWg+rixa5vEZllxFnPLKaJJ0SXa/3bQPF5IPY=; b=AjJJR+9AOH1cBNaW39t9iOdU3XS7P2Ssw2uRiuj/TwSiX+PQbTR23xd9GHinmrBIbf dZ4hgfMHuLHvUL34xfJyelw6IWlupE7eWj7ENJ+EaAILujbOZYTWQt/VlTsNQA7UYZcU sceBaazl70GOpER7Gw4/O9ekEmK2IvZsIExnIPjSBomSC1asTIAD8F+QnZgICXktNii7 x+Ki1VhuutBYZ3HBZ4jIMcV/2LjT8Yd4s5gCNewSHhHUbBr3iKVFR557L2DSEn1Cwt4B 7kl0lhwPnSGpOFzwx4H4osYZJm10iG05w9FQ+Wq7g9WBTMw5WhCEQLjQ48PSYBlCj+tg vXhA== X-Gm-Message-State: APjAAAXeej3ihpd//P7PjdV/4Y2rAvy+jtgsx3MJ7WGNMnHwH1ge0mpr /OGBJ6OLncWzc2jS3u942ttqMlGQ X-Google-Smtp-Source: APXvYqxIw/YLhXF+BKPt7ZsiCrQ4H1rjbWzSh47bHhhujpMv/8i6cgDhNEQ856UPbDNl6ReTsmpS7w== X-Received: by 2002:a7b:c181:: with SMTP id y1mr1580685wmi.16.1573034397414; Wed, 06 Nov 2019 01:59:57 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id k4sm2291871wmk.26.2019.11.06.01.59.56 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 06 Nov 2019 01:59:56 -0800 (PST) Message-Id: In-Reply-To: References: From: "Heba Waly via GitGitGadget" Date: Wed, 06 Nov 2019 09:59:39 +0000 Subject: [PATCH v2 12/20] cache: move doc to cache.h Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Heba Waly , Junio C Hamano , Heba Waly Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Heba Waly Move the documentation from Documentation/technical/api-allocation-growing.txt to cache.h as it's easier for the developers to find the usage information beside the code instead of looking for it in another doc file. Also documentation/technical/api-allocation-growing.txt is removed because the information it has is now redundant and it'll be hard to keep it up to date and synchronized with the documentation in the header file. Signed-off-by: Heba Waly Reviewed-by: Emily Shaffer --- .../technical/api-allocation-growing.txt | 39 ------------------ cache.h | 41 +++++++++++++++++-- 2 files changed, 37 insertions(+), 43 deletions(-) delete mode 100644 Documentation/technical/api-allocation-growing.txt diff --git a/Documentation/technical/api-allocation-growing.txt b/Documentation/technical/api-allocation-growing.txt deleted file mode 100644 index 5a59b54844..0000000000 --- a/Documentation/technical/api-allocation-growing.txt +++ /dev/null @@ -1,39 +0,0 @@ -allocation growing API -====================== - -Dynamically growing an array using realloc() is error prone and boring. - -Define your array with: - -* a pointer (`item`) that points at the array, initialized to `NULL` - (although please name the variable based on its contents, not on its - type); - -* an integer variable (`alloc`) that keeps track of how big the current - allocation is, initialized to `0`; - -* another integer variable (`nr`) to keep track of how many elements the - array currently has, initialized to `0`. - -Then before adding `n`th element to the item, call `ALLOC_GROW(item, n, -alloc)`. This ensures that the array can hold at least `n` elements by -calling `realloc(3)` and adjusting `alloc` variable. - ------------- -sometype *item; -size_t nr; -size_t alloc - -for (i = 0; i < nr; i++) - if (we like item[i] already) - return; - -/* we did not like any existing one, so add one */ -ALLOC_GROW(item, nr + 1, alloc); -item[nr++] = value you like; ------------- - -You are responsible for updating the `nr` variable. - -If you need to specify the number of elements to allocate explicitly -then use the macro `REALLOC_ARRAY(item, alloc)` instead of `ALLOC_GROW`. diff --git a/cache.h b/cache.h index 04cabaac11..8fbbdf971a 100644 --- a/cache.h +++ b/cache.h @@ -632,10 +632,43 @@ int daemonize(void); #define alloc_nr(x) (((x)+16)*3/2) -/* - * Realloc the buffer pointed at by variable 'x' so that it can hold - * at least 'nr' entries; the number of entries currently allocated - * is 'alloc', using the standard growing factor alloc_nr() macro. +/** + * Dynamically growing an array using realloc() is error prone and boring. + * + * Define your array with: + * + * - a pointer (`item`) that points at the array, initialized to `NULL` + * (although please name the variable based on its contents, not on its + * type); + * + * - an integer variable (`alloc`) that keeps track of how big the current + * allocation is, initialized to `0`; + * + * - another integer variable (`nr`) to keep track of how many elements the + * array currently has, initialized to `0`. + * + * Then before adding `n`th element to the item, call `ALLOC_GROW(item, n, + * alloc)`. This ensures that the array can hold at least `n` elements by + * calling `realloc(3)` and adjusting `alloc` variable. + * + * ------------ + * sometype *item; + * size_t nr; + * size_t alloc + * + * for (i = 0; i < nr; i++) + * if (we like item[i] already) + * return; + * + * // we did not like any existing one, so add one + * ALLOC_GROW(item, nr + 1, alloc); + * item[nr++] = value you like; + * ------------ + * + * You are responsible for updating the `nr` variable. + * + * If you need to specify the number of elements to allocate explicitly + * then use the macro `REALLOC_ARRAY(item, alloc)` instead of `ALLOC_GROW`. * * Consider using ALLOC_GROW_BY instead of ALLOC_GROW as it has some * added niceties. From patchwork Wed Nov 6 09:59:40 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Passaro via GitGitGadget X-Patchwork-Id: 11229895 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 5279B112B for ; Wed, 6 Nov 2019 10:00:07 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 269602173B for ; Wed, 6 Nov 2019 10:00:07 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="d+TRUvNL" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731764AbfKFKAE (ORCPT ); Wed, 6 Nov 2019 05:00:04 -0500 Received: from mail-wr1-f54.google.com ([209.85.221.54]:43648 "EHLO mail-wr1-f54.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731633AbfKFKAB (ORCPT ); Wed, 6 Nov 2019 05:00:01 -0500 Received: by mail-wr1-f54.google.com with SMTP id n1so24961983wra.10 for ; Wed, 06 Nov 2019 01:59:59 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=giO2GU2kHEWuMdLCQf18nZDaZn/nf7zmDq7PVNroH0w=; b=d+TRUvNLzYWPiKE4v+UHyzcLL7ec1jbUIAqIVFu0IGDkdRBkSPTVAVZkSNnpCJOgrF pdf7sHPwP0j4LQrdIdoPJlcpZtz4Sk7opDnCuFRgQvbMQpwn4lnxZj+6AmvvZjPgmfe7 043k2FpzXew9eMw469ApCBrFy0OEmTndoPsHQ6g+DXBqiINP02nBRWbI7q2sMScuZKhz SghaR6rvKYtVpCuM2Mpr0ZpsOhXNIjVz/s1estRTJXL5+JyhzRKlJsAuOGJui7JjosHn cAqS1hO3tFgBvkJHHgzItP6Vi35H+3hPCJP08EBtcP1IShKMIBOG6VuMPC4pravaEQUZ 3zcQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=giO2GU2kHEWuMdLCQf18nZDaZn/nf7zmDq7PVNroH0w=; b=rbJmYK/SwR6qg6Gch/rxS+5kjFiKLP2w7X4J4575RvfcyMk2CkAHZYUj14n29EgUsS eLe10TAinE6mqR+xJTYU0Y6YybdzdzbmL6MjnwxZK+MpxyGFE0zzP6xgneF2Uw3wz2Vd pHGlAnUE+/Yq7OYs51f+0IeKv8JgtMrYSjdFXdVejlNDKjpJ53Z40S7+gQNeZMinWEDI W6r/RiNtiueShZOvnezWbbmxqeShoG/IhJbRsci3klvL6+GYnR6DyxHP966eo3rJXZBf vA4g/TM7M9+f2+hSEJ6M8jSmTRFicKuLB0zx2AJUkvmzQnR3e3qWIA5mS0h2gy+MCU79 ckQQ== X-Gm-Message-State: APjAAAUP5vsd4o5Y31Sb7VAj23IW/BVV8unF7wJIAPbxquPDHqbolIMa +DWR/PGJrn7I2lKC++EdDDmHhnGG X-Google-Smtp-Source: APXvYqw+O8GPfoleIszf6F4KogKZDpRWxmT1hpgSK20VmP8NqhPm6iqoVTV0U7JOipn+Y2bXsfg5hw== X-Received: by 2002:a5d:4a50:: with SMTP id v16mr1695103wrs.85.1573034398111; Wed, 06 Nov 2019 01:59:58 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id g184sm2949350wma.8.2019.11.06.01.59.57 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 06 Nov 2019 01:59:57 -0800 (PST) Message-Id: <314864e42c10c64097090d10c42dfba0e407b97d.1573034387.git.gitgitgadget@gmail.com> In-Reply-To: References: From: "Heba Waly via GitGitGadget" Date: Wed, 06 Nov 2019 09:59:40 +0000 Subject: [PATCH v2 13/20] argv-array: move doc to argv-array.h Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Heba Waly , Junio C Hamano , Heba Waly Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Heba Waly Move the documentation from Documentation/technical/api-argv-array.txt to argv-array.h as it's easier for the developers to find the usage information beside the code instead of looking for it in another doc file. Also documentation/technical/api-argv-array.txt is removed because the information it has is now redundant and it'll be hard to keep it up to date and synchronized with the documentation in the header file. Signed-off-by: Heba Waly --- Documentation/technical/api-argv-array.txt | 65 ---------------------- argv-array.h | 62 +++++++++++++++++++++ 2 files changed, 62 insertions(+), 65 deletions(-) delete mode 100644 Documentation/technical/api-argv-array.txt diff --git a/Documentation/technical/api-argv-array.txt b/Documentation/technical/api-argv-array.txt deleted file mode 100644 index 870c8edbfb..0000000000 --- a/Documentation/technical/api-argv-array.txt +++ /dev/null @@ -1,65 +0,0 @@ -argv-array API -============== - -The argv-array API allows one to dynamically build and store -NULL-terminated lists. An argv-array maintains the invariant that the -`argv` member always points to a non-NULL array, and that the array is -always NULL-terminated at the element pointed to by `argv[argc]`. This -makes the result suitable for passing to functions expecting to receive -argv from main(), or the link:api-run-command.html[run-command API]. - -The string-list API (documented in string-list.h) is similar, but cannot be -used for these purposes; instead of storing a straight string pointer, -it contains an item structure with a `util` field that is not compatible -with the traditional argv interface. - -Each `argv_array` manages its own memory. Any strings pushed into the -array are duplicated, and all memory is freed by argv_array_clear(). - -Data Structures ---------------- - -`struct argv_array`:: - - A single array. This should be initialized by assignment from - `ARGV_ARRAY_INIT`, or by calling `argv_array_init`. The `argv` - member contains the actual array; the `argc` member contains the - number of elements in the array, not including the terminating - NULL. - -Functions ---------- - -`argv_array_init`:: - Initialize an array. This is no different than assigning from - `ARGV_ARRAY_INIT`. - -`argv_array_push`:: - Push a copy of a string onto the end of the array. - -`argv_array_pushl`:: - Push a list of strings onto the end of the array. The arguments - should be a list of `const char *` strings, terminated by a NULL - argument. - -`argv_array_pushf`:: - Format a string and push it onto the end of the array. This is a - convenience wrapper combining `strbuf_addf` and `argv_array_push`. - -`argv_array_pushv`:: - Push a null-terminated array of strings onto the end of the array. - -`argv_array_pop`:: - Remove the final element from the array. If there are no - elements in the array, do nothing. - -`argv_array_clear`:: - Free all memory associated with the array and return it to the - initial, empty state. - -`argv_array_detach`:: - Disconnect the `argv` member from the `argv_array` struct and - return it. The caller is responsible for freeing the memory used - by the array, and by the strings it references. After detaching, - the `argv_array` is in a reinitialized state and can be pushed - into again. diff --git a/argv-array.h b/argv-array.h index a39ba43f57..a7d3b10707 100644 --- a/argv-array.h +++ b/argv-array.h @@ -1,8 +1,32 @@ #ifndef ARGV_ARRAY_H #define ARGV_ARRAY_H +/** + * The argv-array API allows one to dynamically build and store + * NULL-terminated lists. An argv-array maintains the invariant that the + * `argv` member always points to a non-NULL array, and that the array is + * always NULL-terminated at the element pointed to by `argv[argc]`. This + * makes the result suitable for passing to functions expecting to receive + * argv from main(). + * + * The string-list API (documented in string-list.h) is similar, but cannot be + * used for these purposes; instead of storing a straight string pointer, + * it contains an item structure with a `util` field that is not compatible + * with the traditional argv interface. + * + * Each `argv_array` manages its own memory. Any strings pushed into the + * array are duplicated, and all memory is freed by argv_array_clear(). + */ + extern const char *empty_argv[]; +/** + * A single array. This should be initialized by assignment from + * `ARGV_ARRAY_INIT`, or by calling `argv_array_init`. The `argv` + * member contains the actual array; the `argc` member contains the + * number of elements in the array, not including the terminating + * NULL. + */ struct argv_array { const char **argv; int argc; @@ -11,17 +35,55 @@ struct argv_array { #define ARGV_ARRAY_INIT { empty_argv, 0, 0 } +/** + * Initialize an array. This is no different than assigning from + * `ARGV_ARRAY_INIT`. + */ void argv_array_init(struct argv_array *); + +/* Push a copy of a string onto the end of the array. */ const char *argv_array_push(struct argv_array *, const char *); + +/** + * Format a string and push it onto the end of the array. This is a + * convenience wrapper combining `strbuf_addf` and `argv_array_push`. + */ __attribute__((format (printf,2,3))) const char *argv_array_pushf(struct argv_array *, const char *fmt, ...); + +/** + * Push a list of strings onto the end of the array. The arguments + * should be a list of `const char *` strings, terminated by a NULL + * argument. + */ LAST_ARG_MUST_BE_NULL void argv_array_pushl(struct argv_array *, ...); + +/* Push a null-terminated array of strings onto the end of the array. */ void argv_array_pushv(struct argv_array *, const char **); + +/** + * Remove the final element from the array. If there are no + * elements in the array, do nothing. + */ void argv_array_pop(struct argv_array *); + /* Splits by whitespace; does not handle quoted arguments! */ void argv_array_split(struct argv_array *, const char *); + +/** + * Free all memory associated with the array and return it to the + * initial, empty state. + */ void argv_array_clear(struct argv_array *); + +/** + * Disconnect the `argv` member from the `argv_array` struct and + * return it. The caller is responsible for freeing the memory used + * by the array, and by the strings it references. After detaching, + * the `argv_array` is in a reinitialized state and can be pushed + * into again. + */ const char **argv_array_detach(struct argv_array *); #endif /* ARGV_ARRAY_H */ From patchwork Wed Nov 6 09:59:41 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Passaro via GitGitGadget X-Patchwork-Id: 11229911 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 20C941575 for ; Wed, 6 Nov 2019 10:00:23 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id D5B30217F4 for ; Wed, 6 Nov 2019 10:00:22 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="LMU/SV7P" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731846AbfKFKAT (ORCPT ); Wed, 6 Nov 2019 05:00:19 -0500 Received: from mail-wm1-f48.google.com ([209.85.128.48]:37507 "EHLO mail-wm1-f48.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725856AbfKFKAD (ORCPT ); Wed, 6 Nov 2019 05:00:03 -0500 Received: by mail-wm1-f48.google.com with SMTP id q130so2582514wme.2 for ; Wed, 06 Nov 2019 02:00:00 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=Tt/5vjPy7rhSe5T9z3YY/AB4QaTIcC2L1xx2NR8WcNE=; b=LMU/SV7PKbgv9oQ0bl010Ocq3Rw10Xp2ZhgJqm6ot0D3pCFlW341RYvrkADEoE0+O+ FST8JJLtpdB1zMwtAjCG6wQ5ntmvpTGAA5z2OHkqOSUXfmWCQEKbnN+twA6wN87QsXtz nyxi37RP8L6b5BQDrQm7IybXS+0LOSP5kW0vybu0d5Z9peDA6OUeAWWECR/Pg/g8Zk7t UML0IML2cornD5oeZ6iwFXVVnbpjdPoHB9lNCRZRPfnktqk/aDQsmGPZimtbbmSLC9vR gnY/ykd7+/caNSx2DcaqB2r85O4gYefp+ZbAArEJcdybdPcBhK56K303jQ+ZIXh/gj4V 8nKQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=Tt/5vjPy7rhSe5T9z3YY/AB4QaTIcC2L1xx2NR8WcNE=; b=L/Hqydtj4IRSk17Hxwig2vJrdxcV3/dRtT4yILx7RU86dRoFzS0sYJmtVoFx70GcAy 1OZEqJvQcsTWqS8PSOWYjBQ1j3QnDQMLlF311t2vRG3YonEs8uH1P0nFWpDhUNchJHrP hR3NUR0vQwWJP9b7GXSHZWYMxJ3e/IhooZIbyddkXYXJEpKeTObluloW3bV/uWZM+xaB qGncsfRNJXsNNbvREUf3PPpdgxraTKf4w26sNFZJJmFrle04SNTqSt31ACvqzOb1d+x/ Cqt/4uw6UdM+YhyDWbI1kqPtP8InHaktHx6Nbo4iovt7HbETw4K72ASURXnfQzBUwzsW 9V5g== X-Gm-Message-State: APjAAAUXtl1YG+X2inpilaW9lX7zE4aG29qHnk5yfSoOX4pHkMUxLCh2 B3jnS91FRwXgSC4ymSSQA5lJEAcs X-Google-Smtp-Source: APXvYqxNWrw1YMU+VkdGr4kruDpjtHZSkNFttwCwC8tigX3gaHlcmKCNTYmyn9zGVoVv4d8ASX/B4Q== X-Received: by 2002:a7b:c305:: with SMTP id k5mr1740028wmj.90.1573034398980; Wed, 06 Nov 2019 01:59:58 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id k4sm2291928wmk.26.2019.11.06.01.59.58 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 06 Nov 2019 01:59:58 -0800 (PST) Message-Id: <8fd1fa98a80fa9c9e04ef67b3f9698ff894b6787.1573034387.git.gitgitgadget@gmail.com> In-Reply-To: References: From: "Heba Waly via GitGitGadget" Date: Wed, 06 Nov 2019 09:59:41 +0000 Subject: [PATCH v2 14/20] credential: move doc to credential.h Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Heba Waly , Junio C Hamano , Heba Waly Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Heba Waly Move the documentation from Documentation/technical/api-credentials.txt to credential.h as it's easier for the developers to find the usage information beside the code instead of looking for it in another doc file. Documentation/technical/api-credentials.txt is removed because the information it has is now redundant and it'll be hard to keep it up to date and synchronized with the documentation in the header file. Documentation/git-credential.txt and Documentation/gitcredentials.txt now link to credential.h instead of Documentation/technical/api-credentials.txt for details about the credetials API. Signed-off-by: Heba Waly --- Documentation/git-credential.txt | 3 +- Documentation/gitcredentials.txt | 3 +- Documentation/technical/api-credentials.txt | 271 -------------------- credential.h | 236 +++++++++++++++++ 4 files changed, 238 insertions(+), 275 deletions(-) delete mode 100644 Documentation/technical/api-credentials.txt diff --git a/Documentation/git-credential.txt b/Documentation/git-credential.txt index b211440373..6f0c7ca80f 100644 --- a/Documentation/git-credential.txt +++ b/Documentation/git-credential.txt @@ -19,8 +19,7 @@ from system-specific helpers, as well as prompting the user for usernames and passwords. The git-credential command exposes this interface to scripts which may want to retrieve, store, or prompt for credentials in the same manner as Git. The design of this scriptable -interface models the internal C API; see -link:technical/api-credentials.html[the Git credential API] for more +interface models the internal C API; see credential.h for more background on the concepts. git-credential takes an "action" option on the command-line (one of diff --git a/Documentation/gitcredentials.txt b/Documentation/gitcredentials.txt index adc759612d..ea759fdee5 100644 --- a/Documentation/gitcredentials.txt +++ b/Documentation/gitcredentials.txt @@ -186,8 +186,7 @@ CUSTOM HELPERS -------------- You can write your own custom helpers to interface with any system in -which you keep credentials. See the documentation for Git's -link:technical/api-credentials.html[credentials API] for details. +which you keep credentials. See credential.h for details. GIT --- diff --git a/Documentation/technical/api-credentials.txt b/Documentation/technical/api-credentials.txt deleted file mode 100644 index 75368f26ca..0000000000 --- a/Documentation/technical/api-credentials.txt +++ /dev/null @@ -1,271 +0,0 @@ -credentials API -=============== - -The credentials API provides an abstracted way of gathering username and -password credentials from the user (even though credentials in the wider -world can take many forms, in this document the word "credential" always -refers to a username and password pair). - -This document describes two interfaces: the C API that the credential -subsystem provides to the rest of Git, and the protocol that Git uses to -communicate with system-specific "credential helpers". If you are -writing Git code that wants to look up or prompt for credentials, see -the section "C API" below. If you want to write your own helper, see -the section on "Credential Helpers" below. - -Typical setup -------------- - ------------- -+-----------------------+ -| Git code (C) |--- to server requiring ---> -| | authentication -|.......................| -| C credential API |--- prompt ---> User -+-----------------------+ - ^ | - | pipe | - | v -+-----------------------+ -| Git credential helper | -+-----------------------+ ------------- - -The Git code (typically a remote-helper) will call the C API to obtain -credential data like a login/password pair (credential_fill). The -API will itself call a remote helper (e.g. "git credential-cache" or -"git credential-store") that may retrieve credential data from a -store. If the credential helper cannot find the information, the C API -will prompt the user. Then, the caller of the API takes care of -contacting the server, and does the actual authentication. - -C API ------ - -The credential C API is meant to be called by Git code which needs to -acquire or store a credential. It is centered around an object -representing a single credential and provides three basic operations: -fill (acquire credentials by calling helpers and/or prompting the user), -approve (mark a credential as successfully used so that it can be stored -for later use), and reject (mark a credential as unsuccessful so that it -can be erased from any persistent storage). - -Data Structures -~~~~~~~~~~~~~~~ - -`struct credential`:: - - This struct represents a single username/password combination - along with any associated context. All string fields should be - heap-allocated (or NULL if they are not known or not applicable). - The meaning of the individual context fields is the same as - their counterparts in the helper protocol; see the section below - for a description of each field. -+ -The `helpers` member of the struct is a `string_list` of helpers. Each -string specifies an external helper which will be run, in order, to -either acquire or store credentials. See the section on credential -helpers below. This list is filled-in by the API functions -according to the corresponding configuration variables before -consulting helpers, so there usually is no need for a caller to -modify the helpers field at all. -+ -This struct should always be initialized with `CREDENTIAL_INIT` or -`credential_init`. - - -Functions -~~~~~~~~~ - -`credential_init`:: - - Initialize a credential structure, setting all fields to empty. - -`credential_clear`:: - - Free any resources associated with the credential structure, - returning it to a pristine initialized state. - -`credential_fill`:: - - Instruct the credential subsystem to fill the username and - password fields of the passed credential struct by first - consulting helpers, then asking the user. After this function - returns, the username and password fields of the credential are - guaranteed to be non-NULL. If an error occurs, the function will - die(). - -`credential_reject`:: - - Inform the credential subsystem that the provided credentials - have been rejected. This will cause the credential subsystem to - notify any helpers of the rejection (which allows them, for - example, to purge the invalid credentials from storage). It - will also free() the username and password fields of the - credential and set them to NULL (readying the credential for - another call to `credential_fill`). Any errors from helpers are - ignored. - -`credential_approve`:: - - Inform the credential subsystem that the provided credentials - were successfully used for authentication. This will cause the - credential subsystem to notify any helpers of the approval, so - that they may store the result to be used again. Any errors - from helpers are ignored. - -`credential_from_url`:: - - Parse a URL into broken-down credential fields. - -Example -~~~~~~~ - -The example below shows how the functions of the credential API could be -used to login to a fictitious "foo" service on a remote host: - ------------------------------------------------------------------------ -int foo_login(struct foo_connection *f) -{ - int status; - /* - * Create a credential with some context; we don't yet know the - * username or password. - */ - - struct credential c = CREDENTIAL_INIT; - c.protocol = xstrdup("foo"); - c.host = xstrdup(f->hostname); - - /* - * Fill in the username and password fields by contacting - * helpers and/or asking the user. The function will die if it - * fails. - */ - credential_fill(&c); - - /* - * Otherwise, we have a username and password. Try to use it. - */ - status = send_foo_login(f, c.username, c.password); - switch (status) { - case FOO_OK: - /* It worked. Store the credential for later use. */ - credential_accept(&c); - break; - case FOO_BAD_LOGIN: - /* Erase the credential from storage so we don't try it - * again. */ - credential_reject(&c); - break; - default: - /* - * Some other error occurred. We don't know if the - * credential is good or bad, so report nothing to the - * credential subsystem. - */ - } - - /* Free any associated resources. */ - credential_clear(&c); - - return status; -} ------------------------------------------------------------------------ - - -Credential Helpers ------------------- - -Credential helpers are programs executed by Git to fetch or save -credentials from and to long-term storage (where "long-term" is simply -longer than a single Git process; e.g., credentials may be stored -in-memory for a few minutes, or indefinitely on disk). - -Each helper is specified by a single string in the configuration -variable `credential.helper` (and others, see linkgit:git-config[1]). -The string is transformed by Git into a command to be executed using -these rules: - - 1. If the helper string begins with "!", it is considered a shell - snippet, and everything after the "!" becomes the command. - - 2. Otherwise, if the helper string begins with an absolute path, the - verbatim helper string becomes the command. - - 3. Otherwise, the string "git credential-" is prepended to the helper - string, and the result becomes the command. - -The resulting command then has an "operation" argument appended to it -(see below for details), and the result is executed by the shell. - -Here are some example specifications: - ----------------------------------------------------- -# run "git credential-foo" -foo - -# same as above, but pass an argument to the helper -foo --bar=baz - -# the arguments are parsed by the shell, so use shell -# quoting if necessary -foo --bar="whitespace arg" - -# you can also use an absolute path, which will not use the git wrapper -/path/to/my/helper --with-arguments - -# or you can specify your own shell snippet -!f() { echo "password=`cat $HOME/.secret`"; }; f ----------------------------------------------------- - -Generally speaking, rule (3) above is the simplest for users to specify. -Authors of credential helpers should make an effort to assist their -users by naming their program "git-credential-$NAME", and putting it in -the $PATH or $GIT_EXEC_PATH during installation, which will allow a user -to enable it with `git config credential.helper $NAME`. - -When a helper is executed, it will have one "operation" argument -appended to its command line, which is one of: - -`get`:: - - Return a matching credential, if any exists. - -`store`:: - - Store the credential, if applicable to the helper. - -`erase`:: - - Remove a matching credential, if any, from the helper's storage. - -The details of the credential will be provided on the helper's stdin -stream. The exact format is the same as the input/output format of the -`git credential` plumbing command (see the section `INPUT/OUTPUT -FORMAT` in linkgit:git-credential[1] for a detailed specification). - -For a `get` operation, the helper should produce a list of attributes -on stdout in the same format. A helper is free to produce a subset, or -even no values at all if it has nothing useful to provide. Any provided -attributes will overwrite those already known about by Git. If a helper -outputs a `quit` attribute with a value of `true` or `1`, no further -helpers will be consulted, nor will the user be prompted (if no -credential has been provided, the operation will then fail). - -For a `store` or `erase` operation, the helper's output is ignored. -If it fails to perform the requested operation, it may complain to -stderr to inform the user. If it does not support the requested -operation (e.g., a read-only store), it should silently ignore the -request. - -If a helper receives any other operation, it should silently ignore the -request. This leaves room for future operations to be added (older -helpers will just ignore the new requests). - -See also --------- - -linkgit:gitcredentials[7] - -linkgit:git-config[1] (See configuration variables `credential.*`) diff --git a/credential.h b/credential.h index 6b0cd16be2..7f88412346 100644 --- a/credential.h +++ b/credential.h @@ -3,8 +3,208 @@ #include "string-list.h" +/** + * The credentials API provides an abstracted way of gathering username and + * password credentials from the user. + * + * Typical setup + * ------------- + * + * ------------ + * +-----------------------+ + * | Git code (C) |--- to server requiring ---> + * | | authentication + * |.......................| + * | C credential API |--- prompt ---> User + * +-----------------------+ + * ^ | + * | pipe | + * | v + * +-----------------------+ + * | Git credential helper | + * +-----------------------+ + * ------------ + * + * The Git code (typically a remote-helper) will call the C API to obtain + * credential data like a login/password pair (credential_fill). The + * API will itself call a remote helper (e.g. "git credential-cache" or + * "git credential-store") that may retrieve credential data from a + * store. If the credential helper cannot find the information, the C API + * will prompt the user. Then, the caller of the API takes care of + * contacting the server, and does the actual authentication. + * + * C API + * ----- + * + * The credential C API is meant to be called by Git code which needs to + * acquire or store a credential. It is centered around an object + * representing a single credential and provides three basic operations: + * fill (acquire credentials by calling helpers and/or prompting the user), + * approve (mark a credential as successfully used so that it can be stored + * for later use), and reject (mark a credential as unsuccessful so that it + * can be erased from any persistent storage). + * + * Example + * ~~~~~~~ + * + * The example below shows how the functions of the credential API could be + * used to login to a fictitious "foo" service on a remote host: + * + * ----------------------------------------------------------------------- + * int foo_login(struct foo_connection *f) + * { + * int status; + * // Create a credential with some context; we don't yet know the + * // username or password. + * + * struct credential c = CREDENTIAL_INIT; + * c.protocol = xstrdup("foo"); + * c.host = xstrdup(f->hostname); + * + * // Fill in the username and password fields by contacting + * // helpers and/or asking the user. The function will die if it + * // fails. + * credential_fill(&c); + * + * // Otherwise, we have a username and password. Try to use it. + * + * status = send_foo_login(f, c.username, c.password); + * switch (status) { + * case FOO_OK: + * // It worked. Store the credential for later use. + * credential_accept(&c); + * break; + * case FOO_BAD_LOGIN: + * // Erase the credential from storage so we don't try it again. + * credential_reject(&c); + * break; + * default: + * // Some other error occurred. We don't know if the + * // credential is good or bad, so report nothing to the + * // credential subsystem. + * } + * + * // Free any associated resources. + * credential_clear(&c); + * + * return status; + * } + * ----------------------------------------------------------------------- + * + * Credential Helpers + * ------------------ + * + * Credential helpers are programs executed by Git to fetch or save + * credentials from and to long-term storage (where "long-term" is simply + * longer than a single Git process; e.g., credentials may be stored + * in-memory for a few minutes, or indefinitely on disk). + * + * Each helper is specified by a single string in the configuration + * variable `credential.helper` (and others, see Documentation/git-config.txt). + * The string is transformed by Git into a command to be executed using + * these rules: + * + * 1. If the helper string begins with "!", it is considered a shell + * snippet, and everything after the "!" becomes the command. + * + * 2. Otherwise, if the helper string begins with an absolute path, the + * verbatim helper string becomes the command. + * + * 3. Otherwise, the string "git credential-" is prepended to the helper + * string, and the result becomes the command. + * + * The resulting command then has an "operation" argument appended to it + * (see below for details), and the result is executed by the shell. + * + * Here are some example specifications: + * + * ---------------------------------------------------- + * # run "git credential-foo" + * foo + * + * # same as above, but pass an argument to the helper + * foo --bar=baz + * + * # the arguments are parsed by the shell, so use shell + * # quoting if necessary + * foo --bar="whitespace arg" + * + * # you can also use an absolute path, which will not use the git wrapper + * /path/to/my/helper --with-arguments + * + * # or you can specify your own shell snippet + * !f() { echo "password=`cat $HOME/.secret`"; }; f + * ---------------------------------------------------- + * + * Generally speaking, rule (3) above is the simplest for users to specify. + * Authors of credential helpers should make an effort to assist their + * users by naming their program "git-credential-$NAME", and putting it in + * the $PATH or $GIT_EXEC_PATH during installation, which will allow a user + * to enable it with `git config credential.helper $NAME`. + * + * When a helper is executed, it will have one "operation" argument + * appended to its command line, which is one of: + * + * `get`:: + * + * Return a matching credential, if any exists. + * + * `store`:: + * + * Store the credential, if applicable to the helper. + * + * `erase`:: + * + * Remove a matching credential, if any, from the helper's storage. + * + * The details of the credential will be provided on the helper's stdin + * stream. The exact format is the same as the input/output format of the + * `git credential` plumbing command (see the section `INPUT/OUTPUT + * FORMAT` in Documentation/git-credential.txt for a detailed specification). + * + * For a `get` operation, the helper should produce a list of attributes + * on stdout in the same format. A helper is free to produce a subset, or + * even no values at all if it has nothing useful to provide. Any provided + * attributes will overwrite those already known about by Git. If a helper + * outputs a `quit` attribute with a value of `true` or `1`, no further + * helpers will be consulted, nor will the user be prompted (if no + * credential has been provided, the operation will then fail). + * + * For a `store` or `erase` operation, the helper's output is ignored. + * If it fails to perform the requested operation, it may complain to + * stderr to inform the user. If it does not support the requested + * operation (e.g., a read-only store), it should silently ignore the + * request. + * + * If a helper receives any other operation, it should silently ignore the + * request. This leaves room for future operations to be added (older + * helpers will just ignore the new requests). + * + */ + + +/** + * This struct represents a single username/password combination + * along with any associated context. All string fields should be + * heap-allocated (or NULL if they are not known or not applicable). + * The meaning of the individual context fields is the same as + * their counterparts in the helper protocol. + * + * This struct should always be initialized with `CREDENTIAL_INIT` or + * `credential_init`. + */ struct credential { + + /** + * A `string_list` of helpers. Each string specifies an external + * helper which will be run, in order, to either acquire or store + * credentials. This list is filled-in by the API functions + * according to the corresponding configuration variables before + * consulting helpers, so there usually is no need for a caller to + * modify the helpers field at all. + */ struct string_list helpers; + unsigned approved:1, configured:1, quit:1, @@ -19,16 +219,52 @@ struct credential { #define CREDENTIAL_INIT { STRING_LIST_INIT_DUP } +/* Initialize a credential structure, setting all fields to empty. */ void credential_init(struct credential *); + +/** + * Free any resources associated with the credential structure, returning + * it to a pristine initialized state. + */ void credential_clear(struct credential *); +/** + * Instruct the credential subsystem to fill the username and + * password fields of the passed credential struct by first + * consulting helpers, then asking the user. After this function + * returns, the username and password fields of the credential are + * guaranteed to be non-NULL. If an error occurs, the function will + * die(). + */ void credential_fill(struct credential *); + +/** + * Inform the credential subsystem that the provided credentials + * were successfully used for authentication. This will cause the + * credential subsystem to notify any helpers of the approval, so + * that they may store the result to be used again. Any errors + * from helpers are ignored. + */ void credential_approve(struct credential *); + +/** + * Inform the credential subsystem that the provided credentials + * have been rejected. This will cause the credential subsystem to + * notify any helpers of the rejection (which allows them, for + * example, to purge the invalid credentials from storage). It + * will also free() the username and password fields of the + * credential and set them to NULL (readying the credential for + * another call to `credential_fill`). Any errors from helpers are + * ignored. + */ void credential_reject(struct credential *); int credential_read(struct credential *, FILE *); void credential_write(const struct credential *, FILE *); + +/* Parse a URL into broken-down credential fields. */ void credential_from_url(struct credential *, const char *url); + int credential_match(const struct credential *have, const struct credential *want); From patchwork Wed Nov 6 09:59:42 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Passaro via GitGitGadget X-Patchwork-Id: 11229903 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 84C22112B for ; Wed, 6 Nov 2019 10:00:11 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 62E39217F4 for ; Wed, 6 Nov 2019 10:00:11 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="BxKXGPTW" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731787AbfKFKAF (ORCPT ); Wed, 6 Nov 2019 05:00:05 -0500 Received: from mail-wr1-f54.google.com ([209.85.221.54]:44179 "EHLO mail-wr1-f54.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731730AbfKFKAE (ORCPT ); Wed, 6 Nov 2019 05:00:04 -0500 Received: by mail-wr1-f54.google.com with SMTP id f2so16051154wrs.11 for ; Wed, 06 Nov 2019 02:00:01 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=bj3ALgBq3/+aaQxmTGbDxl1ml3z4P2kveno+sRlrai8=; b=BxKXGPTWAeTyXptBqa19RSoDToqsX0tv5zewZT4frSLQLlXoAXHhNyIAefGl/IuV5a krYSe7ou9fu1y+qLpBxM2TI2bDIoSwCej5xs/2B12Dspr6Qy8GNeP2biXYEl+yaXzMW9 V3nqHiS1hK5fvjCTEla7Swqz2jB7fZgCtqyGSlMOigLBoYhfUtTyCLoWrcUyfFMAoiqE BXuCMPiIMTFmmbBRdESq0Ms2KirtW7+6hwDV9Natq8NwOJ2BF7m4jr4jx4EuTbesO2ZF hhN7fqffpOE0llpEjOmupkMrYo9nmzzqPwsXy5sJQIAhCqAjxmhlIjDW58ZAL0097+jR N3wQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=bj3ALgBq3/+aaQxmTGbDxl1ml3z4P2kveno+sRlrai8=; b=JAKR3Ac/QnwREOb9N8fnkqD0orHZpR67l3TWmfAUx6Mj0jhLR5OjPoVXRh+5JpHh/1 Xf/397sUl1zTQ87uYS4bkdTKBxOUAb3BwJ8khYDnrm1vaxE1xo6b/pWUV/Zu0pAmWNF6 1zOhOsVLtrHyGyzJSt+2o8keCkixwpJLH3IUamlPeIn6A8sq/n3OqLC1n7wBOjBGOcoZ OTD8jgXiBi8GU4njc4t6nCgNyFlF6gdaSIGOW6qEDJOYpUuC7clOWOeMaprq3yUTXZgl bZRKKbE7hOAzM1WjKHO5Z/xc/ngFtDsPeYfNOYWnj0DrssRvMTHHF1MGrVAxl0OOX8f1 ATfw== X-Gm-Message-State: APjAAAXTyGJ3YymgMlodJX6Mx1ei+OasmiU8nNDwbd8FbsXbTFAG1m5D FGD9yXc5bMW7um4wy731jQScg2oP X-Google-Smtp-Source: APXvYqzV+H2jAMQ6wamFVnNJ3/LPzHrMm7CSXp7MB7z3eucQEfhCqxGc1WgB3A+zmCjDCqwpVEd7mw== X-Received: by 2002:adf:fd4b:: with SMTP id h11mr1705789wrs.191.1573034399693; Wed, 06 Nov 2019 01:59:59 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id a15sm24535160wrw.10.2019.11.06.01.59.59 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 06 Nov 2019 01:59:59 -0800 (PST) Message-Id: <3d1e7e72efca06d18606b6f9dd8c3b6771dfde06.1573034387.git.gitgitgadget@gmail.com> In-Reply-To: References: From: "Heba Waly via GitGitGadget" Date: Wed, 06 Nov 2019 09:59:42 +0000 Subject: [PATCH v2 15/20] parse-options: move doc to parse-options.h Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Heba Waly , Junio C Hamano , Heba Waly Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Heba Waly Move the documentation from Documentation/technical/api-parse-options.txt to parse-options.h as it's easier for the developers to find the usage information beside the code instead of looking for it in another doc file. Documentation/technical/api-parse-options.txt is removed because the information it has is now redundant and it'll be hard to keep it up to date and synchronized with the documentation in the header file. Documentation/MyFirstContribution.txt now link to parse-options.h instead of Documentation/technical/api-parse-options.txt for details about parsing options. Signed-off-by: Heba Waly --- Documentation/MyFirstContribution.txt | 2 +- Documentation/technical/api-parse-options.txt | 313 ----------------- parse-options.h | 329 ++++++++++++++++++ 3 files changed, 330 insertions(+), 314 deletions(-) delete mode 100644 Documentation/technical/api-parse-options.txt diff --git a/Documentation/MyFirstContribution.txt b/Documentation/MyFirstContribution.txt index 5e9b808f5f..a2a91d92e2 100644 --- a/Documentation/MyFirstContribution.txt +++ b/Documentation/MyFirstContribution.txt @@ -487,7 +487,7 @@ Try and run `./bin-wrappers/git psuh -h`. Your command should crash at the end. That's because `-h` is a special case which your command should handle by printing usage. -Take a look at `Documentation/technical/api-parse-options.txt`. This is a handy +Take a look at `parse-options.h`. This is a handy tool for pulling out options you need to be able to handle, and it takes a usage string. diff --git a/Documentation/technical/api-parse-options.txt b/Documentation/technical/api-parse-options.txt deleted file mode 100644 index 2e2e7c10c6..0000000000 --- a/Documentation/technical/api-parse-options.txt +++ /dev/null @@ -1,313 +0,0 @@ -parse-options API -================= - -The parse-options API is used to parse and massage options in Git -and to provide a usage help with consistent look. - -Basics ------- - -The argument vector `argv[]` may usually contain mandatory or optional -'non-option arguments', e.g. a filename or a branch, and 'options'. -Options are optional arguments that start with a dash and -that allow to change the behavior of a command. - -* There are basically three types of options: - 'boolean' options, - options with (mandatory) 'arguments' and - options with 'optional arguments' - (i.e. a boolean option that can be adjusted). - -* There are basically two forms of options: - 'Short options' consist of one dash (`-`) and one alphanumeric - character. - 'Long options' begin with two dashes (`--`) and some - alphanumeric characters. - -* Options are case-sensitive. - Please define 'lower-case long options' only. - -The parse-options API allows: - -* 'stuck' and 'separate form' of options with arguments. - `-oArg` is stuck, `-o Arg` is separate form. - `--option=Arg` is stuck, `--option Arg` is separate form. - -* Long options may be 'abbreviated', as long as the abbreviation - is unambiguous. - -* Short options may be bundled, e.g. `-a -b` can be specified as `-ab`. - -* Boolean long options can be 'negated' (or 'unset') by prepending - `no-`, e.g. `--no-abbrev` instead of `--abbrev`. Conversely, - options that begin with `no-` can be 'negated' by removing it. - Other long options can be unset (e.g., set string to NULL, set - integer to 0) by prepending `no-`. - -* Options and non-option arguments can clearly be separated using the `--` - option, e.g. `-a -b --option -- --this-is-a-file` indicates that - `--this-is-a-file` must not be processed as an option. - -Steps to parse options ----------------------- - -. `#include "parse-options.h"` - -. define a NULL-terminated - `static const char * const builtin_foo_usage[]` array - containing alternative usage strings - -. define `builtin_foo_options` array as described below - in section 'Data Structure'. - -. in `cmd_foo(int argc, const char **argv, const char *prefix)` - call - - argc = parse_options(argc, argv, prefix, builtin_foo_options, builtin_foo_usage, flags); -+ -`parse_options()` will filter out the processed options of `argv[]` and leave the -non-option arguments in `argv[]`. -`argc` is updated appropriately because of the assignment. -+ -You can also pass NULL instead of a usage array as the fifth parameter of -parse_options(), to avoid displaying a help screen with usage info and -option list. This should only be done if necessary, e.g. to implement -a limited parser for only a subset of the options that needs to be run -before the full parser, which in turn shows the full help message. -+ -Flags are the bitwise-or of: - -`PARSE_OPT_KEEP_DASHDASH`:: - Keep the `--` that usually separates options from - non-option arguments. - -`PARSE_OPT_STOP_AT_NON_OPTION`:: - Usually the whole argument vector is massaged and reordered. - Using this flag, processing is stopped at the first non-option - argument. - -`PARSE_OPT_KEEP_ARGV0`:: - Keep the first argument, which contains the program name. It's - removed from argv[] by default. - -`PARSE_OPT_KEEP_UNKNOWN`:: - Keep unknown arguments instead of erroring out. This doesn't - work for all combinations of arguments as users might expect - it to do. E.g. if the first argument in `--unknown --known` - takes a value (which we can't know), the second one is - mistakenly interpreted as a known option. Similarly, if - `PARSE_OPT_STOP_AT_NON_OPTION` is set, the second argument in - `--unknown value` will be mistakenly interpreted as a - non-option, not as a value belonging to the unknown option, - the parser early. That's why parse_options() errors out if - both options are set. - -`PARSE_OPT_NO_INTERNAL_HELP`:: - By default, parse_options() handles `-h`, `--help` and - `--help-all` internally, by showing a help screen. This option - turns it off and allows one to add custom handlers for these - options, or to just leave them unknown. - -Data Structure --------------- - -The main data structure is an array of the `option` struct, -say `static struct option builtin_add_options[]`. -There are some macros to easily define options: - -`OPT__ABBREV(&int_var)`:: - Add `--abbrev[=]`. - -`OPT__COLOR(&int_var, description)`:: - Add `--color[=]` and `--no-color`. - -`OPT__DRY_RUN(&int_var, description)`:: - Add `-n, --dry-run`. - -`OPT__FORCE(&int_var, description)`:: - Add `-f, --force`. - -`OPT__QUIET(&int_var, description)`:: - Add `-q, --quiet`. - -`OPT__VERBOSE(&int_var, description)`:: - Add `-v, --verbose`. - -`OPT_GROUP(description)`:: - Start an option group. `description` is a short string that - describes the group or an empty string. - Start the description with an upper-case letter. - -`OPT_BOOL(short, long, &int_var, description)`:: - Introduce a boolean option. `int_var` is set to one with - `--option` and set to zero with `--no-option`. - -`OPT_COUNTUP(short, long, &int_var, description)`:: - Introduce a count-up option. - Each use of `--option` increments `int_var`, starting from zero - (even if initially negative), and `--no-option` resets it to - zero. To determine if `--option` or `--no-option` was encountered at - all, initialize `int_var` to a negative value, and if it is still - negative after parse_options(), then neither `--option` nor - `--no-option` was seen. - -`OPT_BIT(short, long, &int_var, description, mask)`:: - Introduce a boolean option. - If used, `int_var` is bitwise-ored with `mask`. - -`OPT_NEGBIT(short, long, &int_var, description, mask)`:: - Introduce a boolean option. - If used, `int_var` is bitwise-anded with the inverted `mask`. - -`OPT_SET_INT(short, long, &int_var, description, integer)`:: - Introduce an integer option. - `int_var` is set to `integer` with `--option`, and - reset to zero with `--no-option`. - -`OPT_STRING(short, long, &str_var, arg_str, description)`:: - Introduce an option with string argument. - The string argument is put into `str_var`. - -`OPT_STRING_LIST(short, long, &struct string_list, arg_str, description)`:: - Introduce an option with string argument. - The string argument is stored as an element in `string_list`. - Use of `--no-option` will clear the list of preceding values. - -`OPT_INTEGER(short, long, &int_var, description)`:: - Introduce an option with integer argument. - The integer is put into `int_var`. - -`OPT_MAGNITUDE(short, long, &unsigned_long_var, description)`:: - Introduce an option with a size argument. The argument must be a - non-negative integer and may include a suffix of 'k', 'm' or 'g' to - scale the provided value by 1024, 1024^2 or 1024^3 respectively. - The scaled value is put into `unsigned_long_var`. - -`OPT_EXPIRY_DATE(short, long, ×tamp_t_var, description)`:: - Introduce an option with expiry date argument, see `parse_expiry_date()`. - The timestamp is put into `timestamp_t_var`. - -`OPT_CALLBACK(short, long, &var, arg_str, description, func_ptr)`:: - Introduce an option with argument. - The argument will be fed into the function given by `func_ptr` - and the result will be put into `var`. - See 'Option Callbacks' below for a more elaborate description. - -`OPT_FILENAME(short, long, &var, description)`:: - Introduce an option with a filename argument. - The filename will be prefixed by passing the filename along with - the prefix argument of `parse_options()` to `prefix_filename()`. - -`OPT_ARGUMENT(long, &int_var, description)`:: - Introduce a long-option argument that will be kept in `argv[]`. - If this option was seen, `int_var` will be set to one (except - if a `NULL` pointer was passed). - -`OPT_NUMBER_CALLBACK(&var, description, func_ptr)`:: - Recognize numerical options like -123 and feed the integer as - if it was an argument to the function given by `func_ptr`. - The result will be put into `var`. There can be only one such - option definition. It cannot be negated and it takes no - arguments. Short options that happen to be digits take - precedence over it. - -`OPT_COLOR_FLAG(short, long, &int_var, description)`:: - Introduce an option that takes an optional argument that can - have one of three values: "always", "never", or "auto". If the - argument is not given, it defaults to "always". The `--no-` form - works like `--long=never`; it cannot take an argument. If - "always", set `int_var` to 1; if "never", set `int_var` to 0; if - "auto", set `int_var` to 1 if stdout is a tty or a pager, - 0 otherwise. - -`OPT_NOOP_NOARG(short, long)`:: - Introduce an option that has no effect and takes no arguments. - Use it to hide deprecated options that are still to be recognized - and ignored silently. - -`OPT_PASSTHRU(short, long, &char_var, arg_str, description, flags)`:: - Introduce an option that will be reconstructed into a char* string, - which must be initialized to NULL. This is useful when you need to - pass the command-line option to another command. Any previous value - will be overwritten, so this should only be used for options where - the last one specified on the command line wins. - -`OPT_PASSTHRU_ARGV(short, long, &argv_array_var, arg_str, description, flags)`:: - Introduce an option where all instances of it on the command-line will - be reconstructed into an argv_array. This is useful when you need to - pass the command-line option, which can be specified multiple times, - to another command. - -`OPT_CMDMODE(short, long, &int_var, description, enum_val)`:: - Define an "operation mode" option, only one of which in the same - group of "operating mode" options that share the same `int_var` - can be given by the user. `enum_val` is set to `int_var` when the - option is used, but an error is reported if other "operating mode" - option has already set its value to the same `int_var`. - - -The last element of the array must be `OPT_END()`. - -If not stated otherwise, interpret the arguments as follows: - -* `short` is a character for the short option - (e.g. `'e'` for `-e`, use `0` to omit), - -* `long` is a string for the long option - (e.g. `"example"` for `--example`, use `NULL` to omit), - -* `int_var` is an integer variable, - -* `str_var` is a string variable (`char *`), - -* `arg_str` is the string that is shown as argument - (e.g. `"branch"` will result in ``). - If set to `NULL`, three dots (`...`) will be displayed. - -* `description` is a short string to describe the effect of the option. - It shall begin with a lower-case letter and a full stop (`.`) shall be - omitted at the end. - -Option Callbacks ----------------- - -The function must be defined in this form: - - int func(const struct option *opt, const char *arg, int unset) - -The callback mechanism is as follows: - -* Inside `func`, the only interesting member of the structure - given by `opt` is the void pointer `opt->value`. - `*opt->value` will be the value that is saved into `var`, if you - use `OPT_CALLBACK()`. - For example, do `*(unsigned long *)opt->value = 42;` to get 42 - into an `unsigned long` variable. - -* Return value `0` indicates success and non-zero return - value will invoke `usage_with_options()` and, thus, die. - -* If the user negates the option, `arg` is `NULL` and `unset` is 1. - -Sophisticated option parsing ----------------------------- - -If you need, for example, option callbacks with optional arguments -or without arguments at all, or if you need other special cases, -that are not handled by the macros above, you need to specify the -members of the `option` structure manually. - -This is not covered in this document, but well documented -in `parse-options.h` itself. - -Examples --------- - -See `test-parse-options.c` and -`builtin/add.c`, -`builtin/clone.c`, -`builtin/commit.c`, -`builtin/fetch.c`, -`builtin/fsck.c`, -`builtin/rm.c` -for real-world examples. diff --git a/parse-options.h b/parse-options.h index 38a33a087e..d71a3baa48 100644 --- a/parse-options.h +++ b/parse-options.h @@ -1,6 +1,103 @@ #ifndef PARSE_OPTIONS_H #define PARSE_OPTIONS_H +/** + * The parse-options API is used to parse and massage options in Git + * and to provide a usage help with consistent look. + * + * Basics + * ------ + * + * The argument vector `argv[]` may usually contain mandatory or optional + * 'non-option arguments', e.g. a filename or a branch, and 'options'. + * Options are optional arguments that start with a dash and + * that allow to change the behavior of a command. + * + * - There are basically three types of options: + * 'boolean' options, + * options with (mandatory) 'arguments' and + * options with 'optional arguments' + * (i.e. a boolean option that can be adjusted). + * + * - There are basically two forms of options: + * 'Short options' consist of one dash (`-`) and one alphanumeric + * character. + * 'Long options' begin with two dashes (`--`) and some + * alphanumeric characters. + * + * - Options are case-sensitive. + * Please define 'lower-case long options' only. + * + * The parse-options API allows: + * + * - 'stuck' and 'separate form' of options with arguments. + * `-oArg` is stuck, `-o Arg` is separate form. + * `--option=Arg` is stuck, `--option Arg` is separate form. + * + * - Long options may be 'abbreviated', as long as the abbreviation + * is unambiguous. + * + * - Short options may be bundled, e.g. `-a -b` can be specified as `-ab`. + * + * - Boolean long options can be 'negated' (or 'unset') by prepending + * `no-`, e.g. `--no-abbrev` instead of `--abbrev`. Conversely, + * options that begin with `no-` can be 'negated' by removing it. + * Other long options can be unset (e.g., set string to NULL, set + * integer to 0) by prepending `no-`. + * + * - Options and non-option arguments can clearly be separated using the `--` + * option, e.g. `-a -b --option -- --this-is-a-file` indicates that + * `--this-is-a-file` must not be processed as an option. + * + * Steps to parse options + * ---------------------- + * + * - `#include "parse-options.h"` + * + * - define a NULL-terminated + * `static const char * const builtin_foo_usage[]` array + * containing alternative usage strings + * + * - define `builtin_foo_options` array as described below + * in section 'Data Structure'. + * + * - in `cmd_foo(int argc, const char **argv, const char *prefix)` + * call + * + * argc = parse_options(argc, argv, prefix, builtin_foo_options, builtin_foo_usage, flags); + * + * `parse_options()` will filter out the processed options of `argv[]` and leave the + * non-option arguments in `argv[]`. + * `argc` is updated appropriately because of the assignment. + * + * You can also pass NULL instead of a usage array as the fifth parameter of + * parse_options(), to avoid displaying a help screen with usage info and + * option list. This should only be done if necessary, e.g. to implement + * a limited parser for only a subset of the options that needs to be run + * before the full parser, which in turn shows the full help message. + * + * Sophisticated option parsing + * ---------------------------- + * + * If you need, for example, option callbacks with optional arguments + * or without arguments at all, or if you need other special cases, + * that are not handled by the macros here, you need to specify the + * members of the `option` structure manually. + * + * Examples + * -------- + * + * See `test-parse-options.c` and + * `builtin/add.c`, + * `builtin/clone.c`, + * `builtin/commit.c`, + * `builtin/fetch.c`, + * `builtin/fsck.c`, + * `builtin/rm.c` + * for real-world examples. + * + */ + enum parse_opt_type { /* special types */ OPTION_END, @@ -25,11 +122,47 @@ enum parse_opt_type { }; enum parse_opt_flags { + + /** + * Keep the `--` that usually separates options from non-option arguments. + */ PARSE_OPT_KEEP_DASHDASH = 1, + + /** + * Usually the whole argument vector is massaged and reordered. + * Using this flag, processing is stopped at the first non-option + * argument. + */ PARSE_OPT_STOP_AT_NON_OPTION = 2, + + /** + * Keep the first argument, which contains the program name. It's + * removed from argv[] by default. + */ PARSE_OPT_KEEP_ARGV0 = 4, + + /** + * Keep unknown arguments instead of erroring out. This doesn't + * work for all combinations of arguments as users might expect + * it to do. E.g. if the first argument in `--unknown --known` + * takes a value (which we can't know), the second one is + * mistakenly interpreted as a known option. Similarly, if + * `PARSE_OPT_STOP_AT_NON_OPTION` is set, the second argument in + * `--unknown value` will be mistakenly interpreted as a + * non-option, not as a value belonging to the unknown option, + * the parser early. That's why parse_options() errors out if + * both options are set. + */ PARSE_OPT_KEEP_UNKNOWN = 8, + + /** + * By default, parse_options() handles `-h`, `--help` and + * `--help-all` internally, by showing a help screen. This option + * turns it off and allows one to add custom handlers for these + * options, or to just leave them unknown. + */ PARSE_OPT_NO_INTERNAL_HELP = 16, + PARSE_OPT_ONE_SHOT = 32 }; @@ -56,6 +189,30 @@ enum parse_opt_result { }; struct option; + +/** + * Option Callbacks + * ---------------- + * + * The function must be defined in this form: + * + * int func(const struct option *opt, const char *arg, int unset) + * + * The callback mechanism is as follows: + * + * - Inside `func`, the only interesting member of the structure + * given by `opt` is the void pointer `opt->value`. + * `*opt->value` will be the value that is saved into `var`, if you + * use `OPT_CALLBACK()`. + * For example, do `*(unsigned long *)opt->value = 42;` to get 42 + * into an `unsigned long` variable. + * + * - Return value `0` indicates success and non-zero return + * value will invoke `usage_with_options()` and, thus, die. + * + * - If the user negates the option, `arg` is `NULL` and `unset` is 1. + * + */ typedef int parse_opt_cb(const struct option *, const char *arg, int unset); struct parse_opt_ctx_t; @@ -137,6 +294,36 @@ struct option { intptr_t extra; }; +/** + * Data Structure + * -------------- + * + * The main data structure is an array of the `option` struct, say + * `static struct option builtin_add_options[]`. + * The following macros can be used to easily define options. + * The last element of the array must be `OPT_END()`. + * + * If not stated otherwise, interpret the arguments as follows: + * + * - `short` is a character for the short option + * (e.g. `'e'` for `-e`, use `0` to omit), + * + * - `long` is a string for the long option + * (e.g. `"example"` for `--example`, use `NULL` to omit), + * + * - `int_var` is an integer variable, + * + * - `str_var` is a string variable (`char *`), + * + * - `arg_str` is the string that is shown as argument + * (e.g. `"branch"` will result in ``). + * If set to `NULL`, three dots (`...`) will be displayed. + * + * - `description` is a short string to describe the effect of the option. + * It shall begin with a lower-case letter and a full stop (`.`) shall be + * omitted at the end. + */ + #define OPT_BIT_F(s, l, v, h, b, f) { OPTION_BIT, (s), (l), (v), NULL, (h), \ PARSE_OPT_NOARG|(f), NULL, (b) } #define OPT_COUNTUP_F(s, l, v, h, f) { OPTION_COUNTUP, (s), (l), (v), NULL, \ @@ -150,44 +337,158 @@ struct option { #define OPT_INTEGER_F(s, l, v, h, f) { OPTION_INTEGER, (s), (l), (v), N_("n"), (h), (f) } #define OPT_END() { OPTION_END } + +/** + * Introduce a long-option argument that will be kept in `argv[]`. + * If this option was seen, `int_var` will be set to one (except + * if a `NULL` pointer was passed). + */ #define OPT_ARGUMENT(l, v, h) { OPTION_ARGUMENT, 0, (l), (v), NULL, \ (h), PARSE_OPT_NOARG, NULL, 1 } + +/** + * Start an option group. `description` is a short string that describes the + * group or an empty string. Start the description with an upper-case letter. + */ #define OPT_GROUP(h) { OPTION_GROUP, 0, NULL, NULL, NULL, (h) } + +/** + * Introduce a boolean option. If used, `int_var` is bitwise-ored with `mask`. + */ #define OPT_BIT(s, l, v, h, b) OPT_BIT_F(s, l, v, h, b, 0) + #define OPT_BITOP(s, l, v, h, set, clear) { OPTION_BITOP, (s), (l), (v), NULL, (h), \ PARSE_OPT_NOARG|PARSE_OPT_NONEG, NULL, \ (set), NULL, (clear) } + +/** + * Introduce a boolean option. If used, `int_var` is bitwise-anded with the + * inverted `mask`. + */ #define OPT_NEGBIT(s, l, v, h, b) { OPTION_NEGBIT, (s), (l), (v), NULL, \ (h), PARSE_OPT_NOARG, NULL, (b) } + +/** + * Introduce a count-up option. + * Each use of `--option` increments `int_var`, starting from zero + * (even if initially negative), and `--no-option` resets it to + * zero. To determine if `--option` or `--no-option` was encountered at + * all, initialize `int_var` to a negative value, and if it is still + * negative after parse_options(), then neither `--option` nor + * `--no-option` was seen. + */ #define OPT_COUNTUP(s, l, v, h) OPT_COUNTUP_F(s, l, v, h, 0) + +/** + * Introduce an integer option. `int_var` is set to `integer` with `--option`, + * and reset to zero with `--no-option`. + */ #define OPT_SET_INT(s, l, v, h, i) OPT_SET_INT_F(s, l, v, h, i, 0) + +/** + * Introduce a boolean option. `int_var` is set to one with `--option` and set + * to zero with `--no-option`. + */ #define OPT_BOOL(s, l, v, h) OPT_BOOL_F(s, l, v, h, 0) + #define OPT_HIDDEN_BOOL(s, l, v, h) { OPTION_SET_INT, (s), (l), (v), NULL, \ (h), PARSE_OPT_NOARG | PARSE_OPT_HIDDEN, NULL, 1} + +/** + * Define an "operation mode" option, only one of which in the same + * group of "operating mode" options that share the same `int_var` + * can be given by the user. `enum_val` is set to `int_var` when the + * option is used, but an error is reported if other "operating mode" + * option has already set its value to the same `int_var`. + */ #define OPT_CMDMODE(s, l, v, h, i) { OPTION_CMDMODE, (s), (l), (v), NULL, \ (h), PARSE_OPT_NOARG|PARSE_OPT_NONEG, NULL, (i) } + +/** + * Introduce an option with integer argument. The integer is put into `int_var`. + */ #define OPT_INTEGER(s, l, v, h) OPT_INTEGER_F(s, l, v, h, 0) + +/** + * Introduce an option with a size argument. The argument must be a + * non-negative integer and may include a suffix of 'k', 'm' or 'g' to + * scale the provided value by 1024, 1024^2 or 1024^3 respectively. + * The scaled value is put into `unsigned_long_var`. + */ #define OPT_MAGNITUDE(s, l, v, h) { OPTION_MAGNITUDE, (s), (l), (v), \ N_("n"), (h), PARSE_OPT_NONEG } + +/** + * Introduce an option with string argument. The string argument is put + * into `str_var`. + */ #define OPT_STRING(s, l, v, a, h) OPT_STRING_F(s, l, v, a, h, 0) + +/** + * Introduce an option with string argument. + * The string argument is stored as an element in `string_list`. + * Use of `--no-option` will clear the list of preceding values. + */ #define OPT_STRING_LIST(s, l, v, a, h) \ { OPTION_CALLBACK, (s), (l), (v), (a), \ (h), 0, &parse_opt_string_list } + #define OPT_UYN(s, l, v, h) { OPTION_CALLBACK, (s), (l), (v), NULL, \ (h), PARSE_OPT_NOARG, &parse_opt_tertiary } + +/** + * Introduce an option with expiry date argument, see `parse_expiry_date()`. + * The timestamp is put into `timestamp_t_var`. + */ #define OPT_EXPIRY_DATE(s, l, v, h) \ { OPTION_CALLBACK, (s), (l), (v), N_("expiry-date"),(h), 0, \ parse_opt_expiry_date_cb } + +/** + * Introduce an option with argument. + * The argument will be fed into the function given by `func_ptr` + * and the result will be put into `var`. + */ #define OPT_CALLBACK(s, l, v, a, h, f) OPT_CALLBACK_F(s, l, v, a, h, 0, f) + +/** + * Recognize numerical options like -123 and feed the integer as + * if it was an argument to the function given by `func_ptr`. + * The result will be put into `var`. There can be only one such + * option definition. It cannot be negated and it takes no + * arguments. Short options that happen to be digits take + * precedence over it. + */ #define OPT_NUMBER_CALLBACK(v, h, f) \ { OPTION_NUMBER, 0, NULL, (v), NULL, (h), \ PARSE_OPT_NOARG | PARSE_OPT_NONEG, (f) } + +/** + * Introduce an option with a filename argument. + * The filename will be prefixed by passing the filename along with + * the prefix argument of `parse_options()` to `prefix_filename()`. + */ #define OPT_FILENAME(s, l, v, h) { OPTION_FILENAME, (s), (l), (v), \ N_("file"), (h) } + +/** + * Introduce an option that takes an optional argument that can + * have one of three values: "always", "never", or "auto". If the + * argument is not given, it defaults to "always". The `--no-` form + * works like `--long=never`; it cannot take an argument. If + * "always", set `int_var` to 1; if "never", set `int_var` to 0; if + * "auto", set `int_var` to 1 if stdout is a tty or a pager, + * 0 otherwise. + */ #define OPT_COLOR_FLAG(s, l, v, h) \ { OPTION_CALLBACK, (s), (l), (v), N_("when"), (h), PARSE_OPT_OPTARG, \ parse_opt_color_flag_cb, (intptr_t)"always" } +/** + * Introduce an option that has no effect and takes no arguments. + * Use it to hide deprecated options that are still to be recognized + * and ignored silently. + */ #define OPT_NOOP_NOARG(s, l) \ { OPTION_CALLBACK, (s), (l), NULL, NULL, \ N_("no-op (backward compatibility)"), \ @@ -296,24 +597,52 @@ int parse_opt_noop_cb(const struct option *, const char *, int); enum parse_opt_result parse_opt_unknown_cb(struct parse_opt_ctx_t *ctx, const struct option *, const char *, int); + +/** + * Introduce an option that will be reconstructed into a char* string, + * which must be initialized to NULL. This is useful when you need to + * pass the command-line option to another command. Any previous value + * will be overwritten, so this should only be used for options where + * the last one specified on the command line wins. + */ int parse_opt_passthru(const struct option *, const char *, int); + +/** + * Introduce an option where all instances of it on the command-line will + * be reconstructed into an argv_array. This is useful when you need to + * pass the command-line option, which can be specified multiple times, + * to another command. + */ int parse_opt_passthru_argv(const struct option *, const char *, int); +/* Add `-v, --verbose`. */ #define OPT__VERBOSE(var, h) OPT_COUNTUP('v', "verbose", (var), (h)) + +/* Add `-q, --quiet`. */ #define OPT__QUIET(var, h) OPT_COUNTUP('q', "quiet", (var), (h)) + #define OPT__VERBOSITY(var) \ { OPTION_CALLBACK, 'v', "verbose", (var), NULL, N_("be more verbose"), \ PARSE_OPT_NOARG, &parse_opt_verbosity_cb, 0 }, \ { OPTION_CALLBACK, 'q', "quiet", (var), NULL, N_("be more quiet"), \ PARSE_OPT_NOARG, &parse_opt_verbosity_cb, 0 } + +/* Add `-n, --dry-run`. */ #define OPT__DRY_RUN(var, h) OPT_BOOL('n', "dry-run", (var), (h)) + +/* Add `-f, --force`. */ #define OPT__FORCE(var, h, f) OPT_COUNTUP_F('f', "force", (var), (h), (f)) + +/* Add `--abbrev[=]`. */ #define OPT__ABBREV(var) \ { OPTION_CALLBACK, 0, "abbrev", (var), N_("n"), \ N_("use digits to display SHA-1s"), \ PARSE_OPT_OPTARG, &parse_opt_abbrev_cb, 0 } + +/* Add `--color[=]` and `--no-color`. */ #define OPT__COLOR(var, h) \ OPT_COLOR_FLAG(0, "color", (var), (h)) + #define OPT_COLUMN(s, l, v, h) \ { OPTION_CALLBACK, (s), (l), (v), N_("style"), (h), PARSE_OPT_OPTARG, parseopt_column_callback } #define OPT_PASSTHRU(s, l, v, a, h, f) \ From patchwork Wed Nov 6 09:59:43 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Passaro via GitGitGadget X-Patchwork-Id: 11229901 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 595001864 for ; Wed, 6 Nov 2019 10:00:11 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 2D85A217F4 for ; Wed, 6 Nov 2019 10:00:11 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="ihD6dbHe" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731801AbfKFKAI (ORCPT ); Wed, 6 Nov 2019 05:00:08 -0500 Received: from mail-wr1-f47.google.com ([209.85.221.47]:37751 "EHLO mail-wr1-f47.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731733AbfKFKAF (ORCPT ); Wed, 6 Nov 2019 05:00:05 -0500 Received: by mail-wr1-f47.google.com with SMTP id t1so19027638wrv.4 for ; Wed, 06 Nov 2019 02:00:02 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=IIawSvbKKpQ9HAkTGl9PptIc06PQYjhGBX9042ZZzA4=; b=ihD6dbHe9cvjsXdEGfnhIhovSjMb4WOj7NBrOkIoHkQXm/Nhd2/NYSbtezyYWputxX DOt0qxKLkk8XyE4rKGAz2eB+J3rE+vja7/vicSeUx+8qdUxJ6WqXgzJmMiWBkHXPsMEF m7OPEtmBOiMVOdmtjlTZpkClJcMpnogh7c4Q02U293XXW3myd+MstPYXmOt9UqH+VDLN YMyv7s7IrXVSk5HYnLg3Kp8QO1MbBZue/p5gcmyAPnZVtw2t3SzjRe0q6slZ0WGWGd/6 KVErK3wKaH3SDxmg72hNVga6MvjzMPzpoCWLpLeNND9A3WHlEbtK5Xa6/q6jwdvMKYyi Eqpw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=IIawSvbKKpQ9HAkTGl9PptIc06PQYjhGBX9042ZZzA4=; b=pHEcqe00e/x3X2d9A/dOVeZDhHaYHTs/oni1ICYijEuRV3dq8zJDMCMZw/E5D9jfiS jAW7dZZWbPLFun3nnCfCSIGbStbxx42RmdX8HKs+LLqi6jqyziN98Pu7Ih0r7s4YX+Gu nbkTvq+q+Oxa4re6SqGMaP0EjZg/3hPYL4MmmcS8CV+mMPsTwUhoqvUm6Q8osvuspInq txVSTkj0TaIEeFYxCMjA7oh1zoIXJ89jdlHPPD7YUy4G2ckueljIsj0oqqtaDuL+omqu UDpyq1oGqrJENqv5Hhqh7vX0QD/yj7XUr0rByBP6rdK4urXtm9hCY1xhr4MlrLUq8egK pB/A== X-Gm-Message-State: APjAAAXdT9zd3JDn3/AwL4oYjP3fhEm+w1euwy/Sp7iSDB0GOENgs/65 4VhhelTIdFryucG1TmTyhEdhXG58 X-Google-Smtp-Source: APXvYqz4633Vo7VxB3hrLQPI1Zs1VI0+nKEvHMmSvqbUB2xTHFFbi4cyCzT4siZ3QwazuDswo9rfEw== X-Received: by 2002:a5d:5262:: with SMTP id l2mr1783098wrc.113.1573034400405; Wed, 06 Nov 2019 02:00:00 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id 5sm1848936wmk.48.2019.11.06.01.59.59 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 06 Nov 2019 02:00:00 -0800 (PST) Message-Id: <5d93cab5d9c3bfebc6f0a6391020e1d40de62c6a.1573034387.git.gitgitgadget@gmail.com> In-Reply-To: References: From: "Heba Waly via GitGitGadget" Date: Wed, 06 Nov 2019 09:59:43 +0000 Subject: [PATCH v2 16/20] run-command: move doc to run-command.h Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Heba Waly , Junio C Hamano , Heba Waly Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Heba Waly Move the documentation from Documentation/technical/api-run-command.txt to run-command.h as it's easier for the developers to find the usage information beside the code instead of looking for it in another doc file. Documentation/technical/api-run-command.txt is removed because the information it has is now redundant and it'll be hard to keep it up to date and synchronized with the documentation in the header file. Signed-off-by: Heba Waly --- Documentation/technical/api-run-command.txt | 264 -------------------- run-command.h | 254 ++++++++++++++++++- 2 files changed, 246 insertions(+), 272 deletions(-) delete mode 100644 Documentation/technical/api-run-command.txt diff --git a/Documentation/technical/api-run-command.txt b/Documentation/technical/api-run-command.txt deleted file mode 100644 index 8bf3e37f53..0000000000 --- a/Documentation/technical/api-run-command.txt +++ /dev/null @@ -1,264 +0,0 @@ -run-command API -=============== - -The run-command API offers a versatile tool to run sub-processes with -redirected input and output as well as with a modified environment -and an alternate current directory. - -A similar API offers the capability to run a function asynchronously, -which is primarily used to capture the output that the function -produces in the caller in order to process it. - - -Functions ---------- - -`child_process_init`:: - - Initialize a struct child_process variable. - -`start_command`:: - - Start a sub-process. Takes a pointer to a `struct child_process` - that specifies the details and returns pipe FDs (if requested). - See below for details. - -`finish_command`:: - - Wait for the completion of a sub-process that was started with - start_command(). - -`run_command`:: - - A convenience function that encapsulates a sequence of - start_command() followed by finish_command(). Takes a pointer - to a `struct child_process` that specifies the details. - -`run_command_v_opt`, `run_command_v_opt_cd_env`:: - - Convenience functions that encapsulate a sequence of - start_command() followed by finish_command(). The argument argv - specifies the program and its arguments. The argument opt is zero - or more of the flags `RUN_COMMAND_NO_STDIN`, `RUN_GIT_CMD`, - `RUN_COMMAND_STDOUT_TO_STDERR`, or `RUN_SILENT_EXEC_FAILURE` - that correspond to the members .no_stdin, .git_cmd, - .stdout_to_stderr, .silent_exec_failure of `struct child_process`. - The argument dir corresponds the member .dir. The argument env - corresponds to the member .env. - -`child_process_clear`:: - - Release the memory associated with the struct child_process. - Most users of the run-command API don't need to call this - function explicitly because `start_command` invokes it on - failure and `finish_command` calls it automatically already. - -The functions above do the following: - -. If a system call failed, errno is set and -1 is returned. A diagnostic - is printed. - -. If the program was not found, then -1 is returned and errno is set to - ENOENT; a diagnostic is printed only if .silent_exec_failure is 0. - -. Otherwise, the program is run. If it terminates regularly, its exit - code is returned. No diagnostic is printed, even if the exit code is - non-zero. - -. If the program terminated due to a signal, then the return value is the - signal number + 128, ie. the same value that a POSIX shell's $? would - report. A diagnostic is printed. - - -`start_async`:: - - Run a function asynchronously. Takes a pointer to a `struct - async` that specifies the details and returns a set of pipe FDs - for communication with the function. See below for details. - -`finish_async`:: - - Wait for the completion of an asynchronous function that was - started with start_async(). - -`run_hook`:: - - Run a hook. - The first argument is a pathname to an index file, or NULL - if the hook uses the default index file or no index is needed. - The second argument is the name of the hook. - The further arguments correspond to the hook arguments. - The last argument has to be NULL to terminate the arguments list. - If the hook does not exist or is not executable, the return - value will be zero. - If it is executable, the hook will be executed and the exit - status of the hook is returned. - On execution, .stdout_to_stderr and .no_stdin will be set. - (See below.) - - -Data structures ---------------- - -* `struct child_process` - -This describes the arguments, redirections, and environment of a -command to run in a sub-process. - -The caller: - -1. allocates and clears (using child_process_init() or - CHILD_PROCESS_INIT) a struct child_process variable; -2. initializes the members; -3. calls start_command(); -4. processes the data; -5. closes file descriptors (if necessary; see below); -6. calls finish_command(). - -The .argv member is set up as an array of string pointers (NULL -terminated), of which .argv[0] is the program name to run (usually -without a path). If the command to run is a git command, set argv[0] to -the command name without the 'git-' prefix and set .git_cmd = 1. - -Note that the ownership of the memory pointed to by .argv stays with the -caller, but it should survive until `finish_command` completes. If the -.argv member is NULL, `start_command` will point it at the .args -`argv_array` (so you may use one or the other, but you must use exactly -one). The memory in .args will be cleaned up automatically during -`finish_command` (or during `start_command` when it is unsuccessful). - -The members .in, .out, .err are used to redirect stdin, stdout, -stderr as follows: - -. Specify 0 to request no special redirection. No new file descriptor - is allocated. The child process simply inherits the channel from the - parent. - -. Specify -1 to have a pipe allocated; start_command() replaces -1 - by the pipe FD in the following way: - - .in: Returns the writable pipe end into which the caller writes; - the readable end of the pipe becomes the child's stdin. - - .out, .err: Returns the readable pipe end from which the caller - reads; the writable end of the pipe end becomes child's - stdout/stderr. - - The caller of start_command() must close the so returned FDs - after it has completed reading from/writing to it! - -. Specify a file descriptor > 0 to be used by the child: - - .in: The FD must be readable; it becomes child's stdin. - .out: The FD must be writable; it becomes child's stdout. - .err: The FD must be writable; it becomes child's stderr. - - The specified FD is closed by start_command(), even if it fails to - run the sub-process! - -. Special forms of redirection are available by setting these members - to 1: - - .no_stdin, .no_stdout, .no_stderr: The respective channel is - redirected to /dev/null. - - .stdout_to_stderr: stdout of the child is redirected to its - stderr. This happens after stderr is itself redirected. - So stdout will follow stderr to wherever it is - redirected. - -To modify the environment of the sub-process, specify an array of -string pointers (NULL terminated) in .env: - -. If the string is of the form "VAR=value", i.e. it contains '=' - the variable is added to the child process's environment. - -. If the string does not contain '=', it names an environment - variable that will be removed from the child process's environment. - -If the .env member is NULL, `start_command` will point it at the -.env_array `argv_array` (so you may use one or the other, but not both). -The memory in .env_array will be cleaned up automatically during -`finish_command` (or during `start_command` when it is unsuccessful). - -To specify a new initial working directory for the sub-process, -specify it in the .dir member. - -If the program cannot be found, the functions return -1 and set -errno to ENOENT. Normally, an error message is printed, but if -.silent_exec_failure is set to 1, no message is printed for this -special error condition. - - -* `struct async` - -This describes a function to run asynchronously, whose purpose is -to produce output that the caller reads. - -The caller: - -1. allocates and clears (memset(&asy, 0, sizeof(asy));) a - struct async variable; -2. initializes .proc and .data; -3. calls start_async(); -4. processes communicates with proc through .in and .out; -5. closes .in and .out; -6. calls finish_async(). - -The members .in, .out are used to provide a set of fd's for -communication between the caller and the callee as follows: - -. Specify 0 to have no file descriptor passed. The callee will - receive -1 in the corresponding argument. - -. Specify < 0 to have a pipe allocated; start_async() replaces - with the pipe FD in the following way: - - .in: Returns the writable pipe end into which the caller - writes; the readable end of the pipe becomes the function's - in argument. - - .out: Returns the readable pipe end from which the caller - reads; the writable end of the pipe becomes the function's - out argument. - - The caller of start_async() must close the returned FDs after it - has completed reading from/writing from them. - -. Specify a file descriptor > 0 to be used by the function: - - .in: The FD must be readable; it becomes the function's in. - .out: The FD must be writable; it becomes the function's out. - - The specified FD is closed by start_async(), even if it fails to - run the function. - -The function pointer in .proc has the following signature: - - int proc(int in, int out, void *data); - -. in, out specifies a set of file descriptors to which the function - must read/write the data that it needs/produces. The function - *must* close these descriptors before it returns. A descriptor - may be -1 if the caller did not configure a descriptor for that - direction. - -. data is the value that the caller has specified in the .data member - of struct async. - -. The return value of the function is 0 on success and non-zero - on failure. If the function indicates failure, finish_async() will - report failure as well. - - -There are serious restrictions on what the asynchronous function can do -because this facility is implemented by a thread in the same address -space on most platforms (when pthreads is available), but by a pipe to -a forked process otherwise: - -. It cannot change the program's state (global variables, environment, - etc.) in a way that the caller notices; in other words, .in and .out - are the only communication channels to the caller. - -. It must not change the program's state that the caller of the - facility also uses. diff --git a/run-command.h b/run-command.h index f769e03f01..e7d3aa63ca 100644 --- a/run-command.h +++ b/run-command.h @@ -5,8 +5,60 @@ #include "argv-array.h" +/** + * The run-command API offers a versatile tool to run sub-processes with + * redirected input and output as well as with a modified environment + * and an alternate current directory. + * + * A similar API offers the capability to run a function asynchronously, + * which is primarily used to capture the output that the function + * produces in the caller in order to process it. + */ + + +/** + * This describes the arguments, redirections, and environment of a + * command to run in a sub-process. + * + * The caller: + * + * 1. allocates and clears (using child_process_init() or + * CHILD_PROCESS_INIT) a struct child_process variable; + * 2. initializes the members; + * 3. calls start_command(); + * 4. processes the data; + * 5. closes file descriptors (if necessary; see below); + * 6. calls finish_command(). + * + * Special forms of redirection are available by setting these members + * to 1: + * + * .no_stdin, .no_stdout, .no_stderr: The respective channel is + * redirected to /dev/null. + * + * .stdout_to_stderr: stdout of the child is redirected to its + * stderr. This happens after stderr is itself redirected. + * So stdout will follow stderr to wherever it is + * redirected. + */ struct child_process { - const char **argv; + + /** + * The .argv member is set up as an array of string pointers (NULL + * terminated), of which .argv[0] is the program name to run (usually + * without a path). If the command to run is a git command, set argv[0] to + * the command name without the 'git-' prefix and set .git_cmd = 1. + * + * Note that the ownership of the memory pointed to by .argv stays with the + * caller, but it should survive until `finish_command` completes. If the + * .argv member is NULL, `start_command` will point it at the .args + * `argv_array` (so you may use one or the other, but you must use exactly + * one). The memory in .args will be cleaned up automatically during + * `finish_command` (or during `start_command` when it is unsuccessful). + * + */ + const char **argv; + struct argv_array args; struct argv_array env_array; pid_t pid; @@ -18,8 +70,8 @@ struct child_process { /* * Using .in, .out, .err: - * - Specify 0 for no redirections (child inherits stdin, stdout, - * stderr from parent). + * - Specify 0 for no redirections. No new file descriptor is allocated. + * (child inherits stdin, stdout, stderr from parent). * - Specify -1 to have a pipe allocated as follows: * .in: returns the writable pipe end; parent writes to it, * the readable pipe end becomes child's stdin @@ -37,13 +89,43 @@ struct child_process { int in; int out; int err; + + /** + * To specify a new initial working directory for the sub-process, + * specify it in the .dir member. + */ const char *dir; + + /** + * To modify the environment of the sub-process, specify an array of + * string pointers (NULL terminated) in .env: + * + * - If the string is of the form "VAR=value", i.e. it contains '=' + * the variable is added to the child process's environment. + * + * - If the string does not contain '=', it names an environment + * variable that will be removed from the child process's environment. + * + * If the .env member is NULL, `start_command` will point it at the + * .env_array `argv_array` (so you may use one or the other, but not both). + * The memory in .env_array will be cleaned up automatically during + * `finish_command` (or during `start_command` when it is unsuccessful). + */ const char *const *env; + unsigned no_stdin:1; unsigned no_stdout:1; unsigned no_stderr:1; - unsigned git_cmd:1; /* if this is to be git sub-command */ + unsigned git_cmd:1; /* if this is to be git sub-command */ + + /** + * If the program cannot be found, the functions return -1 and set + * errno to ENOENT. Normally, an error message is printed, but if + * .silent_exec_failure is set to 1, no message is printed for this + * special error condition. + */ unsigned silent_exec_failure:1; + unsigned stdout_to_stderr:1; unsigned use_shell:1; unsigned clean_on_exit:1; @@ -53,13 +135,63 @@ struct child_process { }; #define CHILD_PROCESS_INIT { NULL, ARGV_ARRAY_INIT, ARGV_ARRAY_INIT } + +/** + * The functions: child_process_init, start_command, finish_command, + * run_command, run_command_v_opt, run_command_v_opt_cd_env, child_process_clear + * do the following: + * + * - If a system call failed, errno is set and -1 is returned. A diagnostic + * is printed. + * + * - If the program was not found, then -1 is returned and errno is set to + * ENOENT; a diagnostic is printed only if .silent_exec_failure is 0. + * + * - Otherwise, the program is run. If it terminates regularly, its exit + * code is returned. No diagnostic is printed, even if the exit code is + * non-zero. + * + * - If the program terminated due to a signal, then the return value is the + * signal number + 128, ie. the same value that a POSIX shell's $? would + * report. A diagnostic is printed. + * + */ + +/** + * Initialize a struct child_process variable. + */ void child_process_init(struct child_process *); + +/** + * Release the memory associated with the struct child_process. + * Most users of the run-command API don't need to call this + * function explicitly because `start_command` invokes it on + * failure and `finish_command` calls it automatically already. + */ void child_process_clear(struct child_process *); + int is_executable(const char *name); +/** + * Start a sub-process. Takes a pointer to a `struct child_process` + * that specifies the details and returns pipe FDs (if requested). + * See below for details. + */ int start_command(struct child_process *); + +/** + * Wait for the completion of a sub-process that was started with + * start_command(). + */ int finish_command(struct child_process *); + int finish_command_in_signal(struct child_process *); + +/** + * A convenience function that encapsulates a sequence of + * start_command() followed by finish_command(). Takes a pointer + * to a `struct child_process` that specifies the details. + */ int run_command(struct child_process *); /* @@ -68,6 +200,20 @@ int run_command(struct child_process *); * overwritten by further calls to find_hook and run_hook_*. */ const char *find_hook(const char *name); + +/** + * Run a hook. + * The first argument is a pathname to an index file, or NULL + * if the hook uses the default index file or no index is needed. + * The second argument is the name of the hook. + * The further arguments correspond to the hook arguments. + * The last argument has to be NULL to terminate the arguments list. + * If the hook does not exist or is not executable, the return + * value will be zero. + * If it is executable, the hook will be executed and the exit + * status of the hook is returned. + * On execution, .stdout_to_stderr and .no_stdin will be set. + */ LAST_ARG_MUST_BE_NULL int run_hook_le(const char *const *env, const char *name, ...); int run_hook_ve(const char *const *env, const char *name, va_list args); @@ -78,6 +224,18 @@ int run_hook_ve(const char *const *env, const char *name, va_list args); #define RUN_SILENT_EXEC_FAILURE 8 #define RUN_USING_SHELL 16 #define RUN_CLEAN_ON_EXIT 32 + +/** + * Convenience functions that encapsulate a sequence of + * start_command() followed by finish_command(). The argument argv + * specifies the program and its arguments. The argument opt is zero + * or more of the flags `RUN_COMMAND_NO_STDIN`, `RUN_GIT_CMD`, + * `RUN_COMMAND_STDOUT_TO_STDERR`, or `RUN_SILENT_EXEC_FAILURE` + * that correspond to the members .no_stdin, .git_cmd, + * .stdout_to_stderr, .silent_exec_failure of `struct child_process`. + * The argument dir corresponds the member .dir. The argument env + * corresponds to the member .env. + */ int run_command_v_opt(const char **argv, int opt); int run_command_v_opt_tr2(const char **argv, int opt, const char *tr2_class); /* @@ -125,15 +283,84 @@ static inline int capture_command(struct child_process *cmd, * It is expected that no synchronization and mutual exclusion between * the caller and the feed function is necessary so that the function * can run in a thread without interfering with the caller. + * + * The caller: + * + * 1. allocates and clears (memset(&asy, 0, sizeof(asy));) a + * struct async variable; + * 2. initializes .proc and .data; + * 3. calls start_async(); + * 4. processes communicates with proc through .in and .out; + * 5. closes .in and .out; + * 6. calls finish_async(). + * + * There are serious restrictions on what the asynchronous function can do + * because this facility is implemented by a thread in the same address + * space on most platforms (when pthreads is available), but by a pipe to + * a forked process otherwise: + * + * - It cannot change the program's state (global variables, environment, + * etc.) in a way that the caller notices; in other words, .in and .out + * are the only communication channels to the caller. + * + * - It must not change the program's state that the caller of the + * facility also uses. + * */ struct async { - /* - * proc reads from in; closes it before return - * proc writes to out; closes it before return - * returns 0 on success, non-zero on failure + + /** + * The function pointer in .proc has the following signature: + * + * int proc(int in, int out, void *data); + * + * - in, out specifies a set of file descriptors to which the function + * must read/write the data that it needs/produces. The function + * *must* close these descriptors before it returns. A descriptor + * may be -1 if the caller did not configure a descriptor for that + * direction. + * + * - data is the value that the caller has specified in the .data member + * of struct async. + * + * - The return value of the function is 0 on success and non-zero + * on failure. If the function indicates failure, finish_async() will + * report failure as well. + * */ int (*proc)(int in, int out, void *data); + void *data; + + /** + * The members .in, .out are used to provide a set of fd's for + * communication between the caller and the callee as follows: + * + * - Specify 0 to have no file descriptor passed. The callee will + * receive -1 in the corresponding argument. + * + * - Specify < 0 to have a pipe allocated; start_async() replaces + * with the pipe FD in the following way: + * + * .in: Returns the writable pipe end into which the caller + * writes; the readable end of the pipe becomes the function's + * in argument. + * + * .out: Returns the readable pipe end from which the caller + * reads; the writable end of the pipe becomes the function's + * out argument. + * + * The caller of start_async() must close the returned FDs after it + * has completed reading from/writing from them. + * + * - Specify a file descriptor > 0 to be used by the function: + * + * .in: The FD must be readable; it becomes the function's in. + * .out: The FD must be writable; it becomes the function's out. + * + * The specified FD is closed by start_async(), even if it fails to + * run the function. + */ int in; /* caller writes here and closes it */ int out; /* caller reads from here and closes it */ #ifdef NO_PTHREADS @@ -146,8 +373,19 @@ struct async { int isolate_sigpipe; }; +/** + * Run a function asynchronously. Takes a pointer to a `struct + * async` that specifies the details and returns a set of pipe FDs + * for communication with the function. See below for details. + */ int start_async(struct async *async); + +/** + * Wait for the completion of an asynchronous function that was + * started with start_async(). + */ int finish_async(struct async *async); + int in_async(void); int async_with_fork(void); void check_pipe(int err); From patchwork Wed Nov 6 09:59:44 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Passaro via GitGitGadget X-Patchwork-Id: 11229913 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 EF20E1575 for ; Wed, 6 Nov 2019 10:00:23 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id C36DA217F4 for ; Wed, 6 Nov 2019 10:00:23 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="JYGfjgxn" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731833AbfKFKAT (ORCPT ); Wed, 6 Nov 2019 05:00:19 -0500 Received: from mail-wm1-f46.google.com ([209.85.128.46]:50452 "EHLO mail-wm1-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731732AbfKFKAD (ORCPT ); Wed, 6 Nov 2019 05:00:03 -0500 Received: by mail-wm1-f46.google.com with SMTP id 11so2631973wmk.0 for ; Wed, 06 Nov 2019 02:00:02 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=Yj6dU6eAFClAyLjY8JX8pFhWVOm+gb6VPcSQ1NX0okY=; b=JYGfjgxn5HRUfJ2+LOcx4fQ3PumjBvHHi9dpAGILihVWnQzGbJ4+v6tKqFnsfNgvza fEiKx4I7kyhON7Y3i0xb5AKmLRuf4nt3AxyBq9YZSIGo/Z4PIWrBg9pOGoaFxiEDeBkm O4uWW99fx+cn6sCicDUzw6Ln4fD2sWY6iI/r72qA/DG8q20d2qMWO9z1BPWUO+4NsMtW 2QwiuJqDJt09UHOzLFfk/TtiI2mtAna0zSp5aB6YaGyUZxo+/rtVuF5zNfa1BYT5F3Et QBXebcEOWWWyf/QvAbpkyj/nlumPH3fMc+UjYil1Dqx82nRCW3wJB2A9HYqVGGqu8v9b k7Aw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=Yj6dU6eAFClAyLjY8JX8pFhWVOm+gb6VPcSQ1NX0okY=; b=q8Ct5eRYAic/FIo8vEVuwNMCjRBaqNyXJI3YJbqO1dDxpQNbCBJm3ddXnVC7Z61A1B 7TwyVfH/NytTMem47hqU4Ora9R6bc751koCPRil89+K4bgAA+CRrp5B1fq3kOz1i8+dd NawnM9CQ+hkICP4iCdoPz90R8hTrXfpHQ4Qhj6Xox3hrzxoAUrwrSll2NTuHbNG/K0dQ rB4fJDZE8v61PMXkKXbnalCUswwFlRWLSMS+ibTpvvV0fleDbh0eqrvcgOWSRdEP4+VD wRCHBjJmXbuhTADWndieI+Vy19HGECeKpmkDQLPYmnCQoFs8HY/4f3aDk2j3799y7AwN OPPw== X-Gm-Message-State: APjAAAWzmZR7J237leemF8NwZcPj0GwtZNj9OpqXJDPU+EBK6T8dUgA+ Rfra0UQL8k5PN/nTYtgkbD0LsOXB X-Google-Smtp-Source: APXvYqz2mfPTtGkdl424jmY8XF/8oo3hP+oY51Op77JH6To2VIUMZ9v1NSa6sXR3LDM+lFfObGe2iA== X-Received: by 2002:a1c:814b:: with SMTP id c72mr1680298wmd.167.1573034400964; Wed, 06 Nov 2019 02:00:00 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id 6sm2909209wmd.36.2019.11.06.02.00.00 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 06 Nov 2019 02:00:00 -0800 (PST) Message-Id: <9b02b44cc868d8bbdcfd99d26256c2876fc0b03c.1573034387.git.gitgitgadget@gmail.com> In-Reply-To: References: From: "Heba Waly via GitGitGadget" Date: Wed, 06 Nov 2019 09:59:44 +0000 Subject: [PATCH v2 17/20] trace: move doc to trace.h Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Heba Waly , Junio C Hamano , Heba Waly Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Heba Waly Move the documentation from Documentation/technical/api-trace.txt to trace.h as it's easier for the developers to find the usage information beside the code instead of looking for it in another doc file. Documentation/technical/api-trace.txt is removed because the information it has is now redundant and it'll be hard to keep it up to date and synchronized with the documentation in the header file. Signed-off-by: Heba Waly Reviewed-by: Emily Shaffer --- Documentation/technical/api-trace.txt | 140 -------------------------- trace.h | 133 +++++++++++++++++++++++- 2 files changed, 131 insertions(+), 142 deletions(-) delete mode 100644 Documentation/technical/api-trace.txt diff --git a/Documentation/technical/api-trace.txt b/Documentation/technical/api-trace.txt deleted file mode 100644 index fadb5979c4..0000000000 --- a/Documentation/technical/api-trace.txt +++ /dev/null @@ -1,140 +0,0 @@ -trace API -========= - -The trace API can be used to print debug messages to stderr or a file. Trace -code is inactive unless explicitly enabled by setting `GIT_TRACE*` environment -variables. - -The trace implementation automatically adds `timestamp file:line ... \n` to -all trace messages. E.g.: - ------------- -23:59:59.123456 git.c:312 trace: built-in: git 'foo' -00:00:00.000001 builtin/foo.c:99 foo: some message ------------- - -Data Structures ---------------- - -`struct trace_key`:: - - Defines a trace key (or category). The default (for API functions that - don't take a key) is `GIT_TRACE`. -+ -E.g. to define a trace key controlled by environment variable `GIT_TRACE_FOO`: -+ ------------- -static struct trace_key trace_foo = TRACE_KEY_INIT(FOO); - -static void trace_print_foo(const char *message) -{ - trace_printf_key(&trace_foo, "%s", message); -} ------------- -+ -Note: don't use `const` as the trace implementation stores internal state in -the `trace_key` structure. - -Functions ---------- - -`int trace_want(struct trace_key *key)`:: - - Checks whether the trace key is enabled. Used to prevent expensive - string formatting before calling one of the printing APIs. - -`void trace_disable(struct trace_key *key)`:: - - Disables tracing for the specified key, even if the environment - variable was set. - -`void trace_printf(const char *format, ...)`:: -`void trace_printf_key(struct trace_key *key, const char *format, ...)`:: - - Prints a formatted message, similar to printf. - -`void trace_argv_printf(const char **argv, const char *format, ...)``:: - - Prints a formatted message, followed by a quoted list of arguments. - -`void trace_strbuf(struct trace_key *key, const struct strbuf *data)`:: - - Prints the strbuf, without additional formatting (i.e. doesn't - choke on `%` or even `\0`). - -`uint64_t getnanotime(void)`:: - - Returns nanoseconds since the epoch (01/01/1970), typically used - for performance measurements. -+ -Currently there are high precision timer implementations for Linux (using -`clock_gettime(CLOCK_MONOTONIC)`) and Windows (`QueryPerformanceCounter`). -Other platforms use `gettimeofday` as time source. - -`void trace_performance(uint64_t nanos, const char *format, ...)`:: -`void trace_performance_since(uint64_t start, const char *format, ...)`:: - - Prints the elapsed time (in nanoseconds), or elapsed time since - `start`, followed by a formatted message. Enabled via environment - variable `GIT_TRACE_PERFORMANCE`. Used for manual profiling, e.g.: -+ ------------- -uint64_t start = getnanotime(); -/* code section to measure */ -trace_performance_since(start, "foobar"); ------------- -+ ------------- -uint64_t t = 0; -for (;;) { - /* ignore */ - t -= getnanotime(); - /* code section to measure */ - t += getnanotime(); - /* ignore */ -} -trace_performance(t, "frotz"); ------------- - -Bugs & Caveats --------------- - -GIT_TRACE_* environment variables can be used to tell Git to show -trace output to its standard error stream. Git can often spawn a pager -internally to run its subcommand and send its standard output and -standard error to it. - -Because GIT_TRACE_PERFORMANCE trace is generated only at the very end -of the program with atexit(), which happens after the pager exits, it -would not work well if you send its log to the standard error output -and let Git spawn the pager at the same time. - -As a work around, you can for example use '--no-pager', or set -GIT_TRACE_PERFORMANCE to another file descriptor which is redirected -to stderr, or set GIT_TRACE_PERFORMANCE to a file specified by its -absolute path. - -For example instead of the following command which by default may not -print any performance information: - ------------- -GIT_TRACE_PERFORMANCE=2 git log -1 ------------- - -you may want to use: - ------------- -GIT_TRACE_PERFORMANCE=2 git --no-pager log -1 ------------- - -or: - ------------- -GIT_TRACE_PERFORMANCE=3 3>&2 git log -1 ------------- - -or: - ------------- -GIT_TRACE_PERFORMANCE=/path/to/log/file git log -1 ------------- diff --git a/trace.h b/trace.h index 9fa3e7a594..9826618b33 100644 --- a/trace.h +++ b/trace.h @@ -4,6 +4,82 @@ #include "git-compat-util.h" #include "strbuf.h" +/** + * The trace API can be used to print debug messages to stderr or a file. Trace + * code is inactive unless explicitly enabled by setting `GIT_TRACE*` environment + * variables. + * + * The trace implementation automatically adds `timestamp file:line ... \n` to + * all trace messages. E.g.: + * + * ------------ + * 23:59:59.123456 git.c:312 trace: built-in: git 'foo' + * 00:00:00.000001 builtin/foo.c:99 foo: some message + * ------------ + * + * Bugs & Caveats + * -------------- + * + * GIT_TRACE_* environment variables can be used to tell Git to show + * trace output to its standard error stream. Git can often spawn a pager + * internally to run its subcommand and send its standard output and + * standard error to it. + * + * Because GIT_TRACE_PERFORMANCE trace is generated only at the very end + * of the program with atexit(), which happens after the pager exits, it + * would not work well if you send its log to the standard error output + * and let Git spawn the pager at the same time. + * + * As a work around, you can for example use '--no-pager', or set + * GIT_TRACE_PERFORMANCE to another file descriptor which is redirected + * to stderr, or set GIT_TRACE_PERFORMANCE to a file specified by its + * absolute path. + * + * For example instead of the following command which by default may not + * print any performance information: + * + * ------------ + * GIT_TRACE_PERFORMANCE=2 git log -1 + * ------------ + * + * you may want to use: + * + * ------------ + * GIT_TRACE_PERFORMANCE=2 git --no-pager log -1 + * ------------ + * + * or: + * + * ------------ + * GIT_TRACE_PERFORMANCE=3 3>&2 git log -1 + * ------------ + * + * or: + * + * ------------ + * GIT_TRACE_PERFORMANCE=/path/to/log/file git log -1 + * ------------ + * + */ + +/** + * Defines a trace key (or category). The default (for API functions that + * don't take a key) is `GIT_TRACE`. + * + * E.g. to define a trace key controlled by environment variable `GIT_TRACE_FOO`: + * + * ------------ + * static struct trace_key trace_foo = TRACE_KEY_INIT(FOO); + * + * static void trace_print_foo(const char *message) + * { + * trace_printf_key(&trace_foo, "%s", message); + * } + * ------------ + * + * Note: don't use `const` as the trace implementation stores internal state in + * the `trace_key` structure. + */ struct trace_key { const char * const key; int fd; @@ -18,31 +94,84 @@ extern struct trace_key trace_perf_key; extern struct trace_key trace_setup_key; void trace_repo_setup(const char *prefix); + +/** + * Checks whether the trace key is enabled. Used to prevent expensive + * string formatting before calling one of the printing APIs. + */ int trace_want(struct trace_key *key); + +/** + * Disables tracing for the specified key, even if the environment variable + * was set. + */ void trace_disable(struct trace_key *key); + +/** + * Returns nanoseconds since the epoch (01/01/1970), typically used + * for performance measurements. + * Currently there are high precision timer implementations for Linux (using + * `clock_gettime(CLOCK_MONOTONIC)`) and Windows (`QueryPerformanceCounter`). + * Other platforms use `gettimeofday` as time source. + */ uint64_t getnanotime(void); + void trace_command_performance(const char **argv); void trace_verbatim(struct trace_key *key, const void *buf, unsigned len); uint64_t trace_performance_enter(void); #ifndef HAVE_VARIADIC_MACROS +/** + * Prints a formatted message, similar to printf. + */ __attribute__((format (printf, 1, 2))) void trace_printf(const char *format, ...); __attribute__((format (printf, 2, 3))) void trace_printf_key(struct trace_key *key, const char *format, ...); +/** + * Prints a formatted message, followed by a quoted list of arguments. + */ __attribute__((format (printf, 2, 3))) void trace_argv_printf(const char **argv, const char *format, ...); +/** + * Prints the strbuf, without additional formatting (i.e. doesn't + * choke on `%` or even `\0`). + */ void trace_strbuf(struct trace_key *key, const struct strbuf *data); -/* Prints elapsed time (in nanoseconds) if GIT_TRACE_PERFORMANCE is enabled. */ +/** + * Prints elapsed time (in nanoseconds) if GIT_TRACE_PERFORMANCE is enabled. + * + * Example: + * ------------ + * uint64_t t = 0; + * for (;;) { + * // ignore + * t -= getnanotime(); + * // code section to measure + * t += getnanotime(); + * // ignore + * } + * trace_performance(t, "frotz"); + * ------------ + */ __attribute__((format (printf, 2, 3))) void trace_performance(uint64_t nanos, const char *format, ...); -/* Prints elapsed time since 'start' if GIT_TRACE_PERFORMANCE is enabled. */ +/** + * Prints elapsed time since 'start' if GIT_TRACE_PERFORMANCE is enabled. + * + * Example: + * ------------ + * uint64_t start = getnanotime(); + * // code section to measure + * trace_performance_since(start, "foobar"); + * ------------ + */ __attribute__((format (printf, 2, 3))) void trace_performance_since(uint64_t start, const char *format, ...); From patchwork Wed Nov 6 09:59:45 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Passaro via GitGitGadget X-Patchwork-Id: 11229899 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 23ED11575 for ; Wed, 6 Nov 2019 10:00:11 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id EC63D217F5 for ; Wed, 6 Nov 2019 10:00:10 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="KXMQlW4/" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731794AbfKFKAH (ORCPT ); Wed, 6 Nov 2019 05:00:07 -0500 Received: from mail-wr1-f67.google.com ([209.85.221.67]:43188 "EHLO mail-wr1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731735AbfKFKAF (ORCPT ); Wed, 6 Nov 2019 05:00:05 -0500 Received: by mail-wr1-f67.google.com with SMTP id n1so24962173wra.10 for ; Wed, 06 Nov 2019 02:00:02 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=HbACMYxVeKZISfJjlWuOfXOiD4JKlD+P2JYaSrDwUQY=; b=KXMQlW4/ylCvyvnvepwNu/M06SvmOLi+/s//tnlXCxMb0XfVvChC0SwEn3J7qZDfwo ZXnCrhQS7JrhA0+5Cf0qGz2nFMpk0X45IWH2pQUegbtYeE5U0eIw1lTZ+u4NVvhvYu8/ OPh2ZCZxzAcBoNZwBEctWR6PpLHq5mEj9ba7kmXnGkfEecE5FaakvZTw8tTko36H25UU E6IMyZw7W9GHA3oX6lNhLWNlMAZQ8Qb4uOS95TmKTKl8kuI58RzZRb7Pgm+4r0/IbEya /4ecq+ERnLjUr8W2t+lPSeNVOQw5K6HTm74DS7w+d/bn62dPERXv2EXe6zErKl0y3Jev Vc+A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=HbACMYxVeKZISfJjlWuOfXOiD4JKlD+P2JYaSrDwUQY=; b=AxKD3av/SGvgb/s7VzUMmqhlzMHfF+qSyFpr4lElgK9g5ooiLVJ6r+oXOAqXavjt1y nfUW7db266kmveiC+7Gh/j0VbTkWjttd+BReTWx2tq97EhJdGefNXSRgUbu7Ihqo1bJG iSE6mJM+03CS4ajukzNhEcyG1/xJDwptnOdjDCnTX5YnRIOcUPZfyLhsk2WKXT0K//kj b0lyV+KWvqdvB7/2Uk58ufgId8ryJiIKgtGEh1BFrKSKdNdKJhqgGL29hWfvKtbw8uWs PwczLjFqhJI2wmoTs2Ckos0L8StFfaqUFiEQWTldpLWR2dD7BipF+ii4mzE4IUut16wE s47A== X-Gm-Message-State: APjAAAUQsDp/CR1shq4XPKt+FOzGaLKnNW4JkDAiQiRcdC/QQ93T9pCK J+W/ltPKOdiUyzMUzmkE9rS4Mm5D X-Google-Smtp-Source: APXvYqzD3q1GgSknd85GpuqJgt+Q2zRPkZkUYKiWH4IxuuVLSe9nBlr9NBtHDioxzxGYNwWK2SuUkQ== X-Received: by 2002:adf:b608:: with SMTP id f8mr1680854wre.99.1573034401549; Wed, 06 Nov 2019 02:00:01 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id v19sm1896427wmh.16.2019.11.06.02.00.01 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 06 Nov 2019 02:00:01 -0800 (PST) Message-Id: <9c8f5c1cbeef426a33e89b6a32911f8e23f9b0cf.1573034387.git.gitgitgadget@gmail.com> In-Reply-To: References: From: "Heba Waly via GitGitGadget" Date: Wed, 06 Nov 2019 09:59:45 +0000 Subject: [PATCH v2 18/20] tree-walk: move doc to tree-walk.h Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Heba Waly , Junio C Hamano , Heba Waly Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Heba Waly Move the documentation from Documentation/technical/api-tree-walking.txt to tree-walk.h as it's easier for the developers to find the usage information beside the code instead of looking for it in another doc file. Documentation/technical/api-tree-walking.txt is removed because the information it has is now redundant and it'll be hard to keep it up to date and synchronized with the documentation in the header file. Signed-off-by: Heba Waly --- Documentation/technical/api-tree-walking.txt | 149 ------------------- tree-walk.h | 122 ++++++++++++++- 2 files changed, 120 insertions(+), 151 deletions(-) delete mode 100644 Documentation/technical/api-tree-walking.txt diff --git a/Documentation/technical/api-tree-walking.txt b/Documentation/technical/api-tree-walking.txt deleted file mode 100644 index 7962e32854..0000000000 --- a/Documentation/technical/api-tree-walking.txt +++ /dev/null @@ -1,149 +0,0 @@ -tree walking API -================ - -The tree walking API is used to traverse and inspect trees. - -Data Structures ---------------- - -`struct name_entry`:: - - An entry in a tree. Each entry has a sha1 identifier, pathname, and - mode. - -`struct tree_desc`:: - - A semi-opaque data structure used to maintain the current state of the - walk. -+ -* `buffer` is a pointer into the memory representation of the tree. It always -points at the current entry being visited. - -* `size` counts the number of bytes left in the `buffer`. - -* `entry` points to the current entry being visited. - -`struct traverse_info`:: - - A structure used to maintain the state of a traversal. -+ -* `prev` points to the traverse_info which was used to descend into the -current tree. If this is the top-level tree `prev` will point to -a dummy traverse_info. - -* `name` is the entry for the current tree (if the tree is a subtree). - -* `pathlen` is the length of the full path for the current tree. - -* `conflicts` can be used by callbacks to maintain directory-file conflicts. - -* `fn` is a callback called for each entry in the tree. See Traversing for more -information. - -* `data` can be anything the `fn` callback would want to use. - -* `show_all_errors` tells whether to stop at the first error or not. - -Initializing ------------- - -`init_tree_desc`:: - - Initialize a `tree_desc` and decode its first entry. The buffer and - size parameters are assumed to be the same as the buffer and size - members of `struct tree`. - -`fill_tree_descriptor`:: - - Initialize a `tree_desc` and decode its first entry given the - object ID of a tree. Returns the `buffer` member if the latter - is a valid tree identifier and NULL otherwise. - -`setup_traverse_info`:: - - Initialize a `traverse_info` given the pathname of the tree to start - traversing from. - -Walking -------- - -`tree_entry`:: - - Visit the next entry in a tree. Returns 1 when there are more entries - left to visit and 0 when all entries have been visited. This is - commonly used in the test of a while loop. - -`tree_entry_len`:: - - Calculate the length of a tree entry's pathname. This utilizes the - memory structure of a tree entry to avoid the overhead of using a - generic strlen(). - -`update_tree_entry`:: - - Walk to the next entry in a tree. This is commonly used in conjunction - with `tree_entry_extract` to inspect the current entry. - -`tree_entry_extract`:: - - Decode the entry currently being visited (the one pointed to by - `tree_desc's` `entry` member) and return the sha1 of the entry. The - `pathp` and `modep` arguments are set to the entry's pathname and mode - respectively. - -`get_tree_entry`:: - - Find an entry in a tree given a pathname and the sha1 of a tree to - search. Returns 0 if the entry is found and -1 otherwise. The third - and fourth parameters are set to the entry's sha1 and mode - respectively. - -Traversing ----------- - -`traverse_trees`:: - - Traverse `n` number of trees in parallel. The `fn` callback member of - `traverse_info` is called once for each tree entry. - -`traverse_callback_t`:: - The arguments passed to the traverse callback are as follows: -+ -* `n` counts the number of trees being traversed. - -* `mask` has its nth bit set if something exists in the nth entry. - -* `dirmask` has its nth bit set if the nth tree's entry is a directory. - -* `entry` is an array of size `n` where the nth entry is from the nth tree. - -* `info` maintains the state of the traversal. - -+ -Returning a negative value will terminate the traversal. Otherwise the -return value is treated as an update mask. If the nth bit is set the nth tree -will be updated and if the bit is not set the nth tree entry will be the -same in the next callback invocation. - -`make_traverse_path`:: - - Generate the full pathname of a tree entry based from the root of the - traversal. For example, if the traversal has recursed into another - tree named "bar" the pathname of an entry "baz" in the "bar" - tree would be "bar/baz". - -`traverse_path_len`:: - - Calculate the length of a pathname returned by `make_traverse_path`. - This utilizes the memory structure of a tree entry to avoid the - overhead of using a generic strlen(). - -`strbuf_make_traverse_path`:: - - Convenience wrapper to `make_traverse_path` into a strbuf. - -Authors -------- - -Written by Junio C Hamano and Linus Torvalds - diff --git a/tree-walk.h b/tree-walk.h index abe2caf4e0..b9699ca641 100644 --- a/tree-walk.h +++ b/tree-walk.h @@ -3,6 +3,13 @@ #include "cache.h" +/** + * The tree walking API is used to traverse and inspect trees. + */ + +/** + * An entry in a tree. Each entry has a sha1 identifier, pathname, and mode. + */ struct name_entry { struct object_id oid; const char *path; @@ -10,12 +17,29 @@ struct name_entry { unsigned int mode; }; +/** + * A semi-opaque data structure used to maintain the current state of the walk. + */ struct tree_desc { + /* + * pointer into the memory representation of the tree. It always + * points at the current entry being visited. + */ const void *buffer; + + /* points to the current entry being visited. */ struct name_entry entry; + + /* counts the number of bytes left in the `buffer`. */ unsigned int size; }; +/** + * Decode the entry currently being visited (the one pointed to by + * `tree_desc's` `entry` member) and return the sha1 of the entry. The + * `pathp` and `modep` arguments are set to the entry's pathname and mode + * respectively. + */ static inline const struct object_id *tree_entry_extract(struct tree_desc *desc, const char **pathp, unsigned short *modep) { *pathp = desc->entry.path; @@ -23,6 +47,11 @@ static inline const struct object_id *tree_entry_extract(struct tree_desc *desc, return &desc->entry.oid; } +/** + * Calculate the length of a tree entry's pathname. This utilizes the + * memory structure of a tree entry to avoid the overhead of using a + * generic strlen(). + */ static inline int tree_entry_len(const struct name_entry *ne) { return ne->pathlen; @@ -33,52 +62,141 @@ static inline int tree_entry_len(const struct name_entry *ne) * corrupt tree entry rather than dying, */ +/** + * Walk to the next entry in a tree. This is commonly used in conjunction + * with `tree_entry_extract` to inspect the current entry. + */ void update_tree_entry(struct tree_desc *); + int update_tree_entry_gently(struct tree_desc *); + +/** + * Initialize a `tree_desc` and decode its first entry. The buffer and + * size parameters are assumed to be the same as the buffer and size + * members of `struct tree`. + */ void init_tree_desc(struct tree_desc *desc, const void *buf, unsigned long size); + int init_tree_desc_gently(struct tree_desc *desc, const void *buf, unsigned long size); /* - * Helper function that does both tree_entry_extract() and update_tree_entry() - * and returns true for success + * Visit the next entry in a tree. Returns 1 when there are more entries + * left to visit and 0 when all entries have been visited. This is + * commonly used in the test of a while loop. */ int tree_entry(struct tree_desc *, struct name_entry *); + int tree_entry_gently(struct tree_desc *, struct name_entry *); +/** + * Initialize a `tree_desc` and decode its first entry given the + * object ID of a tree. Returns the `buffer` member if the latter + * is a valid tree identifier and NULL otherwise. + */ void *fill_tree_descriptor(struct repository *r, struct tree_desc *desc, const struct object_id *oid); struct traverse_info; typedef int (*traverse_callback_t)(int n, unsigned long mask, unsigned long dirmask, struct name_entry *entry, struct traverse_info *); + +/** + * Traverse `n` number of trees in parallel. The `fn` callback member of + * `traverse_info` is called once for each tree entry. + */ int traverse_trees(struct index_state *istate, int n, struct tree_desc *t, struct traverse_info *info); enum get_oid_result get_tree_entry_follow_symlinks(struct repository *r, struct object_id *tree_oid, const char *name, struct object_id *result, struct strbuf *result_path, unsigned short *mode); +/** + * A structure used to maintain the state of a traversal. + */ struct traverse_info { const char *traverse_path; + + /* + * points to the traverse_info which was used to descend into the + * current tree. If this is the top-level tree `prev` will point to + * a dummy traverse_info. + */ struct traverse_info *prev; + + /* is the entry for the current tree (if the tree is a subtree). */ const char *name; + size_t namelen; unsigned mode; + /* is the length of the full path for the current tree. */ size_t pathlen; + struct pathspec *pathspec; + /* can be used by callbacks to maintain directory-file conflicts. */ unsigned long df_conflicts; + + /* a callback called for each entry in the tree. + * + * The arguments passed to the traverse callback are as follows: + * + * - `n` counts the number of trees being traversed. + * + * - `mask` has its nth bit set if something exists in the nth entry. + * + * - `dirmask` has its nth bit set if the nth tree's entry is a directory. + * + * - `entry` is an array of size `n` where the nth entry is from the nth tree. + * + * - `info` maintains the state of the traversal. + * + * Returning a negative value will terminate the traversal. Otherwise the + * return value is treated as an update mask. If the nth bit is set the nth tree + * will be updated and if the bit is not set the nth tree entry will be the + * same in the next callback invocation. + */ traverse_callback_t fn; + + /* can be anything the `fn` callback would want to use. */ void *data; + + /* tells whether to stop at the first error or not. */ int show_all_errors; }; +/** + * Find an entry in a tree given a pathname and the sha1 of a tree to + * search. Returns 0 if the entry is found and -1 otherwise. The third + * and fourth parameters are set to the entry's sha1 and mode respectively. + */ int get_tree_entry(struct repository *, const struct object_id *, const char *, struct object_id *, unsigned short *); + +/** + * Generate the full pathname of a tree entry based from the root of the + * traversal. For example, if the traversal has recursed into another + * tree named "bar" the pathname of an entry "baz" in the "bar" + * tree would be "bar/baz". + */ char *make_traverse_path(char *path, size_t pathlen, const struct traverse_info *info, const char *name, size_t namelen); + +/** + * Convenience wrapper to `make_traverse_path` into a strbuf. + */ void strbuf_make_traverse_path(struct strbuf *out, const struct traverse_info *info, const char *name, size_t namelen); + +/** + * Initialize a `traverse_info` given the pathname of the tree to start + * traversing from. + */ void setup_traverse_info(struct traverse_info *info, const char *base); +/** + * Calculate the length of a pathname returned by `make_traverse_path`. + * This utilizes the memory structure of a tree entry to avoid the + * overhead of using a generic strlen(). + */ static inline size_t traverse_path_len(const struct traverse_info *info, size_t namelen) { From patchwork Wed Nov 6 09:59:46 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Passaro via GitGitGadget X-Patchwork-Id: 11229907 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 3EAC41575 for ; Wed, 6 Nov 2019 10:00:17 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 136E12173B for ; Wed, 6 Nov 2019 10:00:17 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="XVoNVhZm" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731776AbfKFKAF (ORCPT ); Wed, 6 Nov 2019 05:00:05 -0500 Received: from mail-wm1-f51.google.com ([209.85.128.51]:40399 "EHLO mail-wm1-f51.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731697AbfKFKAE (ORCPT ); Wed, 6 Nov 2019 05:00:04 -0500 Received: by mail-wm1-f51.google.com with SMTP id f3so2555707wmc.5 for ; Wed, 06 Nov 2019 02:00:03 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=mPeoWAcBb00eGe8EIY/HsjteDgVd3vEwluZm6lyqWhE=; b=XVoNVhZmrLL3hTbpZ2fGLl7KlxNBCy+iu9eLAlsS8AfbISa8m2O98UW6Yj4a9hMYJk NdqkHVpsbEIAfEOaxiXfV1oYO4Dez7avRAheCJ1QIoyEZJvMFupq5fu0+0HTJNjbi8fB yTKFc27QvV9EiCNl57OxkRQwZt8gRMRiOUjOaX9Jbx1vfaD33Jc9LMCG4JlSHLVqM/We RbtqgU5v+qOdXmADkdpq+dRZKSEUL3DZCOo/sVRFsFDhefEq/c/uOzpcdr3vvoMz1fIy LpQm0VjelDkweRdZD1npqX2CPpTExfzxfr/nrHqEP+2uqyXJ6tarQID3Q8CSZ1L3SxGd cMVw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=mPeoWAcBb00eGe8EIY/HsjteDgVd3vEwluZm6lyqWhE=; b=M3K42DKm7ImqjjqtXgM4yHkg9tkCBCTcCyyupowXDhkLTRsoA/cfcpVqGHj7ba1eXB c3p6kuTNxqnWbjjo9aKPEDBH1k60aDiGOxSt8Z3arQJtbj9jhDC6ZToHmMxROW0/bWkK VOeLYSPSDoapfszdAyMboB2V2Sxe8/HK34PiVVHZuLU67onX7pHbLLxp8WGAnIkAE1P3 OOlf2SAb0zU3uE4INtkpuKYgnNW9MokZ3HoCHsOzctyD4mHqJCF1qKsU6RNQ1YhFIq1G 1JfwFstbqkE2y8qm6rwNTp8MuFVRvVEjZmICq8c7VjM6GhTWjRmOMTXNnX7koFbsP+oA d0PQ== X-Gm-Message-State: APjAAAV/FfSbOq3PyZX+7XyGAc2mWxSYTGMU5RHr+cCfa11aPJaWNbSL /SKyRAhdiZAM9qSIyK9kDEghZP30 X-Google-Smtp-Source: APXvYqzgAmYWEJ6DLcufRY6V5XtK0Owu0PHaYz4c0ozrX8BZpNcvbGqizMzktHN8X1yZeXaZ5oKGCA== X-Received: by 2002:a7b:c747:: with SMTP id w7mr1719929wmk.62.1573034402194; Wed, 06 Nov 2019 02:00:02 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id v184sm2566830wme.31.2019.11.06.02.00.01 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 06 Nov 2019 02:00:01 -0800 (PST) Message-Id: <7fa5cdf83ff7bc4811e30d0a0e038a27154a8809.1573034387.git.gitgitgadget@gmail.com> In-Reply-To: References: From: "Heba Waly via GitGitGadget" Date: Wed, 06 Nov 2019 09:59:46 +0000 Subject: [PATCH v2 19/20] submodule-config: move doc to submodule-config.h Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Heba Waly , Junio C Hamano , Heba Waly Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Heba Waly Move the documentation from Documentation/technical/api-submodule-config.txt to submodule-config.h as it's easier for the developers to find the usage information beside the code instead of looking for it in another doc file. Documentation/technical/api-submodule-config.txt is removed because the information it has is now redundant and it'll be hard to keep it up to date and synchronized with the documentation in the header file. The documentation of parse_submodule_config_option() is discarded as the function was removed 2 years ago. Signed-off-by: Heba Waly --- .../technical/api-submodule-config.txt | 66 ------------------- submodule-config.h | 38 ++++++++++- 2 files changed, 37 insertions(+), 67 deletions(-) delete mode 100644 Documentation/technical/api-submodule-config.txt diff --git a/Documentation/technical/api-submodule-config.txt b/Documentation/technical/api-submodule-config.txt deleted file mode 100644 index fb06089393..0000000000 --- a/Documentation/technical/api-submodule-config.txt +++ /dev/null @@ -1,66 +0,0 @@ -submodule config cache API -========================== - -The submodule config cache API allows to read submodule -configurations/information from specified revisions. Internally -information is lazily read into a cache that is used to avoid -unnecessary parsing of the same .gitmodules files. Lookups can be done by -submodule path or name. - -Usage ------ - -To initialize the cache with configurations from the worktree the caller -typically first calls `gitmodules_config()` to read values from the -worktree .gitmodules and then to overlay the local git config values -`parse_submodule_config_option()` from the config parsing -infrastructure. - -The caller can look up information about submodules by using the -`submodule_from_path()` or `submodule_from_name()` functions. They return -a `struct submodule` which contains the values. The API automatically -initializes and allocates the needed infrastructure on-demand. If the -caller does only want to lookup values from revisions the initialization -can be skipped. - -If the internal cache might grow too big or when the caller is done with -the API, all internally cached values can be freed with submodule_free(). - -Data Structures ---------------- - -`struct submodule`:: - - This structure is used to return the information about one - submodule for a certain revision. It is returned by the lookup - functions. - -Functions ---------- - -`void submodule_free(struct repository *r)`:: - - Use these to free the internally cached values. - -`int parse_submodule_config_option(const char *var, const char *value)`:: - - Can be passed to the config parsing infrastructure to parse - local (worktree) submodule configurations. - -`const struct submodule *submodule_from_path(const unsigned char *treeish_name, const char *path)`:: - - Given a tree-ish in the superproject and a path, return the - submodule that is bound at the path in the named tree. - -`const struct submodule *submodule_from_name(const unsigned char *treeish_name, const char *name)`:: - - The same as above but lookup by name. - -Whenever a submodule configuration is parsed in `parse_submodule_config_option` -via e.g. `gitmodules_config()`, it will overwrite the null_sha1 entry. -So in the normal case, when HEAD:.gitmodules is parsed first and then overlayed -with the repository configuration, the null_sha1 entry contains the local -configuration of a submodule (e.g. consolidated values from local git -configuration and the .gitmodules file in the worktree). - -For an example usage see test-submodule-config.c. diff --git a/submodule-config.h b/submodule-config.h index 1b4e2da658..42918b55e8 100644 --- a/submodule-config.h +++ b/submodule-config.h @@ -7,9 +7,31 @@ #include "submodule.h" #include "strbuf.h" +/** + * The submodule config cache API allows to read submodule + * configurations/information from specified revisions. Internally + * information is lazily read into a cache that is used to avoid + * unnecessary parsing of the same .gitmodules files. Lookups can be done by + * submodule path or name. + * + * Usage + * ----- + * + * The caller can look up information about submodules by using the + * `submodule_from_path()` or `submodule_from_name()` functions. They return + * a `struct submodule` which contains the values. The API automatically + * initializes and allocates the needed infrastructure on-demand. If the + * caller does only want to lookup values from revisions the initialization + * can be skipped. + * + * If the internal cache might grow too big or when the caller is done with + * the API, all internally cached values can be freed with submodule_free(). + * + */ + /* * Submodule entry containing the information about a certain submodule - * in a certain revision. + * in a certain revision. It is returned by the lookup functions. */ struct submodule { const char *path; @@ -41,13 +63,27 @@ int parse_update_recurse_submodules_arg(const char *opt, const char *arg); int parse_push_recurse_submodules_arg(const char *opt, const char *arg); void repo_read_gitmodules(struct repository *repo); void gitmodules_config_oid(const struct object_id *commit_oid); + +/** + * Same as submodule_from_path but lookup by name. + */ const struct submodule *submodule_from_name(struct repository *r, const struct object_id *commit_or_tree, const char *name); + +/** + * Given a tree-ish in the superproject and a path, return the submodule that + * is bound at the path in the named tree. + */ const struct submodule *submodule_from_path(struct repository *r, const struct object_id *commit_or_tree, const char *path); + +/** + * Use these to free the internally cached values. + */ void submodule_free(struct repository *r); + int print_config_from_gitmodules(struct repository *repo, const char *key); int config_set_in_gitmodules_file_gently(const char *key, const char *value); From patchwork Wed Nov 6 09:59:47 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Passaro via GitGitGadget X-Patchwork-Id: 11229905 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 D3D5C1986 for ; Wed, 6 Nov 2019 10:00:11 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id B19E621929 for ; Wed, 6 Nov 2019 10:00:11 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="uqfpxc3U" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731806AbfKFKAK (ORCPT ); Wed, 6 Nov 2019 05:00:10 -0500 Received: from mail-wr1-f68.google.com ([209.85.221.68]:41543 "EHLO mail-wr1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727642AbfKFKAH (ORCPT ); Wed, 6 Nov 2019 05:00:07 -0500 Received: by mail-wr1-f68.google.com with SMTP id p4so24938055wrm.8 for ; Wed, 06 Nov 2019 02:00:04 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=T4cCjgwyvPk9O6Um579iba6D3AYyluQy7eZXJaKLZI0=; b=uqfpxc3UZvSFNx12BGJeU8OeH+yLfzwwDgh8xC63s9NKjgNV0QtnaIO1WdxOdsXnqi zJX+1ThhxNBc9DJdTkp/E03I1lkJvgYsyOKp5y/0K/QQ38bwy0QtckkJU4oelqAHf6gX FDUgHVgv1z438hLM0gb1Qssxj1SHqMc1f+dFIKwztWxCqrtMBw3oOK10rcI4UhPJkjA7 tpCOi3OT7yNIs00V9xtIiYdPi/IDSTF4m0Io17eu1Nx57XOg4bFRbQtAhsEOhbXxWJBT 5WKs1oAZGUhWGix98OFFk+BvBhFGchiOLeo/iwWHZnD9OSA/BkOnF0ybY8alFZAZynWj j9iA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=T4cCjgwyvPk9O6Um579iba6D3AYyluQy7eZXJaKLZI0=; b=JM7UTPzlwLda1eR8d89qXPlm/dqwDp3m/MCLgvy7GDUiiFpTvWodO1uWT79ASz0NUu mMTT+zPZgEWXfCpkkPaiYmQ1Wt3ScO8X7NI1r1pnVscnJjAVQIzzGF03Ct4pcCb+inaJ UKmN9LeAOzPA11DJ4pnwftC+T2mwoIkQ+O76+OTtKbGqL3RqCBZ6TU45gx1KJ91P+ETa K2gPYacgKVEXqoT2CCghRfmG3Pc78M/aVei1ifJGSyuDm3O9mMnz/yHc2jydVxBDxRWc ymgJ5A89WCn+H8Nobdt7N8+hRLnBgj6A9Vy7I6V3nl5Wbo0tCwi9NXIcBwRK6jsRj22u VSnQ== X-Gm-Message-State: APjAAAUvn2A/ZlC3vR7alErVTpp8rdL5vKeo/SmnE4gAfvShW4xAek9u rB41Nq57+uhMNZEhx6fTUz0iLtI3 X-Google-Smtp-Source: APXvYqykDRUMhIcshpGPuujbK9K4PYduP4ir6vp196MnlCRkoWhi+mp+/4fA1lRPEqEYC+eTWUjOQw== X-Received: by 2002:adf:dc44:: with SMTP id m4mr1896794wrj.203.1573034402940; Wed, 06 Nov 2019 02:00:02 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id f188sm2054994wmf.3.2019.11.06.02.00.02 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 06 Nov 2019 02:00:02 -0800 (PST) Message-Id: <4c3215e92bfd28cd815d92b8804cdcc8a7552a51.1573034387.git.gitgitgadget@gmail.com> In-Reply-To: References: From: "Heba Waly via GitGitGadget" Date: Wed, 06 Nov 2019 09:59:47 +0000 Subject: [PATCH v2 20/20] trace2: move doc to trace2.h Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Heba Waly , Junio C Hamano , Heba Waly Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Heba Waly Move the functions documentation from Documentation/technical/api-submodule-config.txt to submodule-config.h as it's easier for the developers to find the usage information beside the code instead of looking for it in another doc file. Only the functions documentation section is removed from Documentation/technical/api-submodule-config.txt as the file is full of more details that seemed more appropriate to be in a separate doc file as it is, with a link to the doc file added in the trace2.h. Also the functions doc is removed to avoid having redundandt info which will be hard to keep syncronized with the documentation in the header file. Signed-off-by: Heba Waly --- Documentation/technical/api-trace2.txt | 262 +------------------------ trace2.h | 146 +++++++++++--- 2 files changed, 125 insertions(+), 283 deletions(-) diff --git a/Documentation/technical/api-trace2.txt b/Documentation/technical/api-trace2.txt index a045dbe422..a2da5d8f31 100644 --- a/Documentation/technical/api-trace2.txt +++ b/Documentation/technical/api-trace2.txt @@ -182,267 +182,7 @@ All Trace2 API functions send a messsage to all of the active Trace2 Targets. This section describes the set of available messages. -It helps to divide these functions into groups for discussion -purposes. - -=== Basic Command Messages - -These are concerned with the lifetime of the overall git process. - -`void trace2_initialize_clock()`:: - - Initialize the Trace2 start clock and nothing else. This should - be called at the very top of main() to capture the process start - time and reduce startup order dependencies. - -`void trace2_initialize()`:: - - Determines if any Trace2 Targets should be enabled and - initializes the Trace2 facility. This includes setting up the - Trace2 thread local storage (TLS). -+ -This function emits a "version" message containing the version of git -and the Trace2 protocol. -+ -This function should be called from `main()` as early as possible in -the life of the process after essential process initialization. - -`int trace2_is_enabled()`:: - - Returns 1 if Trace2 is enabled (at least one target is - active). - -`void trace2_cmd_start(int argc, const char **argv)`:: - - Emits a "start" message containing the process command line - arguments. - -`int trace2_cmd_exit(int exit_code)`:: - - Emits an "exit" message containing the process exit-code and - elapsed time. -+ -Returns the exit-code. - -`void trace2_cmd_error(const char *fmt, va_list ap)`:: - - Emits an "error" message containing a formatted error message. - -`void trace2_cmd_path(const char *pathname)`:: - - Emits a "cmd_path" message with the full pathname of the - current process. - -=== Command Detail Messages - -These are concerned with describing the specific Git command -after the command line, config, and environment are inspected. - -`void trace2_cmd_name(const char *name)`:: - - Emits a "cmd_name" message with the canonical name of the - command, for example "status" or "checkout". - -`void trace2_cmd_mode(const char *mode)`:: - - Emits a "cmd_mode" message with a qualifier name to further - describe the current git command. -+ -This message is intended to be used with git commands having multiple -major modes. For example, a "checkout" command can checkout a new -branch or it can checkout a single file, so the checkout code could -emit a cmd_mode message of "branch" or "file". - -`void trace2_cmd_alias(const char *alias, const char **argv_expansion)`:: - - Emits an "alias" message containing the alias used and the - argument expansion. - -`void trace2_def_param(const char *parameter, const char *value)`:: - - Emits a "def_param" message containing a key/value pair. -+ -This message is intended to report some global aspect of the current -command, such as a configuration setting or command line switch that -significantly affects program performance or behavior, such as -`core.abbrev`, `status.showUntrackedFiles`, or `--no-ahead-behind`. - -`void trace2_cmd_list_config()`:: - - Emits a "def_param" messages for "important" configuration - settings. -+ -The environment variable `GIT_TRACE2_CONFIG_PARAMS` or the `trace2.configParams` -config value can be set to a -list of patterns of important configuration settings, for example: -`core.*,remote.*.url`. This function will iterate over all config -settings and emit a "def_param" message for each match. - -`void trace2_cmd_set_config(const char *key, const char *value)`:: - - Emits a "def_param" message for a new or updated key/value - pair IF `key` is considered important. -+ -This is used to hook into `git_config_set()` and catch any -configuration changes and update a value previously reported by -`trace2_cmd_list_config()`. - -`void trace2_def_repo(struct repository *repo)`:: - - Registers a repository with the Trace2 layer. Assigns a - unique "repo-id" to `repo->trace2_repo_id`. -+ -Emits a "worktree" messages containing the repo-id and the worktree -pathname. -+ -Region and data messages (described later) may refer to this repo-id. -+ -The main/top-level repository will have repo-id value 1 (aka "r1"). -+ -The repo-id field is in anticipation of future in-proc submodule -repositories. - -=== Child Process Messages - -These are concerned with the various spawned child processes, -including shell scripts, git commands, editors, pagers, and hooks. - -`void trace2_child_start(struct child_process *cmd)`:: - - Emits a "child_start" message containing the "child-id", - "child-argv", and "child-classification". -+ -Before calling this, set `cmd->trace2_child_class` to a name -describing the type of child process, for example "editor". -+ -This function assigns a unique "child-id" to `cmd->trace2_child_id`. -This field is used later during the "child_exit" message to associate -it with the "child_start" message. -+ -This function should be called before spawning the child process. - -`void trace2_child_exit(struct child_proess *cmd, int child_exit_code)`:: - - Emits a "child_exit" message containing the "child-id", - the child's elapsed time and exit-code. -+ -The reported elapsed time includes the process creation overhead and -time spend waiting for it to exit, so it may be slightly longer than -the time reported by the child itself. -+ -This function should be called after reaping the child process. - -`int trace2_exec(const char *exe, const char **argv)`:: - - Emits a "exec" message containing the "exec-id" and the - argv of the new process. -+ -This function should be called before calling one of the `exec()` -variants, such as `execvp()`. -+ -This function returns a unique "exec-id". This value is used later -if the exec() fails and a "exec-result" message is necessary. - -`void trace2_exec_result(int exec_id, int error_code)`:: - - Emits a "exec_result" message containing the "exec-id" - and the error code. -+ -On Unix-based systems, `exec()` does not return if successful. -This message is used to indicate that the `exec()` failed and -that the current program is continuing. - -=== Git Thread Messages - -These messages are concerned with Git thread usage. - -`void trace2_thread_start(const char *thread_name)`:: - - Emits a "thread_start" message. -+ -The `thread_name` field should be a descriptive name, such as the -unique name of the thread-proc. A unique "thread-id" will be added -to the name to uniquely identify thread instances. -+ -Region and data messages (described later) may refer to this thread -name. -+ -This function must be called by the thread-proc of the new thread -(so that TLS data is properly initialized) and not by the caller -of `pthread_create()`. - -`void trace2_thread_exit()`:: - - Emits a "thread_exit" message containing the thread name - and the thread elapsed time. -+ -This function must be called by the thread-proc before it returns -(so that the coorect TLS data is used and cleaned up. It should -not be called by the caller of `pthread_join()`. - -=== Region and Data Messages - -These are concerned with recording performance data -over regions or spans of code. - -`void trace2_region_enter(const char *category, const char *label, const struct repository *repo)`:: - -`void trace2_region_enter_printf(const char *category, const char *label, const struct repository *repo, const char *fmt, ...)`:: - -`void trace2_region_enter_printf_va(const char *category, const char *label, const struct repository *repo, const char *fmt, va_list ap)`:: - - Emits a thread-relative "region_enter" message with optional - printf string. -+ -This function pushes a new region nesting stack level on the current -thread and starts a clock for the new stack frame. -+ -The `category` field is an arbitrary category name used to classify -regions by feature area, such as "status" or "index". At this time -it is only just printed along with the rest of the message. It may -be used in the future to filter messages. -+ -The `label` field is an arbitrary label used to describe the activity -being started, such as "read_recursive" or "do_read_index". -+ -The `repo` field, if set, will be used to get the "repo-id", so that -recursive oerations can be attributed to the correct repository. - -`void trace2_region_leave(const char *category, const char *label, const struct repository *repo)`:: - -`void trace2_region_leave_printf(const char *category, const char *label, const struct repository *repo, const char *fmt, ...)`:: - -`void trace2_region_leave_printf_va(const char *category, const char *label, const struct repository *repo, const char *fmt, va_list ap)`:: - - Emits a thread-relative "region_leave" message with optional - printf string. -+ -This function pops the region nesting stack on the current thread -and reports the elapsed time of the stack frame. -+ -The `category`, `label`, and `repo` fields are the same as above. -The `category` and `label` do not need to match the correpsonding -"region_enter" message, but it makes the data stream easier to -understand. - -`void trace2_data_string(const char *category, const struct repository *repo, const char *key, const char * value)`:: - -`void trace2_data_intmax(const char *category, const struct repository *repo, const char *key, intmax value)`:: - -`void trace2_data_json(const char *category, const struct repository *repo, const char *key, const struct json_writer *jw)`:: - - Emits a region- and thread-relative "data" or "data_json" message. -+ -This is a key/value pair message containing information about the -current thread, region stack, and repository. This could be used -to print the number of files in a directory during a multi-threaded -recursive tree walk. - -`void trace2_printf(const char *fmt, ...)`:: - -`void trace2_printf_va(const char *fmt, va_list ap)`:: - - Emits a region- and thread-relative "printf" message. +Refer to trace2.h for details about trace2 functions. == Trace2 Target Formats diff --git a/trace2.h b/trace2.h index 050bf3c8c1..76bf6fddb8 100644 --- a/trace2.h +++ b/trace2.h @@ -1,6 +1,40 @@ #ifndef TRACE2_H #define TRACE2_H +/** + * The Trace2 API can be used to print debug, performance, and telemetry + * information to stderr or a file. The Trace2 feature is inactive unless + * explicitly enabled by enabling one or more Trace2 Targets. + * + * The Trace2 API is intended to replace the existing (Trace1) + * printf-style tracing provided by the existing `GIT_TRACE` and + * `GIT_TRACE_PERFORMANCE` facilities. During initial implementation, + * Trace2 and Trace1 may operate in parallel. + * + * The Trace2 API defines a set of high-level messages with known fields, + * such as (`start`: `argv`) and (`exit`: {`exit-code`, `elapsed-time`}). + * + * Trace2 instrumentation throughout the Git code base sends Trace2 + * messages to the enabled Trace2 Targets. Targets transform these + * messages content into purpose-specific formats and write events to + * their data streams. In this manner, the Trace2 API can drive + * many different types of analysis. + * + * Targets are defined using a VTable allowing easy extension to other + * formats in the future. This might be used to define a binary format, + * for example. + * + * Trace2 is controlled using `trace2.*` config values in the system and + * global config files and `GIT_TRACE2*` environment variables. Trace2 does + * not read from repo local or worktree config files or respect `-c` + * command line config settings. + * + * For more info about: trace2 targets, conventions for public functions and + * macros, trace2 target formats and examples on trace2 API usage refer to + * Documentation/technical/api-trace2.txt + * + */ + struct child_process; struct repository; struct json_writer; @@ -39,7 +73,12 @@ void trace2_initialize_clock(void); /* * Initialize TRACE2 tracing facility if any of the builtin TRACE2 * targets are enabled in the system config or the environment. - * Emits a 'version' event. + * This includes setting up the Trace2 thread local storage (TLS). + * Emits a 'version' message containing the version of git + * and the Trace2 protocol. + * + * This function should be called from `main()` as early as possible in + * the life of the process after essential process initialization. * * Cleanup/Termination is handled automatically by a registered * atexit() routine. @@ -49,7 +88,7 @@ void trace2_initialize_fl(const char *file, int line); #define trace2_initialize() trace2_initialize_fl(__FILE__, __LINE__) /* - * Return true if trace2 is enabled. + * Return 1 if trace2 is enabled (at least one target is active). */ int trace2_is_enabled(void); @@ -114,7 +153,8 @@ void trace2_cmd_mode_fl(const char *file, int line, const char *mode); #define trace2_cmd_mode(sv) trace2_cmd_mode_fl(__FILE__, __LINE__, (sv)) /* - * Emit an 'alias' expansion event. + * Emits an "alias" message containing the alias used and the argument + * expansion. */ void trace2_cmd_alias_fl(const char *file, int line, const char *alias, const char **argv); @@ -123,7 +163,7 @@ void trace2_cmd_alias_fl(const char *file, int line, const char *alias, trace2_cmd_alias_fl(__FILE__, __LINE__, (alias), (argv)) /* - * Emit one or more 'def_param' events for "interesting" configuration + * Emit one or more 'def_param' events for "important" configuration * settings. * * Use the TR2_SYSENV_CFG_PARAM setting to register a comma-separated @@ -144,7 +184,7 @@ void trace2_cmd_list_config_fl(const char *file, int line); /* * Emit a "def_param" event for the given config key/value pair IF - * we consider the key to be "interesting". + * we consider the key to be "important". * * Use this for new/updated config settings created/updated after * trace2_cmd_list_config() is called. @@ -155,20 +195,42 @@ void trace2_cmd_set_config_fl(const char *file, int line, const char *key, #define trace2_cmd_set_config(k, v) \ trace2_cmd_set_config_fl(__FILE__, __LINE__, (k), (v)) -/* - * Emit a 'child_start' event prior to spawning a child process. +/** + * Child Process Messages + * ---------------------- + * + * These are concerned with the various spawned child processes, + * including shell scripts, git commands, editors, pagers, and hooks. + */ + +/** + * Emits a "child_start" message containing the "child-id", + * "child-argv", and "child-classification". * * Before calling optionally set "cmd->trace2_child_class" to a string * describing the type of the child process. For example, "editor" or * "pager". + * + * This function assigns a unique "child-id" to `cmd->trace2_child_id`. + * This field is used later during the "child_exit" message to associate + * it with the "child_start" message. + * + * This function should be called before spawning the child process. */ void trace2_child_start_fl(const char *file, int line, struct child_process *cmd); #define trace2_child_start(cmd) trace2_child_start_fl(__FILE__, __LINE__, (cmd)) -/* - * Emit a 'child_exit' event after the child process completes. +/** + * Emits a "child_exit" message containing the "child-id", + * the child's elapsed time and exit-code. + * + * The reported elapsed time includes the process creation overhead and + * time spend waiting for it to exit, so it may be slightly longer than + * the time reported by the child itself. + * + * This function should be called after reaping the child process. */ void trace2_child_exit_fl(const char *file, int line, struct child_process *cmd, int child_exit_code); @@ -176,21 +238,22 @@ void trace2_child_exit_fl(const char *file, int line, struct child_process *cmd, #define trace2_child_exit(cmd, code) \ trace2_child_exit_fl(__FILE__, __LINE__, (cmd), (code)) -/* +/** * Emit an 'exec' event prior to calling one of exec(), execv(), * execvp(), and etc. On Unix-derived systems, this will be the * last event emitted for the current process, unless the exec * fails. On Windows, exec() behaves like 'child_start' and a * waitpid(), so additional events may be emitted. * - * Returns the "exec_id". + * Returns a unique "exec-id". This value is used later + * if the exec() fails and a "exec-result" message is necessary. */ int trace2_exec_fl(const char *file, int line, const char *exe, const char **argv); #define trace2_exec(exe, argv) trace2_exec_fl(__FILE__, __LINE__, (exe), (argv)) -/* +/** * Emit an 'exec_result' when possible. On Unix-derived systems, * this should be called after exec() returns (which only happens * when there is an error starting the new process). On Windows, @@ -203,6 +266,13 @@ void trace2_exec_result_fl(const char *file, int line, int exec_id, int code); #define trace2_exec_result(id, code) \ trace2_exec_result_fl(__FILE__, __LINE__, (id), (code)) + +/** + * Git Thread Messages + * ------------------- + * These messages are concerned with Git thread usage. + */ + /* * Emit a 'thread_start' event. This must be called from inside the * thread-proc to set up the trace2 TLS data for the thread. @@ -226,11 +296,12 @@ void trace2_thread_exit_fl(const char *file, int line); #define trace2_thread_exit() trace2_thread_exit_fl(__FILE__, __LINE__) /* - * Emit a 'param' event. + * Emits a "def_param" message containing a key/value pair. * - * Write a " = " pair describing some aspect of the - * run such as an important configuration setting or command line - * option that significantly changes command behavior. + * This message is intended to report some global aspect of the current + * command, such as a configuration setting or command line switch that + * significantly affects program performance or behavior, such as + * `core.abbrev`, `status.showUntrackedFiles`, or `--no-ahead-behind`. */ void trace2_def_param_fl(const char *file, int line, const char *param, const char *value); @@ -243,18 +314,42 @@ void trace2_def_param_fl(const char *file, int line, const char *param, * a trace2-repo-id to be used in subsequent activity events. * * Emits a 'worktree' event for this repo instance. + * + * Region and data messages may refer to this repo-id. + * + * The main/top-level repository will have repo-id value 1 (aka "r1"). + * + * The repo-id field is in anticipation of future in-proc submodule + * repositories. */ void trace2_def_repo_fl(const char *file, int line, struct repository *repo); #define trace2_def_repo(repo) trace2_def_repo_fl(__FILE__, __LINE__, repo) -/* +/** + * Region and Data Messages + * ------------------------ + * These are concerned with recording performance data over regions or spans + * of code. + */ + +/** * Emit a 'region_enter' event for .