Merge branch 'ab/config-based-hooks-base' into seen
[git] / t / helper / test-fsmonitor-client.c
1 /*
2  * test-fsmonitor-client.c: client code to send commands/requests to
3  * a `git fsmonitor--daemon` daemon.
4  */
5
6 #include "test-tool.h"
7 #include "cache.h"
8 #include "parse-options.h"
9 //#include "fsmonitor.h"
10 #include "fsmonitor-ipc.h"
11 //#include "compat/fsmonitor/fsmonitor-fs-listen.h"
12 //#include "fsmonitor--daemon.h"
13 //#include "simple-ipc.h"
14
15 #ifndef HAVE_FSMONITOR_DAEMON_BACKEND
16 int cmd__fsmonitor_client(int argc, const char **argv)
17 {
18         die("fsmonitor--daemon not available on this platform");
19 }
20 #else
21
22 /*
23  * Read the `.git/index` to get the last token written to the
24  * FSMonitor Index Extension.
25  */
26 static const char *get_token_from_index(void)
27 {
28         struct index_state *istate = the_repository->index;
29
30         if (do_read_index(istate, the_repository->index_file, 0) < 0)
31                 die("unable to read index file");
32         if (!istate->fsmonitor_last_update)
33                 die("index file does not have fsmonitor extension");
34
35         return istate->fsmonitor_last_update;
36 }
37
38 /*
39  * Send an IPC query to a `git-fsmonitor--daemon` daemon and
40  * ask for the changes since the given token or from the last
41  * token in the index extension.
42  *
43  * This will implicitly start a daemon process if necessary.  The
44  * daemon process will persist after we exit.
45  */
46 static int do_send_query(const char *token)
47 {
48         struct strbuf answer = STRBUF_INIT;
49         int ret;
50
51         if (!token || !*token)
52                 token = get_token_from_index();
53
54         ret = fsmonitor_ipc__send_query(token, &answer);
55         if (ret < 0)
56                 die(_("could not query fsmonitor--daemon"));
57
58         write_in_full(1, answer.buf, answer.len);
59         strbuf_release(&answer);
60
61         return 0;
62 }
63
64 /*
65  * Send a "flush" command to the `git-fsmonitor--daemon` (if running)
66  * and tell it to flush its cache.
67  *
68  * This feature is primarily used by the test suite to simulate a loss of
69  * sync with the filesystem where we miss kernel events.
70  */
71 static int do_send_flush(void)
72 {
73         struct strbuf answer = STRBUF_INIT;
74         int ret;
75
76         ret = fsmonitor_ipc__send_command("flush", &answer);
77         if (ret)
78                 return ret;
79
80         write_in_full(1, answer.buf, answer.len);
81         strbuf_release(&answer);
82
83         return 0;
84 }
85
86 int cmd__fsmonitor_client(int argc, const char **argv)
87 {
88         const char *subcmd;
89         const char *token = NULL;
90
91         const char * const fsmonitor_client_usage[] = {
92                 N_("test-helper fsmonitor-client query [<token>]"),
93                 N_("test-helper fsmonitor-client flush"),
94                 NULL,
95         };
96
97         struct option options[] = {
98                 OPT_STRING(0, "token", &token, N_("token"),
99                            N_("command token to send to the server")),
100                 OPT_END()
101         };
102
103         if (argc < 2)
104                 usage_with_options(fsmonitor_client_usage, options);
105
106         if (argc == 2 && !strcmp(argv[1], "-h"))
107                 usage_with_options(fsmonitor_client_usage, options);
108
109         subcmd = argv[1];
110         argv--;
111         argc++;
112
113         argc = parse_options(argc, argv, NULL, options, fsmonitor_client_usage, 0);
114
115         setup_git_directory();
116
117         if (!strcmp(subcmd, "query"))
118                 return !!do_send_query(token);
119
120         if (!strcmp(subcmd, "flush"))
121                 return !!do_send_flush();
122
123         die("Unhandled subcommand: '%s'", subcmd);
124 }
125 #endif