All of lore.kernel.org
 help / color / mirror / Atom feed
From: Junio C Hamano <gitster@pobox.com>
To: Christian Couder <chriscool@tuxfamily.org>
Cc: git@vger.kernel.org
Subject: Re: [PATCH 1/3] trailer: add a trailer.trimEmpty config option
Date: Sat, 07 Feb 2015 12:20:32 -0800	[thread overview]
Message-ID: <xmqq386hcw33.fsf@gitster.dls.corp.google.com> (raw)
In-Reply-To: <20150207131112.394.30858.chriscool@tuxfamily.org> (Christian Couder's message of "Sat, 07 Feb 2015 14:11:09 +0100")

Christian Couder <chriscool@tuxfamily.org> writes:

> This way people who always want trimed trailers
> don't need to specify it on the command line.

I sense that print_all() that cares about trimming illustrate a
design mistake in the original code structure.  Why isn't the entire
program structured like this instead?

    - read input and split that into three parts:

	struct {
		struct strbuf messsage_proper;

		struct trailers {
			int nr, alloc;
	                struct strbuf *array_of_trailers[];
		} trailers;

		struct strbuf lines_after_trailers;
	};

    - do "trailer stuff" by calling a central helper that does
      "trailer stuff" a pointer to the middle, trailers, struct.

      - when the trailer becomes a reusable subsystem, this central
        helper will become the primary entry point to the API.

      - "trailer stuff" will include adding new ones, removing
        existing ones, and rewriting lines.  What you do in the
        current process_command_line_args() and
        process_trailers_lists() [*1*] would come here.

    - write out the result, given the outermost struct.  This will
      become another entry point in the API.

Structured that way, callers will supply that outermost structure,
and can trust that the trailers subsystem will not molest
message_proper or lines_after_trailers part.  They can even process
the parts that the trailer subsystem would not touch, e.g. running
stripspace to the text in message_proper.

Viewed that way, it would be clear that "strip empty ones" should be
a new feature in the "trailer stuff", not just "filter out only
during the output phase".  Having it in the output phase does not
feel that the labor/responsibility is split in the right way.

Another problem I have with "filter out during the output phase"
comes from the semantics/correctness in the resulting code, and I
suspect that it would need to be done a lot earlier, before you
allow the logic such as "if I have X, do this, but if there is no X,
do this other thing".  If you have an X that is empty in the input,
trimming that before such logic kicks in and trimming that in the
final output phase would give different results, and I think the
latter would give a less intuitive result.

As this is the second time I have to point out that the data
structure used by the current code to hold the trailers and other
stuff to work on smells fishy, I would seriously consider cleaning
up the existing code to make it easier to allow us to later create
a reusable API and "trailer subsystem" out of it, before piling new
features on top of it, if I were you.

> Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
> ---
>  builtin/interpret-trailers.c |  2 +-
>  trailer.c                    | 13 ++++++++++---
>  trailer.h                    |  2 +-
>  3 files changed, 12 insertions(+), 5 deletions(-)
>
> diff --git a/builtin/interpret-trailers.c b/builtin/interpret-trailers.c
> index 46838d2..1adf814 100644
> --- a/builtin/interpret-trailers.c
> +++ b/builtin/interpret-trailers.c
> @@ -18,7 +18,7 @@ static const char * const git_interpret_trailers_usage[] = {
>  
>  int cmd_interpret_trailers(int argc, const char **argv, const char *prefix)
>  {
> -	int trim_empty = 0;
> +	int trim_empty = -1;
>  	struct string_list trailers = STRING_LIST_INIT_DUP;
>  
>  	struct option options[] = {
> diff --git a/trailer.c b/trailer.c
> index 623adeb..7614182 100644
> --- a/trailer.c
> +++ b/trailer.c
> @@ -36,6 +36,8 @@ static struct trailer_item *first_conf_item;
>  
>  static char *separators = ":";
>  
> +static int trim_empty;
> +
>  #define TRAILER_ARG_STRING "$ARG"
>  
>  static int after_or_end(enum action_where where)
> @@ -120,7 +122,7 @@ static void print_tok_val(const char *tok, const char *val)
>  		printf("%s%c %s\n", tok, separators[0], val);
>  }
>  
> -static void print_all(struct trailer_item *first, int trim_empty)
> +static void print_all(struct trailer_item *first)
>  {
>  	struct trailer_item *item;
>  	for (item = first; item; item = item->next) {
> @@ -509,6 +511,8 @@ static int git_trailer_default_config(const char *conf_key, const char *value, v
>  					value, conf_key);
>  		} else if (!strcmp(trailer_item, "separators")) {
>  			separators = xstrdup(value);
> +		} else if (!strcmp(trailer_item, "trimempty")) {
> +			trim_empty = git_config_bool(conf_key, value);
>  		}
>  	}
>  	return 0;
> @@ -842,7 +846,7 @@ static void free_all(struct trailer_item **first)
>  	}
>  }
>  
> -void process_trailers(const char *file, int trim_empty, struct string_list *trailers)
> +void process_trailers(const char *file, int trim, struct string_list *trailers)
>  {
>  	struct trailer_item *in_tok_first = NULL;
>  	struct trailer_item *in_tok_last = NULL;
> @@ -854,6 +858,9 @@ void process_trailers(const char *file, int trim_empty, struct string_list *trai
>  	git_config(git_trailer_default_config, NULL);
>  	git_config(git_trailer_config, NULL);
>  
> +	if (trim > -1)
> +		trim_empty = trim;
> +
>  	lines = read_input_file(file);
>  
>  	/* Print the lines before the trailers */
> @@ -863,7 +870,7 @@ void process_trailers(const char *file, int trim_empty, struct string_list *trai
>  
>  	process_trailers_lists(&in_tok_first, &in_tok_last, &arg_tok_first);
>  
> -	print_all(in_tok_first, trim_empty);
> +	print_all(in_tok_first);
>  
>  	free_all(&in_tok_first);
>  
> diff --git a/trailer.h b/trailer.h
> index 8eb25d5..4f481d0 100644
> --- a/trailer.h
> +++ b/trailer.h
> @@ -1,6 +1,6 @@
>  #ifndef TRAILER_H
>  #define TRAILER_H
>  
> -void process_trailers(const char *file, int trim_empty, struct string_list *trailers);
> +void process_trailers(const char *file, int trim, struct string_list *trailers);
>  
>  #endif /* TRAILER_H */

  reply	other threads:[~2015-02-07 20:20 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-02-07 13:11 [PATCH 1/3] trailer: add a trailer.trimEmpty config option Christian Couder
2015-02-07 20:20 ` Junio C Hamano [this message]
2015-02-07 22:19   ` Christian Couder
2015-02-09 18:23     ` Junio C Hamano
2015-02-10 21:58     ` Junio C Hamano
2015-02-10 22:06     ` Junio C Hamano

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=xmqq386hcw33.fsf@gitster.dls.corp.google.com \
    --to=gitster@pobox.com \
    --cc=chriscool@tuxfamily.org \
    --cc=git@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.