Browse Source

fsmonitor-ipc: create client routines for git-fsmonitor--daemon

Create fsmonitor_ipc__*() client routines to spawn the built-in file
system monitor daemon and send it an IPC request using the `Simple
IPC` API.

Stub in empty fsmonitor_ipc__*() functions for unsupported platforms.

Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
maint
Jeff Hostetler 3 years ago committed by Junio C Hamano
parent
commit
d2bd862e7a
  1. 1
      Makefile
  2. 171
      fsmonitor-ipc.c
  3. 48
      fsmonitor-ipc.h

1
Makefile

@ -907,6 +907,7 @@ LIB_OBJS += fetch-pack.o @@ -907,6 +907,7 @@ LIB_OBJS += fetch-pack.o
LIB_OBJS += fmt-merge-msg.o
LIB_OBJS += fsck.o
LIB_OBJS += fsmonitor.o
LIB_OBJS += fsmonitor-ipc.o
LIB_OBJS += gettext.o
LIB_OBJS += gpg-interface.o
LIB_OBJS += graph.o

171
fsmonitor-ipc.c

@ -0,0 +1,171 @@ @@ -0,0 +1,171 @@
#include "cache.h"
#include "fsmonitor.h"
#include "simple-ipc.h"
#include "fsmonitor-ipc.h"
#include "run-command.h"
#include "strbuf.h"
#include "trace2.h"

#ifndef HAVE_FSMONITOR_DAEMON_BACKEND

/*
* A trivial implementation of the fsmonitor_ipc__ API for unsupported
* platforms.
*/

int fsmonitor_ipc__is_supported(void)
{
return 0;
}

const char *fsmonitor_ipc__get_path(void)
{
return NULL;
}

enum ipc_active_state fsmonitor_ipc__get_state(void)
{
return IPC_STATE__OTHER_ERROR;
}

int fsmonitor_ipc__send_query(const char *since_token,
struct strbuf *answer)
{
return -1;
}

int fsmonitor_ipc__send_command(const char *command,
struct strbuf *answer)
{
return -1;
}

#else

int fsmonitor_ipc__is_supported(void)
{
return 1;
}

GIT_PATH_FUNC(fsmonitor_ipc__get_path, "fsmonitor--daemon.ipc")

enum ipc_active_state fsmonitor_ipc__get_state(void)
{
return ipc_get_active_state(fsmonitor_ipc__get_path());
}

static int spawn_daemon(void)
{
const char *args[] = { "fsmonitor--daemon", "start", NULL };

return run_command_v_opt_tr2(args, RUN_COMMAND_NO_STDIN | RUN_GIT_CMD,
"fsmonitor");
}

int fsmonitor_ipc__send_query(const char *since_token,
struct strbuf *answer)
{
int ret = -1;
int tried_to_spawn = 0;
enum ipc_active_state state = IPC_STATE__OTHER_ERROR;
struct ipc_client_connection *connection = NULL;
struct ipc_client_connect_options options
= IPC_CLIENT_CONNECT_OPTIONS_INIT;
const char *tok = since_token ? since_token : "";
size_t tok_len = since_token ? strlen(since_token) : 0;

options.wait_if_busy = 1;
options.wait_if_not_found = 0;

trace2_region_enter("fsm_client", "query", NULL);
trace2_data_string("fsm_client", NULL, "query/command", tok);

try_again:
state = ipc_client_try_connect(fsmonitor_ipc__get_path(), &options,
&connection);

switch (state) {
case IPC_STATE__LISTENING:
ret = ipc_client_send_command_to_connection(
connection, tok, tok_len, answer);
ipc_client_close_connection(connection);

trace2_data_intmax("fsm_client", NULL,
"query/response-length", answer->len);
goto done;

case IPC_STATE__NOT_LISTENING:
case IPC_STATE__PATH_NOT_FOUND:
if (tried_to_spawn)
goto done;

tried_to_spawn++;
if (spawn_daemon())
goto done;

/*
* Try again, but this time give the daemon a chance to
* actually create the pipe/socket.
*
* Granted, the daemon just started so it can't possibly have
* any FS cached yet, so we'll always get a trivial answer.
* BUT the answer should include a new token that can serve
* as the basis for subsequent requests.
*/
options.wait_if_not_found = 1;
goto try_again;

case IPC_STATE__INVALID_PATH:
ret = error(_("fsmonitor_ipc__send_query: invalid path '%s'"),
fsmonitor_ipc__get_path());
goto done;

case IPC_STATE__OTHER_ERROR:
default:
ret = error(_("fsmonitor_ipc__send_query: unspecified error on '%s'"),
fsmonitor_ipc__get_path());
goto done;
}

done:
trace2_region_leave("fsm_client", "query", NULL);

return ret;
}

int fsmonitor_ipc__send_command(const char *command,
struct strbuf *answer)
{
struct ipc_client_connection *connection = NULL;
struct ipc_client_connect_options options
= IPC_CLIENT_CONNECT_OPTIONS_INIT;
int ret;
enum ipc_active_state state;
const char *c = command ? command : "";
size_t c_len = command ? strlen(command) : 0;

strbuf_reset(answer);

options.wait_if_busy = 1;
options.wait_if_not_found = 0;

state = ipc_client_try_connect(fsmonitor_ipc__get_path(), &options,
&connection);
if (state != IPC_STATE__LISTENING) {
die(_("fsmonitor--daemon is not running"));
return -1;
}

ret = ipc_client_send_command_to_connection(connection, c, c_len,
answer);
ipc_client_close_connection(connection);

if (ret == -1) {
die(_("could not send '%s' command to fsmonitor--daemon"), c);
return -1;
}

return 0;
}

#endif

48
fsmonitor-ipc.h

@ -0,0 +1,48 @@ @@ -0,0 +1,48 @@
#ifndef FSMONITOR_IPC_H
#define FSMONITOR_IPC_H

#include "simple-ipc.h"

/*
* Returns true if built-in file system monitor daemon is defined
* for this platform.
*/
int fsmonitor_ipc__is_supported(void);

/*
* Returns the pathname to the IPC named pipe or Unix domain socket
* where a `git-fsmonitor--daemon` process will listen. This is a
* per-worktree value.
*
* Returns NULL if the daemon is not supported on this platform.
*/
const char *fsmonitor_ipc__get_path(void);

/*
* Try to determine whether there is a `git-fsmonitor--daemon` process
* listening on the IPC pipe/socket.
*/
enum ipc_active_state fsmonitor_ipc__get_state(void);

/*
* Connect to a `git-fsmonitor--daemon` process via simple-ipc
* and ask for the set of changed files since the given token.
*
* Spawn a daemon process in the background if necessary.
*
* Returns -1 on error; 0 on success.
*/
int fsmonitor_ipc__send_query(const char *since_token,
struct strbuf *answer);

/*
* Connect to a `git-fsmonitor--daemon` process via simple-ipc and
* send a command verb. If no daemon is available, we DO NOT try to
* start one.
*
* Returns -1 on error; 0 on success.
*/
int fsmonitor_ipc__send_command(const char *command,
struct strbuf *answer);

#endif /* FSMONITOR_IPC_H */
Loading…
Cancel
Save