Skip to content

Commit d0d93cd

Browse files
committed
cli/discover(feat[config-scope]): honor user vs project workspace labels (#487)
1 parent 538803d commit d0d93cd

File tree

1 file changed

+78
-4
lines changed

1 file changed

+78
-4
lines changed

src/vcspull/cli/discover.py

Lines changed: 78 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,62 @@
2828

2929
log = logging.getLogger(__name__)
3030

31+
ConfigScope = t.Literal["system", "user", "project", "external"]
32+
33+
34+
def _classify_config_scope(
35+
config_path: pathlib.Path,
36+
*,
37+
cwd: pathlib.Path,
38+
home: pathlib.Path,
39+
) -> ConfigScope:
40+
"""Determine whether a config lives in user, system, project, or external scope."""
41+
42+
resolved = config_path.expanduser().resolve()
43+
home = home.expanduser().resolve()
44+
cwd = cwd.expanduser().resolve()
45+
46+
default_user_configs = {
47+
(home / ".vcspull.yaml").resolve(),
48+
(home / ".vcspull.json").resolve(),
49+
}
50+
if resolved in default_user_configs:
51+
return "user"
52+
53+
xdg_config_home = pathlib.Path(
54+
os.environ.get("XDG_CONFIG_HOME", home / ".config")
55+
).expanduser().resolve()
56+
user_config_root = (xdg_config_home / "vcspull").resolve()
57+
try:
58+
resolved.relative_to(user_config_root)
59+
return "user"
60+
except ValueError:
61+
pass
62+
63+
xdg_config_dirs_value = os.environ.get("XDG_CONFIG_DIRS")
64+
if xdg_config_dirs_value:
65+
config_dir_bases = [
66+
pathlib.Path(entry).expanduser().resolve()
67+
for entry in xdg_config_dirs_value.split(os.pathsep)
68+
if entry
69+
]
70+
else:
71+
config_dir_bases = [pathlib.Path("/etc/xdg").resolve()]
72+
73+
for base in config_dir_bases:
74+
candidate = (base / "vcspull").resolve()
75+
try:
76+
resolved.relative_to(candidate)
77+
return "system"
78+
except ValueError:
79+
continue
80+
81+
try:
82+
resolved.relative_to(cwd)
83+
return "project"
84+
except ValueError:
85+
return "external"
86+
3187

3288
def get_git_origin_url(repo_path: pathlib.Path) -> str | None:
3389
"""Get the origin URL from a git repository.
@@ -199,6 +255,11 @@ def discover_repos(
199255

200256
display_config_path = str(PrivatePath(config_file_path))
201257

258+
cwd = pathlib.Path.cwd()
259+
home = pathlib.Path.home()
260+
config_scope = _classify_config_scope(config_file_path, cwd=cwd, home=home)
261+
allow_relative_workspace = config_scope == "project"
262+
202263
raw_config: dict[str, t.Any]
203264
duplicate_root_occurrences: dict[str, list[t.Any]]
204265
if config_file_path.exists() and config_file_path.is_file():
@@ -288,8 +349,8 @@ def discover_repos(
288349
"" if occurrence_count == 1 else "s",
289350
)
290351

291-
cwd = pathlib.Path.cwd()
292-
home = pathlib.Path.home()
352+
explicit_relative_override = workspace_root_override in {".", "./"}
353+
preserve_cwd_label = explicit_relative_override or allow_relative_workspace
293354

294355
if merge_duplicates:
295356
(
@@ -301,6 +362,7 @@ def discover_repos(
301362
raw_config,
302363
cwd=cwd,
303364
home=home,
365+
preserve_cwd_label=preserve_cwd_label,
304366
)
305367
else:
306368
(
@@ -312,6 +374,7 @@ def discover_repos(
312374
raw_config,
313375
cwd=cwd,
314376
home=home,
377+
preserve_cwd_label=preserve_cwd_label,
315378
)
316379

317380
for message in merge_conflicts:
@@ -378,7 +441,12 @@ def discover_repos(
378441
for name, url, workspace_path in found_repos:
379442
workspace_label = workspace_map.get(workspace_path)
380443
if workspace_label is None:
381-
workspace_label = workspace_root_label(workspace_path, cwd=cwd, home=home)
444+
workspace_label = workspace_root_label(
445+
workspace_path,
446+
cwd=cwd,
447+
home=home,
448+
preserve_cwd_label=preserve_cwd_label,
449+
)
382450
workspace_map[workspace_path] = workspace_label
383451
raw_config.setdefault(workspace_label, {})
384452

@@ -416,6 +484,7 @@ def discover_repos(
416484
workspace_path,
417485
cwd=cwd,
418486
home=home,
487+
preserve_cwd_label=preserve_cwd_label,
419488
)
420489
workspace_map[workspace_path] = workspace_label
421490
raw_config.setdefault(workspace_label, {})
@@ -517,7 +586,12 @@ def discover_repos(
517586
for repo_name, repo_url, workspace_path in repos_to_add:
518587
workspace_label = workspace_map.get(workspace_path)
519588
if workspace_label is None:
520-
workspace_label = workspace_root_label(workspace_path, cwd=cwd, home=home)
589+
workspace_label = workspace_root_label(
590+
workspace_path,
591+
cwd=cwd,
592+
home=home,
593+
preserve_cwd_label=preserve_cwd_label,
594+
)
521595
workspace_map[workspace_path] = workspace_label
522596

523597
if workspace_label not in raw_config:

0 commit comments

Comments
 (0)