Subject: Re: [PATCH v4 1/4] fsmonitor: add two new config options, allowRemote and socketDir

From: Junio C Hamano <[email-masked]>
Date: Wed, 31 Aug 2022 13:04:34 -0700

"Eric DeCosta via GitGitGadget" <[email-masked]> writes:

> From: Eric DeCosta <[email-masked]>
>
> Introduce two new configuration options
>
>    fsmonitor.allowRemote - setting this to true overrides fsmonitor's
>    default behavior of erroring out when enountering network file
>    systems. Additionly, when true, the Unix domain socket (UDS) file
>    used for IPC is located in $HOME rather than in the .git directory.
>
>    fsmonitor.socketDir - allows for the UDS file to be located
>    anywhere the user chooses rather $HOME.

Before describing "what they do", please justify why we need to add
them.  The usual way to do so is to start with some observation of
the status quo, and describe the "gap" between what can be done with
the current system and what the users would want to do.  It might
further be necessary to justify why "would want to do" is worthwhile
to support.  I suspect that you can do all of the above in a couple
of paragraphs, and you'd succeed if the solution you chose would
fall out as a natural consequence in the mind of readers who follow
your line of thought by reading these introductory paragraphs.  And
then after the stage is set like so, the above description of what
you chose to implement as a solution should come.

>  struct fsmonitor_settings {
>  	enum fsmonitor_mode mode;
>  	enum fsmonitor_reason reason;
> +	int allow_remote;

I am debating myuself if a comment like

	int allow_remote; /* -1: undecided, 0: unallowed, 1: allowed */

is necessary (I know it would help if we had one; I am just
wondering if it is too obvious).

>  	char *hook_path;
> +	char *sock_dir;
>  };
>  
>  static enum fsmonitor_reason check_for_incompatible(struct repository *r)
> @@ -43,6 +45,7 @@ static struct fsmonitor_settings *alloc_settings(void)
>  	CALLOC_ARRAY(s, 1);
>  	s->mode = FSMONITOR_MODE_DISABLED;
>  	s->reason = FSMONITOR_REASON_UNTESTED;
> +	s->allow_remote = -1;
>  
>  	return s;
>  }

OK.  socket_dir is naturally NULL at the start.

> @@ -100,6 +123,7 @@ enum fsmonitor_mode fsm_settings__get_mode(struct repository *r)
>  	return r->settings.fsmonitor->mode;
>  }
>  
> +
>  const char *fsm_settings__get_hook_path(struct repository *r)
>  {
>  	if (!r)

A noise hunk?

> @@ -110,9 +134,44 @@ const char *fsm_settings__get_hook_path(struct repository *r)
> ...
> +void fsm_settings__set_socket_dir(struct repository *r)
> +{
> +	const char *path;
> +
> +	if (!r)
> +		r = the_repository;
> +	if (!r->settings.fsmonitor)
> +		r->settings.fsmonitor = alloc_settings();
> +
> +	if (!repo_config_get_pathname(r, "fsmonitor.socketdir", &path)) {
> +		FREE_AND_NULL(r->settings.fsmonitor->sock_dir);
> +		r->settings.fsmonitor->sock_dir = strdup(path);

As we are overwriting it immediately, just calling free(), not
FREE_AND_NULL(), is more appropriate, isn't it?

> @@ -135,7 +194,11 @@ void fsm_settings__set_ipc(struct repository *r)
>  
>  void fsm_settings__set_hook(struct repository *r, const char *path)
>  {
> -	enum fsmonitor_reason reason = check_for_incompatible(r);
> +	enum fsmonitor_reason reason;
> +
> +	fsm_settings__set_allow_remote(r);
> +	fsm_settings__set_socket_dir(r);
> +	reason = check_for_incompatible(r);
>  
>  	if (reason != FSMONITOR_REASON_OK) {
>  		fsm_settings__set_incompatible(r, reason);
> diff --git a/fsmonitor-settings.h b/fsmonitor-settings.h
> index d9c2605197f..2de54c85e94 100644
> --- a/fsmonitor-settings.h
> +++ b/fsmonitor-settings.h
> @@ -23,12 +23,16 @@ enum fsmonitor_reason {
>  	FSMONITOR_REASON_NOSOCKETS, /* NTFS,FAT32 do not support Unix sockets */
>  };
>  
> +void fsm_settings__set_allow_remote(struct repository *r);
> +void fsm_settings__set_socket_dir(struct repository *r);

Do these two need to be extern?

I would imagine that implementations in compat/fsmonitor/* would
just call fsm_settings__set_hook() or __set_ipc() and that causes
these two to be called as part of the set-up sequence.  Do they need
to call these two directly?

If not, we probably should make them static.  I suspect that some
existing declarations in this header file fall into the same
category and may need to become static for the same reason, which
you can do as a preliminary clean-up patch, or post-clean-up after
the dust settles.  Regardless of which approach to take for existing
ones, we do not want to make it worse by adding new externally
visible names that do not have to be visible.

>  void fsm_settings__set_ipc(struct repository *r);
>  void fsm_settings__set_hook(struct repository *r, const char *path);
>  void fsm_settings__set_disabled(struct repository *r);
>  void fsm_settings__set_incompatible(struct repository *r,
>  				    enum fsmonitor_reason reason);
>  
> +int fsm_settings__get_allow_remote(struct repository *r);
> +const char *fsm_settings__get_socket_dir(struct repository *r);

On the other hand, these may need to be query-able by the
implementations.

>  enum fsmonitor_mode fsm_settings__get_mode(struct repository *r);
>  const char *fsm_settings__get_hook_path(struct repository *r);