Skip to content

Commit bc820cf

Browse files
committed
Merge branch 'vd/scalar-enables-fsmonitor'
"scalar" now enables built-in fsmonitor on enlisted repositories, when able. * vd/scalar-enables-fsmonitor: scalar: update technical doc roadmap with FSMonitor support scalar unregister: stop FSMonitor daemon scalar: enable built-in FSMonitor on `register` scalar: move config setting logic into its own function scalar-delete: do not 'die()' in 'delete_enlistment()' scalar-[un]register: clearly indicate source of error scalar-unregister: handle error codes greater than 0 scalar: constrain enlistment search
2 parents 0b08ba7 + 8e28418 commit bc820cf

File tree

3 files changed

+220
-91
lines changed

3 files changed

+220
-91
lines changed

Documentation/technical/scalar.txt

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -87,17 +87,20 @@ series have been accepted:
8787
- `scalar-generalize-diagnose`: Move the functionality of `scalar diagnose`
8888
into `git diagnose` and `git bugreport --diagnose`.
8989

90+
- 'scalar-add-fsmonitor: Enable the built-in FSMonitor in Scalar
91+
enlistments. At the end of this series, Scalar should be feature-complete
92+
from the perspective of a user.
93+
9094
Roughly speaking (and subject to change), the following series are needed to
9195
"finish" this initial version of Scalar:
9296

93-
- Finish Scalar features: Enable the built-in FSMonitor in Scalar enlistments
94-
and implement `scalar help`. At the end of this series, Scalar should be
95-
feature-complete from the perspective of a user.
96-
9797
- Move Scalar to toplevel: Move Scalar out of `contrib/` and into the root of
98-
`git`, including updates to build and install it with the rest of Git. This
99-
change will incorporate Scalar into the Git CI and test framework, as well as
100-
expand regression and performance testing to ensure the tool is stable.
98+
`git`. This includes a variety of related updates, including:
99+
- building & installing Scalar in the Git root-level 'make [install]'.
100+
- builing & testing Scalar as part of CI.
101+
- moving and expanding test coverage of Scalar (including perf tests).
102+
- implementing 'scalar help'/'git help scalar' to display scalar
103+
documentation.
101104

102105
Finally, there are two additional patch series that exist in Microsoft's fork of
103106
Git, but there is no current plan to upstream them. There are some interesting

contrib/scalar/scalar.c

Lines changed: 117 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -7,34 +7,22 @@
77
#include "parse-options.h"
88
#include "config.h"
99
#include "run-command.h"
10+
#include "simple-ipc.h"
11+
#include "fsmonitor-ipc.h"
12+
#include "fsmonitor-settings.h"
1013
#include "refs.h"
1114
#include "dir.h"
1215
#include "packfile.h"
1316
#include "help.h"
1417

15-
/*
16-
* Remove the deepest subdirectory in the provided path string. Path must not
17-
* include a trailing path separator. Returns 1 if parent directory found,
18-
* otherwise 0.
19-
*/
20-
static int strbuf_parent_directory(struct strbuf *buf)
21-
{
22-
size_t len = buf->len;
23-
size_t offset = offset_1st_component(buf->buf);
24-
char *path_sep = find_last_dir_sep(buf->buf + offset);
25-
strbuf_setlen(buf, path_sep ? path_sep - buf->buf : offset);
26-
27-
return buf->len < len;
28-
}
29-
3018
static void setup_enlistment_directory(int argc, const char **argv,
3119
const char * const *usagestr,
3220
const struct option *options,
3321
struct strbuf *enlistment_root)
3422
{
3523
struct strbuf path = STRBUF_INIT;
36-
char *root;
37-
int enlistment_found = 0;
24+
int enlistment_is_repo_parent = 0;
25+
size_t len;
3826

3927
if (startup_info->have_repository)
4028
BUG("gitdir already set up?!?");
@@ -47,51 +35,36 @@ static void setup_enlistment_directory(int argc, const char **argv,
4735
strbuf_add_absolute_path(&path, argv[0]);
4836
if (!is_directory(path.buf))
4937
die(_("'%s' does not exist"), path.buf);
38+
if (chdir(path.buf) < 0)
39+
die_errno(_("could not switch to '%s'"), path.buf);
5040
} else if (strbuf_getcwd(&path) < 0)
5141
die(_("need a working directory"));
5242

5343
strbuf_trim_trailing_dir_sep(&path);
54-
do {
55-
const size_t len = path.len;
5644

57-
/* check if currently in enlistment root with src/ workdir */
58-
strbuf_addstr(&path, "/src");
59-
if (is_nonbare_repository_dir(&path)) {
60-
if (enlistment_root)
61-
strbuf_add(enlistment_root, path.buf, len);
62-
63-
enlistment_found = 1;
64-
break;
65-
}
66-
67-
/* reset to original path */
68-
strbuf_setlen(&path, len);
69-
70-
/* check if currently in workdir */
71-
if (is_nonbare_repository_dir(&path)) {
72-
if (enlistment_root) {
73-
/*
74-
* If the worktree's directory's name is `src`, the enlistment is the
75-
* parent directory, otherwise it is identical to the worktree.
76-
*/
77-
root = strip_path_suffix(path.buf, "src");
78-
strbuf_addstr(enlistment_root, root ? root : path.buf);
79-
free(root);
80-
}
45+
/* check if currently in enlistment root with src/ workdir */
46+
len = path.len;
47+
strbuf_addstr(&path, "/src");
48+
if (is_nonbare_repository_dir(&path)) {
49+
enlistment_is_repo_parent = 1;
50+
if (chdir(path.buf) < 0)
51+
die_errno(_("could not switch to '%s'"), path.buf);
52+
}
53+
strbuf_setlen(&path, len);
8154

82-
enlistment_found = 1;
83-
break;
84-
}
85-
} while (strbuf_parent_directory(&path));
55+
setup_git_directory();
8656

87-
if (!enlistment_found)
88-
die(_("could not find enlistment root"));
57+
if (!the_repository->worktree)
58+
die(_("Scalar enlistments require a worktree"));
8959

90-
if (chdir(path.buf) < 0)
91-
die_errno(_("could not switch to '%s'"), path.buf);
60+
if (enlistment_root) {
61+
if (enlistment_is_repo_parent)
62+
strbuf_addbuf(enlistment_root, &path);
63+
else
64+
strbuf_addstr(enlistment_root, the_repository->worktree);
65+
}
9266

9367
strbuf_release(&path);
94-
setup_git_directory();
9568
}
9669

9770
static int run_git(const char *arg, ...)
@@ -113,13 +86,39 @@ static int run_git(const char *arg, ...)
11386
return res;
11487
}
11588

89+
struct scalar_config {
90+
const char *key;
91+
const char *value;
92+
int overwrite_on_reconfigure;
93+
};
94+
95+
static int set_scalar_config(const struct scalar_config *config, int reconfigure)
96+
{
97+
char *value = NULL;
98+
int res;
99+
100+
if ((reconfigure && config->overwrite_on_reconfigure) ||
101+
git_config_get_string(config->key, &value)) {
102+
trace2_data_string("scalar", the_repository, config->key, "created");
103+
res = git_config_set_gently(config->key, config->value);
104+
} else {
105+
trace2_data_string("scalar", the_repository, config->key, "exists");
106+
res = 0;
107+
}
108+
109+
free(value);
110+
return res;
111+
}
112+
113+
static int have_fsmonitor_support(void)
114+
{
115+
return fsmonitor_ipc__is_supported() &&
116+
fsm_settings__get_reason(the_repository) == FSMONITOR_REASON_OK;
117+
}
118+
116119
static int set_recommended_config(int reconfigure)
117120
{
118-
struct {
119-
const char *key;
120-
const char *value;
121-
int overwrite_on_reconfigure;
122-
} config[] = {
121+
struct scalar_config config[] = {
123122
/* Required */
124123
{ "am.keepCR", "true", 1 },
125124
{ "core.FSCache", "true", 1 },
@@ -173,17 +172,16 @@ static int set_recommended_config(int reconfigure)
173172
char *value;
174173

175174
for (i = 0; config[i].key; i++) {
176-
if ((reconfigure && config[i].overwrite_on_reconfigure) ||
177-
git_config_get_string(config[i].key, &value)) {
178-
trace2_data_string("scalar", the_repository, config[i].key, "created");
179-
if (git_config_set_gently(config[i].key,
180-
config[i].value) < 0)
181-
return error(_("could not configure %s=%s"),
182-
config[i].key, config[i].value);
183-
} else {
184-
trace2_data_string("scalar", the_repository, config[i].key, "exists");
185-
free(value);
186-
}
175+
if (set_scalar_config(config + i, reconfigure))
176+
return error(_("could not configure %s=%s"),
177+
config[i].key, config[i].value);
178+
}
179+
180+
if (have_fsmonitor_support()) {
181+
struct scalar_config fsmonitor = { "core.fsmonitor", "true" };
182+
if (set_scalar_config(&fsmonitor, reconfigure))
183+
return error(_("could not configure %s=%s"),
184+
fsmonitor.key, fsmonitor.value);
187185
}
188186

189187
/*
@@ -234,28 +232,53 @@ static int add_or_remove_enlistment(int add)
234232
"scalar.repo", the_repository->worktree, NULL);
235233
}
236234

235+
static int start_fsmonitor_daemon(void)
236+
{
237+
assert(have_fsmonitor_support());
238+
239+
if (fsmonitor_ipc__get_state() != IPC_STATE__LISTENING)
240+
return run_git("fsmonitor--daemon", "start", NULL);
241+
242+
return 0;
243+
}
244+
245+
static int stop_fsmonitor_daemon(void)
246+
{
247+
assert(have_fsmonitor_support());
248+
249+
if (fsmonitor_ipc__get_state() == IPC_STATE__LISTENING)
250+
return run_git("fsmonitor--daemon", "stop", NULL);
251+
252+
return 0;
253+
}
254+
237255
static int register_dir(void)
238256
{
239-
int res = add_or_remove_enlistment(1);
257+
if (add_or_remove_enlistment(1))
258+
return error(_("could not add enlistment"));
240259

241-
if (!res)
242-
res = set_recommended_config(0);
260+
if (set_recommended_config(0))
261+
return error(_("could not set recommended config"));
243262

244-
if (!res)
245-
res = toggle_maintenance(1);
263+
if (toggle_maintenance(1))
264+
return error(_("could not turn on maintenance"));
246265

247-
return res;
266+
if (have_fsmonitor_support() && start_fsmonitor_daemon()) {
267+
return error(_("could not start the FSMonitor daemon"));
268+
}
269+
270+
return 0;
248271
}
249272

250273
static int unregister_dir(void)
251274
{
252275
int res = 0;
253276

254-
if (toggle_maintenance(0) < 0)
255-
res = -1;
277+
if (toggle_maintenance(0))
278+
res = error(_("could not turn off maintenance"));
256279

257-
if (add_or_remove_enlistment(0) < 0)
258-
res = -1;
280+
if (add_or_remove_enlistment(0))
281+
res = error(_("could not remove enlistment"));
259282

260283
return res;
261284
}
@@ -336,25 +359,35 @@ static int delete_enlistment(struct strbuf *enlistment)
336359
{
337360
#ifdef WIN32
338361
struct strbuf parent = STRBUF_INIT;
362+
size_t offset;
363+
char *path_sep;
339364
#endif
340365

341366
if (unregister_dir())
342-
die(_("failed to unregister repository"));
367+
return error(_("failed to unregister repository"));
343368

344369
#ifdef WIN32
345370
/*
346371
* Change the current directory to one outside of the enlistment so
347372
* that we may delete everything underneath it.
348373
*/
349-
strbuf_addbuf(&parent, enlistment);
350-
strbuf_parent_directory(&parent);
351-
if (chdir(parent.buf) < 0)
352-
die_errno(_("could not switch to '%s'"), parent.buf);
374+
offset = offset_1st_component(enlistment->buf);
375+
path_sep = find_last_dir_sep(enlistment->buf + offset);
376+
strbuf_add(&parent, enlistment->buf,
377+
path_sep ? path_sep - enlistment->buf : offset);
378+
if (chdir(parent.buf) < 0) {
379+
int res = error_errno(_("could not switch to '%s'"), parent.buf);
380+
strbuf_release(&parent);
381+
return res;
382+
}
353383
strbuf_release(&parent);
354384
#endif
355385

386+
if (have_fsmonitor_support() && stop_fsmonitor_daemon())
387+
return error(_("failed to stop the FSMonitor daemon"));
388+
356389
if (remove_dir_recursively(enlistment, 0))
357-
die(_("failed to delete enlistment directory"));
390+
return error(_("failed to delete enlistment directory"));
358391

359392
return 0;
360393
}

0 commit comments

Comments
 (0)