fsmonitor-settings: bare repos are incompatible with FSMonitor
Bare repos do not have a worktree, so there is nothing for the daemon watch. Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Jeff Hostetler committed
May 26, 2022 at 21:46 UTC
62a62a28308453ee830bb7e02cf732474a6e01a5
5 files changed
+186
-20
builtin/fsmonitor--daemon.c
+18
@@ -1423,6 +1423,7 @@ static int try_to_start_background_daemon(void)
1423
int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix)
1424
{
1425
const char *subcmd;
1426
+ enum fsmonitor_reason reason;
1427
int detach_console = 0;
1428
1429
struct option options[] = {
@@ -1449,6 +1450,23 @@ int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix)
1450
die(_("invalid 'ipc-threads' value (%d)"),
1451
fsmonitor__ipc_threads);
1452
1453
+ prepare_repo_settings(the_repository);
1454
+ /*
1455
+ * If the repo is fsmonitor-compatible, explicitly set IPC-mode
1456
+ * (without bothering to load the `core.fsmonitor` config settings).
1457
+ *
1458
+ * If the repo is not compatible, the repo-settings will be set to
1459
+ * incompatible rather than IPC, so we can use one of the __get
1460
+ * routines to detect the discrepancy.
1461
+ */
1462
+ fsm_settings__set_ipc(the_repository);
1463
+
1464
+ reason = fsm_settings__get_reason(the_repository);
1465
+ if (reason > FSMONITOR_REASON_OK)
1466
+ die("%s",
1467
+ fsm_settings__get_incompatible_msg(the_repository,
1468
+ reason));
1469
+
1470
if (!strcmp(subcmd, "start"))
1471
return !!try_to_start_background_daemon();
1472
builtin/update-index.c
+16
@@ -1237,6 +1237,22 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
1237
1238
if (fsmonitor > 0) {
1239
enum fsmonitor_mode fsm_mode = fsm_settings__get_mode(r);
1240
+ enum fsmonitor_reason reason = fsm_settings__get_reason(r);
1241
+
1242
+ /*
1243
+ * The user wants to turn on FSMonitor using the command
1244
+ * line argument. (We don't know (or care) whether that
1245
+ * is the IPC or HOOK version.)
1246
+ *
1247
+ * Use one of the __get routines to force load the FSMonitor
1248
+ * config settings into the repo-settings. That will detect
1249
+ * whether the file system is compatible so that we can stop
1250
+ * here with a nice error message.
1251
+ */
1252
+ if (reason > FSMONITOR_REASON_OK)
1253
+ die("%s",
1254
+ fsm_settings__get_incompatible_msg(r, reason));
1255
+
1256
if (fsm_mode == FSMONITOR_MODE_DISABLED) {
1257
warning(_("core.fsmonitor is unset; "
1258
"set it if you really want to "
fsmonitor-settings.c
+113
-20
@@ -9,23 +9,42 @@
9
*/
10
struct fsmonitor_settings {
11
enum fsmonitor_mode mode;
12
+ enum fsmonitor_reason reason;
13
char *hook_path;
14
};
15
15
-static void lookup_fsmonitor_settings(struct repository *r)
16
+static enum fsmonitor_reason check_for_incompatible(struct repository *r)
17
+{
18
+ if (!r->worktree) {
19
+ /*
20
+ * Bare repositories don't have a working directory and
21
+ * therefore have nothing to watch.
22
+ */
23
+ return FSMONITOR_REASON_BARE;
24
+ }
25
+
26
+ return FSMONITOR_REASON_OK;
27
+}
28
+
29
+static struct fsmonitor_settings *alloc_settings(void)
30
{
31
struct fsmonitor_settings *s;
32
+
33
+ CALLOC_ARRAY(s, 1);
34
+ s->mode = FSMONITOR_MODE_DISABLED;
35
+ s->reason = FSMONITOR_REASON_UNTESTED;
36
+
37
+ return s;
38
+}
39
+
40
+static void lookup_fsmonitor_settings(struct repository *r)
41
+{
42
const char *const_str;
43
int bool_value;
44
45
if (r->settings.fsmonitor)
46
return;
47
24
- CALLOC_ARRAY(s, 1);
25
- s->mode = FSMONITOR_MODE_DISABLED;
26
-
27
- r->settings.fsmonitor = s;
28
-
48
/*
49
* Overload the existing "core.fsmonitor" config setting (which
50
* has historically been either unset or a hook pathname) to
@@ -38,6 +57,8 @@ static void lookup_fsmonitor_settings(struct repository *r)
57
case 0: /* config value was set to <bool> */
58
if (bool_value)
59
fsm_settings__set_ipc(r);
60
+ else
61
+ fsm_settings__set_disabled(r);
62
return;
63
64
case 1: /* config value was unset */
@@ -53,18 +74,18 @@ static void lookup_fsmonitor_settings(struct repository *r)
74
return;
75
}
76
56
- if (!const_str || !*const_str)
57
- return;
58
-
59
- fsm_settings__set_hook(r, const_str);
77
+ if (const_str && *const_str)
78
+ fsm_settings__set_hook(r, const_str);
79
+ else
80
+ fsm_settings__set_disabled(r);
81
}
82
83
enum fsmonitor_mode fsm_settings__get_mode(struct repository *r)
84
{
85
if (!r)
86
r = the_repository;
66
-
67
- lookup_fsmonitor_settings(r);
87
+ if (!r->settings.fsmonitor)
88
+ lookup_fsmonitor_settings(r);
89
90
return r->settings.fsmonitor->mode;
91
}
@@ -73,31 +94,55 @@ const char *fsm_settings__get_hook_path(struct repository *r)
94
{
95
if (!r)
96
r = the_repository;
76
-
77
- lookup_fsmonitor_settings(r);
97
+ if (!r->settings.fsmonitor)
98
+ lookup_fsmonitor_settings(r);
99
100
return r->settings.fsmonitor->hook_path;
101
}
102
103
void fsm_settings__set_ipc(struct repository *r)
104
{
105
+ enum fsmonitor_reason reason = check_for_incompatible(r);
106
+
107
+ if (reason != FSMONITOR_REASON_OK) {
108
+ fsm_settings__set_incompatible(r, reason);
109
+ return;
110
+ }
111
+
112
+ /*
113
+ * Caller requested IPC explicitly, so avoid (possibly
114
+ * recursive) config lookup.
115
+ */
116
if (!r)
117
r = the_repository;
86
-
87
- lookup_fsmonitor_settings(r);
118
+ if (!r->settings.fsmonitor)
119
+ r->settings.fsmonitor = alloc_settings();
120
121
r->settings.fsmonitor->mode = FSMONITOR_MODE_IPC;
122
+ r->settings.fsmonitor->reason = reason;
123
FREE_AND_NULL(r->settings.fsmonitor->hook_path);
124
}
125
126
void fsm_settings__set_hook(struct repository *r, const char *path)
127
{
128
+ enum fsmonitor_reason reason = check_for_incompatible(r);
129
+
130
+ if (reason != FSMONITOR_REASON_OK) {
131
+ fsm_settings__set_incompatible(r, reason);
132
+ return;
133
+ }
134
+
135
+ /*
136
+ * Caller requested hook explicitly, so avoid (possibly
137
+ * recursive) config lookup.
138
+ */
139
if (!r)
140
r = the_repository;
97
-
98
- lookup_fsmonitor_settings(r);
141
+ if (!r->settings.fsmonitor)
142
+ r->settings.fsmonitor = alloc_settings();
143
144
r->settings.fsmonitor->mode = FSMONITOR_MODE_HOOK;
145
+ r->settings.fsmonitor->reason = reason;
146
FREE_AND_NULL(r->settings.fsmonitor->hook_path);
147
r->settings.fsmonitor->hook_path = strdup(path);
148
}
@@ -106,9 +151,57 @@ void fsm_settings__set_disabled(struct repository *r)
151
{
152
if (!r)
153
r = the_repository;
109
-
110
- lookup_fsmonitor_settings(r);
154
+ if (!r->settings.fsmonitor)
155
+ r->settings.fsmonitor = alloc_settings();
156
157
r->settings.fsmonitor->mode = FSMONITOR_MODE_DISABLED;
158
+ r->settings.fsmonitor->reason = FSMONITOR_REASON_OK;
159
+ FREE_AND_NULL(r->settings.fsmonitor->hook_path);
160
+}
161
+
162
+void fsm_settings__set_incompatible(struct repository *r,
163
+ enum fsmonitor_reason reason)
164
+{
165
+ if (!r)
166
+ r = the_repository;
167
+ if (!r->settings.fsmonitor)
168
+ r->settings.fsmonitor = alloc_settings();
169
+
170
+ r->settings.fsmonitor->mode = FSMONITOR_MODE_INCOMPATIBLE;
171
+ r->settings.fsmonitor->reason = reason;
172
FREE_AND_NULL(r->settings.fsmonitor->hook_path);
173
}
174
+
175
+enum fsmonitor_reason fsm_settings__get_reason(struct repository *r)
176
+{
177
+ if (!r)
178
+ r = the_repository;
179
+ if (!r->settings.fsmonitor)
180
+ lookup_fsmonitor_settings(r);
181
+
182
+ return r->settings.fsmonitor->reason;
183
+}
184
+
185
+char *fsm_settings__get_incompatible_msg(const struct repository *r,
186
+ enum fsmonitor_reason reason)
187
+{
188
+ struct strbuf msg = STRBUF_INIT;
189
+
190
+ switch (reason) {
191
+ case FSMONITOR_REASON_UNTESTED:
192
+ case FSMONITOR_REASON_OK:
193
+ goto done;
194
+
195
+ case FSMONITOR_REASON_BARE:
196
+ strbuf_addf(&msg,
197
+ _("bare repository '%s' is incompatible with fsmonitor"),
198
+ xgetcwd());
199
+ goto done;
200
+ }
201
+
202
+ BUG("Unhandled case in fsm_settings__get_incompatible_msg: '%d'",
203
+ reason);
204
+
205
+done:
206
+ return strbuf_detach(&msg, NULL);
207
+}
fsmonitor-settings.h
+16
@@ -4,18 +4,34 @@
4
struct repository;
5
6
enum fsmonitor_mode {
7
+ FSMONITOR_MODE_INCOMPATIBLE = -1, /* see _reason */
8
FSMONITOR_MODE_DISABLED = 0,
9
FSMONITOR_MODE_HOOK = 1, /* core.fsmonitor=<hook_path> */
10
FSMONITOR_MODE_IPC = 2, /* core.fsmonitor=<true> */
11
};
12
13
+/*
14
+ * Incompatibility reasons.
15
+ */
16
+enum fsmonitor_reason {
17
+ FSMONITOR_REASON_UNTESTED = 0,
18
+ FSMONITOR_REASON_OK, /* no incompatibility or when disabled */
19
+ FSMONITOR_REASON_BARE,
20
+};
21
+
22
void fsm_settings__set_ipc(struct repository *r);
23
void fsm_settings__set_hook(struct repository *r, const char *path);
24
void fsm_settings__set_disabled(struct repository *r);
25
+void fsm_settings__set_incompatible(struct repository *r,
26
+ enum fsmonitor_reason reason);
27
28
enum fsmonitor_mode fsm_settings__get_mode(struct repository *r);
29
const char *fsm_settings__get_hook_path(struct repository *r);
30
31
+enum fsmonitor_reason fsm_settings__get_reason(struct repository *r);
32
+char *fsm_settings__get_incompatible_msg(const struct repository *r,
33
+ enum fsmonitor_reason reason);
34
+
35
struct fsmonitor_settings;
36
37
#endif /* FSMONITOR_SETTINGS_H */
t/t7519-status-fsmonitor.sh
+23
@@ -55,6 +55,29 @@ test_lazy_prereq UNTRACKED_CACHE '
55
test $ret -ne 1
56
'
57
58
+# Test that we detect and disallow repos that are incompatible with FSMonitor.
59
+test_expect_success 'incompatible bare repo' '
60
+ test_when_finished "rm -rf ./bare-clone actual expect" &&
61
+ git init --bare bare-clone &&
62
+
63
+ test_must_fail \
64
+ git -C ./bare-clone -c core.fsmonitor=foo \
65
+ update-index --fsmonitor 2>actual &&
66
+ grep "bare repository .* is incompatible with fsmonitor" actual &&
67
+
68
+ test_must_fail \
69
+ git -C ./bare-clone -c core.fsmonitor=true \
70
+ update-index --fsmonitor 2>actual &&
71
+ grep "bare repository .* is incompatible with fsmonitor" actual
72
+'
73
+
74
+test_expect_success FSMONITOR_DAEMON 'run fsmonitor-daemon in bare repo' '
75
+ test_when_finished "rm -rf ./bare-clone actual" &&
76
+ git init --bare bare-clone &&
77
+ test_must_fail git -C ./bare-clone fsmonitor--daemon run 2>actual &&
78
+ grep "bare repository .* is incompatible with fsmonitor" actual
79
+'
80
+
81
test_expect_success 'setup' '
82
mkdir -p .git/hooks &&
83
: >tracked &&