Config - vcspull.config

Configuration functionality for vcspull.

vcspull.config.expand_dir(dir_, cwd=pathlib.Path.cwd)
function[source]
function[source]
vcspull.config.expand_dir(dir_, cwd=pathlib.Path.cwd)

Return path with environmental variables and tilde ~ expanded.

Parameters:
Returns:

Absolute directory path

Return type:

pathlib.Path

vcspull.config.normalize_config_file_path(path, cwd=pathlib.Path.cwd)
function[source]
function[source]
vcspull.config.normalize_config_file_path(path, cwd=pathlib.Path.cwd)

Return absolute config file path without resolving symlinks.

Symlink entry names are preserved intact so that downstream operations (e.g. atomic writes) can resolve them as needed, while the logical path is used for display and identity.

Parameters:
Returns:

Absolute config file path with symlink names preserved.

Return type:

pathlib.Path

Examples

>>> normalize_config_file_path(pathlib.Path("~/cfg.yaml")).name
'cfg.yaml'
>>> normalize_config_file_path(
...     pathlib.Path("configs/vcspull.yaml"),
...     cwd=pathlib.Path("/tmp/project"),
... )
PosixPath('.../configs/vcspull.yaml')
vcspull.config._validate_worktrees_config(worktrees_raw, repo_name)
function[source]
function[source]
vcspull.config._validate_worktrees_config(worktrees_raw, repo_name)

Validate and normalize worktrees configuration.

Parameters:
  • worktrees_raw (Any) – Raw worktrees configuration from YAML/JSON.

  • repo_name (str) – Name of the parent repository (for error messages).

Returns:

Validated list of worktree configurations.

Return type:

list[WorktreeConfigDict]

Raises:

VCSPullException – If the worktrees configuration is invalid.

Examples

Valid configuration with a tag:

>>> from vcspull.config import _validate_worktrees_config
>>> config = [{"dir": "../v1", "tag": "v1.0.0"}]
>>> result = _validate_worktrees_config(config, "myrepo")
>>> len(result)
1
>>> result[0]["dir"]
'../v1'
>>> result[0]["tag"]
'v1.0.0'

Valid configuration with a branch:

>>> config = [{"dir": "../dev", "branch": "develop"}]
>>> result = _validate_worktrees_config(config, "myrepo")
>>> result[0]["branch"]
'develop'

Valid configuration with a commit:

>>> config = [{"dir": "../fix", "commit": "abc123"}]
>>> result = _validate_worktrees_config(config, "myrepo")
>>> result[0]["commit"]
'abc123'

Error: worktrees must be a list:

>>> _validate_worktrees_config("not-a-list", "myrepo")
Traceback (most recent call last):
    ...
vcspull.exc.VCSPullException: ...worktrees must be a list, got str

Error: worktree entry must be a dict:

>>> _validate_worktrees_config(["not-a-dict"], "myrepo")
Traceback (most recent call last):
    ...
vcspull.exc.VCSPullException: ...must be a dict, got str

Error: missing required ‘dir’ field:

>>> _validate_worktrees_config([{"tag": "v1.0.0"}], "myrepo")
Traceback (most recent call last):
    ...
vcspull.exc.VCSPullException: ...missing required 'dir' field

Error: no ref type specified:

>>> _validate_worktrees_config([{"dir": "../wt"}], "myrepo")
Traceback (most recent call last):
    ...
vcspull.exc.VCSPullException: ...must specify one of: tag, branch, or commit

Error: empty ref value:

>>> _validate_worktrees_config([{"dir": "../wt", "tag": ""}], "myrepo")
Traceback (most recent call last):
    ...
vcspull.exc.VCSPullException: ...empty ref value...

Error: multiple refs specified:

>>> _validate_worktrees_config(
...     [{"dir": "../wt", "tag": "v1", "branch": "main"}], "myrepo"
... )
Traceback (most recent call last):
    ...
vcspull.exc.VCSPullException: ...cannot specify multiple refs...
vcspull.config.extract_repos(config, cwd=pathlib.Path.cwd)
function[source]
function[source]
vcspull.config.extract_repos(config, cwd=pathlib.Path.cwd)

Return expanded configuration.

end-user configuration permit inline configuration shortcuts, expand to identical format for parsing.

Parameters:
  • config (dict) – the repo config in dict format.

  • cwd (pathlib.Path) – current working dir (for deciphering relative paths)

Returns:

list

Return type:

List of normalized repository information

vcspull.config.find_home_config_files(filetype=None)
function[source]
function[source]
vcspull.config.find_home_config_files(filetype=None)

Return configs of .vcspull.{yaml,json} in user’s home directory.

The returned path preserves the logical home entry name so callers keep the config type implied by .yaml or .json even when the file is a symlink.

Parameters:

filetype (list of str, optional) – File types to search for (default ["json", "yaml"])

Returns:

Absolute paths to discovered config files

Return type:

list of pathlib.Path

Examples

>>> find_home_config_files()
[]
vcspull.config.find_config_files(path=None, match=None, filetype=None, include_home=False)
function[source]
function[source]
vcspull.config.find_config_files(path=None, match=None, filetype=None, include_home=False)

Return repos from a directory and match. Not recursive.

Parameters:
  • path (list) – list of paths to search

  • match (list) – list of globs to search against

  • filetype (list) – of filetypes to search against

  • include_home (bool) – Include home configuration files

Raises:

LoadConfigRepoConflict : – There are two configs that have same path and name with different repo urls.

Returns:

list of absolute paths to config files.

Return type:

list

vcspull.config.load_configs(files, cwd=pathlib.Path.cwd, *, merge_duplicates=True, warn_legacy_options=False)
function[source]
function[source]
vcspull.config.load_configs(files, cwd=pathlib.Path.cwd, *, merge_duplicates=True, warn_legacy_options=False)

Return repos from a list of files.

Parameters:
Returns:

expanded config dict item

Return type:

list of dict

vcspull.config.detect_duplicate_repos(config1, config2)
function[source]
function[source]
vcspull.config.detect_duplicate_repos(config1, config2)

Return duplicate repos dict if repo_dir same and vcs different.

Parameters:
Returns:

List of duplicate tuples

Return type:

list[tuple[ConfigDict, ConfigDict]]

vcspull.config.in_dir(config_dir=None, extensions=None)
function[source]
function[source]
vcspull.config.in_dir(config_dir=None, extensions=None)

Return a list of configs in config_dir.

Parameters:
  • config_dir (str) – directory to search

  • extensions (list) – filetypes to check (e.g. ['.yaml', '.json']).

Return type:

list

vcspull.config.filter_repos(config, path=None, vcs_url=None, name=None)
function[source]
function[source]
vcspull.config.filter_repos(config, path=None, vcs_url=None, name=None)

Return a list list of repos from (expanded) config file.

path, vcs_url and name all support fnmatch.

Parameters:
  • config (dict) – the expanded repo config in dict format.

  • path (str, Optional) – directory of checkout location, fnmatch pattern supported

  • vcs_url (str, Optional) – url of vcs remote, fn match pattern supported

  • name (str, Optional) – project name, fnmatch pattern supported

Returns:

Repos

Return type:

list

vcspull.config.is_config_file(filename, extensions=None)
function[source]
function[source]
vcspull.config.is_config_file(filename, extensions=None)

Return True if file has a valid config file type.

Parameters:
  • filename (str) – filename to check (e.g. mysession.json).

  • extensions (list or str) – filetypes to check (e.g. ['.yaml', '.json']).

Returns:

bool

Return type:

True if is a valid config file type

vcspull.config._atomic_write(target, content)
function[source]
function[source]
vcspull.config._atomic_write(target, content)

Write content to a file atomically via temp-file-then-rename.

If target is a symbolic link the write goes through the symlink: the temporary file is created next to the resolved destination and the rename replaces the resolved path, leaving the symlink intact.

Parameters:
  • target (pathlib.Path) – Destination file path (may be a symlink)

  • content (str) – Content to write

Return type:

None

Examples

>>> import pathlib, tempfile
>>> with tempfile.TemporaryDirectory() as tmp:
...     p = pathlib.Path(tmp) / "test.txt"
...     _atomic_write(p, "hello")
...     p.read_text(encoding="utf-8")
'hello'

Symlinks are preserved — the real target is updated:

>>> with tempfile.TemporaryDirectory() as tmp:
...     real = pathlib.Path(tmp) / "real.txt"
...     _ = real.write_text("old", encoding="utf-8")
...     link = pathlib.Path(tmp) / "link.txt"
...     link.symlink_to(real)
...     _atomic_write(link, "new")
...     link.is_symlink(), link.read_text(encoding="utf-8")
(True, 'new')
vcspull.config.save_config_yaml(config_file_path, data)
function[source]
function[source]
vcspull.config.save_config_yaml(config_file_path, data)

Save configuration data to a YAML file.

Parameters:
  • config_file_path (pathlib.Path) – Path to the configuration file to write

  • data (dict) – Configuration data to save

Return type:

None

Examples

>>> import pathlib, tempfile
>>> with tempfile.TemporaryDirectory() as tmp:
...     p = pathlib.Path(tmp) / "cfg.yaml"
...     save_config_yaml(p, {"~/code/": {"myrepo": "git+https://example.com/repo.git"}})
...     "myrepo" in p.read_text(encoding="utf-8")
True
vcspull.config.save_config_json(config_file_path, data)
function[source]
function[source]
vcspull.config.save_config_json(config_file_path, data)

Save configuration data to a JSON file.

Parameters:
  • config_file_path (pathlib.Path) – Path to the configuration file to write

  • data (dict) – Configuration data to save

Return type:

None

Examples

>>> import json, pathlib, tempfile
>>> with tempfile.TemporaryDirectory() as tmp:
...     p = pathlib.Path(tmp) / "cfg.json"
...     save_config_json(p, {"~/code/": {"myrepo": "git+https://example.com/repo.git"}})
...     loaded = json.loads(p.read_text(encoding="utf-8"))
...     "~/code/" in loaded
True
vcspull.config.detect_git_shallow(repo_path)
function[source]
function[source]
vcspull.config.detect_git_shallow(repo_path)

Return whether a local git checkout is shallow.

Uses git rev-parse --is-shallow-repository (git 2.15+), falling back to the presence of .git/shallow. Any error (missing binary, non-git path) is treated as “not shallow”.

Parameters:

repo_path (pathlib.Path) – Path to the local git repository.

Returns:

True if the checkout is shallow, else False.

Return type:

bool

Examples

A full clone is not shallow:

>>> remote = create_git_remote_repo()
>>> full = tmp_path / "full"
>>> _ = subprocess.run(
...     ["git", "clone", f"file://{remote}", str(full)],
...     check=True, capture_output=True,
... )
>>> detect_git_shallow(full)
False

A --depth 1 clone is shallow:

>>> shallow = tmp_path / "shallow"
>>> _ = subprocess.run(
...     ["git", "clone", "--depth", "1", f"file://{remote}", str(shallow)],
...     check=True, capture_output=True,
... )
>>> detect_git_shallow(shallow)
True
vcspull.config.detect_git_depth(repo_path)
function[source]
function[source]
vcspull.config.detect_git_depth(repo_path)

Return the clone depth of a shallow git checkout, else None.

A full (non-shallow) checkout returns None. A shallow checkout returns the number of commits reachable from HEAD (git rev-list --count HEAD), which equals the --depth used to clone a linear history. Any error (missing binary, non-git path, unparsable output) is treated as “cannot determine” and returns None.

Parameters:

repo_path (pathlib.Path) – Path to the local git repository.

Returns:

Commit count of a shallow checkout, or None when full or unknown.

Return type:

int | None

Examples

Seed a remote with enough history that a --depth 2 clone is shallow:

>>> remote = create_git_remote_repo()
>>> for message in ("two", "three"):
...     _ = subprocess.run(
...         ["git", "-C", str(remote), "commit", "-q", "--allow-empty",
...          "-m", message],
...         check=True, capture_output=True,
...     )

A full clone has no depth:

>>> full = tmp_path / "full"
>>> _ = subprocess.run(
...     ["git", "clone", f"file://{remote}", str(full)],
...     check=True, capture_output=True,
... )
>>> detect_git_depth(full) is None
True

A --depth 2 clone reports its depth:

>>> shallow = tmp_path / "shallow"
>>> _ = subprocess.run(
...     ["git", "clone", "--depth", "2", f"file://{remote}", str(shallow)],
...     check=True, capture_output=True,
... )
>>> detect_git_depth(shallow)
2
vcspull.config.resolve_clone_depth(repo_path, *, explicit_shallow=False, explicit_depth=None)
function[source]
function[source]
vcspull.config.resolve_clone_depth(repo_path, *, explicit_shallow=False, explicit_depth=None)

Resolve the (shallow, depth) to record for a checkout.

Centralizes the precedence shared by add and discover so the two subcommands stay consistent. Precedence, highest first:

  1. explicit_depth (from --depth N) → (False, explicit_depth).

  2. explicit_shallow (from --shallow) → (True, None).

  3. Auto-detected depth (hybrid): a depth-1 checkout records shallow: true (the common case), depth > 1 records depth: N, and a full checkout records neither.

Parameters:
  • repo_path (pathlib.Path) – Path to the local git checkout to inspect when auto-detecting.

  • explicit_shallow (bool) – Whether --shallow was passed.

  • explicit_depth (int | None) – Value of --depth N, or None when not passed.

Returns:

(shallow, depth) to hand to build_repo_entry().

Return type:

tuple[bool, int | None]

Examples

Explicit flags win and never touch the filesystem:

>>> resolve_clone_depth(tmp_path, explicit_depth=5)
(False, 5)
>>> resolve_clone_depth(tmp_path, explicit_shallow=True)
(True, None)

A path that is not a shallow checkout records neither:

>>> resolve_clone_depth(tmp_path)
(False, None)
vcspull.config.build_repo_entry(url, *, rev=None, shallow=False, depth=None)
function[source]
function[source]
vcspull.config.build_repo_entry(url, *, rev=None, shallow=False, depth=None)

Build a raw per-repository config entry for add/discover.

Centralizes the entry shape written by both subcommands so the recorded keys stay consistent. Sync-tuning keys are nested under options:; depth wins over shallow when both are supplied.

Parameters:
  • url (str) – VCS URL in vcspull format, e.g. git+https://github.com/u/r.git.

  • rev (str | None) – Commit, tag, or branch to pin via options.rev. Omitted when falsy.

  • shallow (bool) – If True, record options.shallow: true (clone --depth 1).

  • depth (int | None) – If set, record options.depth: N (clone --depth N).

Returns:

Mapping ready to store under a workspace root in the config.

Return type:

dict

Examples

>>> build_repo_entry("git+https://github.com/u/r.git")
{'repo': 'git+https://github.com/u/r.git'}
>>> build_repo_entry("git+https://github.com/u/r.git", rev="v1.0.0")
{'repo': 'git+https://github.com/u/r.git', 'options': {'rev': 'v1.0.0'}}
>>> build_repo_entry("git+https://github.com/u/r.git", shallow=True)
{'repo': 'git+https://github.com/u/r.git', 'options': {'shallow': True}}
>>> build_repo_entry("git+https://github.com/u/r.git", depth=50)
{'repo': 'git+https://github.com/u/r.git', 'options': {'depth': 50}}

depth wins over shallow:

>>> build_repo_entry("git+https://github.com/u/r.git", shallow=True, depth=50)
{'repo': 'git+https://github.com/u/r.git', 'options': {'depth': 50}}
vcspull.config.LEGACY_REPO_OPTION_KEYS = ('rev', 'shallow', 'depth')
data
data
vcspull.config.LEGACY_REPO_OPTION_KEYS = ('rev', 'shallow', 'depth')

Per-repository sync-tuning keys whose canonical home is the options: block. They were accepted at the entry root in v1.61.0; that form is now deprecated and migrated by migrate_repo_entry().

vcspull.config.migrate_repo_entry(entry)
function[source]
function[source]
vcspull.config.migrate_repo_entry(entry)

Relocate legacy top-level sync keys under options:.

Moves any top-level rev/shallow/depth into the entry’s options: block. A value already present under options: wins, so the redundant top-level copy is simply dropped. When both shallow and a truthy depth end up under options:, depth wins and shallow is removed (matching how sync resolves precedence).

Parameters:

entry (Any) – A raw repository entry (string shorthand or mapping).

Returns:

(changed, entry). changed is False (and the entry returned unchanged) for string shorthands and mappings with no legacy keys.

Return type:

tuple[bool, Any]

Examples

String shorthands and already-migrated entries are untouched:

>>> migrate_repo_entry("git+ssh://x")
(False, 'git+ssh://x')
>>> migrate_repo_entry({"repo": "git+ssh://x"})
(False, {'repo': 'git+ssh://x'})

A legacy top-level key is relocated:

>>> migrate_repo_entry({"repo": "git+ssh://x", "shallow": True})
(True, {'repo': 'git+ssh://x', 'options': {'shallow': True}})

depth wins over shallow in the migrated entry:

>>> migrate_repo_entry(
...     {"repo": "git+ssh://x", "rev": "v1", "shallow": True, "depth": 5}
... )
(True, {'repo': 'git+ssh://x', 'options': {'rev': 'v1', 'depth': 5}})
vcspull.config.detect_legacy_repo_options(raw_config)
function[source]
function[source]
vcspull.config.detect_legacy_repo_options(raw_config)

Return (workspace_label, repo_name) pairs using legacy top-level keys.

Scans a raw (unexpanded) config mapping for repository entries that still carry top-level rev/shallow/depth instead of nesting them under options:. Callers use the result to warn users to run vcspull migrate.

Parameters:

raw_config (Any) – Raw config mapping (workspace root → repo name → entry).

Returns:

One (workspace_label, repo_name) pair per legacy entry.

Return type:

list[tuple[str, str]]

Examples

>>> detect_legacy_repo_options(
...     {"~/code/": {"flask": {"repo": "git+x", "shallow": True}}}
... )
[('~/code/', 'flask')]

The canonical options: form is not flagged:

>>> detect_legacy_repo_options(
...     {"~/code/": {"flask": {"repo": "git+x", "options": {"shallow": True}}}}
... )
[]
vcspull.config.save_config(config_file_path, data)
function[source]
function[source]
vcspull.config.save_config(config_file_path, data)

Save configuration data, dispatching by file extension.

Parameters:
  • config_file_path (pathlib.Path) – Path to the configuration file to write

  • data (dict) – Configuration data to save

Return type:

None

Examples

>>> import pathlib, tempfile, json
>>> with tempfile.TemporaryDirectory() as tmp:
...     p = pathlib.Path(tmp) / "test.json"
...     save_config(p, {"~/code/": {"repo": {"repo": "git+https://x"}}})
...     loaded = json.loads(p.read_text(encoding="utf-8"))
...     loaded["~/code/"]["repo"]["repo"]
'git+https://x'
>>> with tempfile.TemporaryDirectory() as tmp:
...     p = pathlib.Path(tmp) / "test.yaml"
...     save_config(p, {"~/code/": {"repo": {"repo": "git+https://x"}}})
...     "repo" in p.read_text(encoding="utf-8")
True
vcspull.config.save_config_yaml_with_items(config_file_path, items)
function[source]
function[source]
vcspull.config.save_config_yaml_with_items(config_file_path, items)

Persist configuration data while preserving duplicate top-level sections.

Unlike save_config_yaml(), which loses duplicate keys when given a plain dict, this function accepts ordered (label, data) pairs so that two workspace-root entries with the same key are each serialised as a separate YAML block.

Parameters:
  • config_file_path (pathlib.Path) – Destination config file (may be a symlink; the real target is updated).

  • items (list of tuple[str, Any]) – Ordered (section_label, section_data) pairs. Each pair becomes one YAML document block in the output.

Return type:

None

Examples

>>> import pathlib, tempfile
>>> with tempfile.TemporaryDirectory() as tmp:
...     p = pathlib.Path(tmp) / "cfg.yaml"
...     save_config_yaml_with_items(p, [
...         ("~/code/", {"flask": "git+https://github.com/pallets/flask.git"}),
...         ("~/code/", {"django": "git+https://github.com/django/django.git"}),
...     ])
...     content = p.read_text(encoding="utf-8")
...     "flask" in content and "django" in content
True
vcspull.config._VALID_OPS: frozenset[str] = frozenset({'add', 'discover', 'fmt', 'import', 'merge'})
data
data
vcspull.config._VALID_OPS: frozenset[str] = frozenset({'add', 'discover', 'fmt', 'import', 'merge'})

Valid operation names for pin checking.

vcspull.config.is_pinned_for_op(entry, op)
function[source]
function[source]
vcspull.config.is_pinned_for_op(entry, op)

Return True if the repo config entry is pinned for op.

Parameters:
  • entry (Any) – Raw repo config value (string, dict, or None).

  • op (str) – Operation name: "import", "add", "discover", "fmt", or "merge".

Return type:

bool

Examples

Global pin applies to all ops:

>>> is_pinned_for_op({"repo": "git+x", "options": {"pin": True}}, "import")
True
>>> is_pinned_for_op({"repo": "git+x", "options": {"pin": True}}, "fmt")
True

Per-op pin is scoped:

>>> entry = {"repo": "git+x", "options": {"pin": {"import": True}}}
>>> is_pinned_for_op(entry, "import")
True
>>> is_pinned_for_op(entry, "fmt")
False

allow_overwrite: false is shorthand for pin: {import: true} (guards against --sync):

>>> entry2 = {"repo": "git+x", "options": {"allow_overwrite": False}}
>>> is_pinned_for_op(entry2, "import")
True
>>> is_pinned_for_op(entry2, "add")
False

Plain string entries and entries without options are never pinned:

>>> is_pinned_for_op("git+x", "import")
False
>>> is_pinned_for_op({"repo": "git+x"}, "import")
False

Explicit false is not pinned:

>>> is_pinned_for_op({"repo": "git+x", "options": {"pin": False}}, "import")
False

String values for pin (not bool) are ignored — not pinned:

>>> is_pinned_for_op({"repo": "git+x", "options": {"pin": "true"}}, "import")
False

Invalid op raises ValueError:

>>> is_pinned_for_op(
...     {"repo": "git+x"}, "bogus"
... )
Traceback (most recent call last):
    ...
ValueError: Unknown op: 'bogus'
vcspull.config.get_pin_reason(entry)
function[source]
function[source]
vcspull.config.get_pin_reason(entry)

Return the human-readable pin reason from a repo config entry.

Non-string values are coerced to str() so callers can safely interpolate the result into log messages.

Examples

>>> entry = {"repo": "git+x", "options": {"pin": True, "pin_reason": "pinned"}}
>>> get_pin_reason(entry)
'pinned'
>>> get_pin_reason({"repo": "git+x"}) is None
True
>>> get_pin_reason("git+x") is None
True

Non-string pin_reason is coerced:

>>> get_pin_reason({"repo": "git+x", "options": {"pin_reason": 42}})
'42'
Parameters:

entry (Any)

Return type:

str | None

class vcspull.config.MergeAction
class vcspull.config.MergeAction

Bases: Enum

Action for resolving a duplicate workspace-root repo conflict.

vcspull.config._classify_merge_action(existing_entry, incoming_entry)
function[source]
function[source]
vcspull.config._classify_merge_action(existing_entry, incoming_entry)

Classify the merge conflict resolution action.

Parameters:
  • existing_entry (Any) – The entry already stored (first occurrence).

  • incoming_entry (Any) – The duplicate entry being merged in.

Return type:

MergeAction

Examples

Neither pinned — keep existing (first-occurrence-wins):

>>> _classify_merge_action({"repo": "git+a"}, {"repo": "git+b"})
<MergeAction.KEEP_EXISTING: 'keep_existing'>

Incoming is pinned — incoming wins:

>>> _classify_merge_action(
...     {"repo": "git+a"},
...     {"repo": "git+b", "options": {"pin": True}},
... )
<MergeAction.KEEP_INCOMING: 'keep_incoming'>

Existing is pinned — existing wins regardless:

>>> _classify_merge_action(
...     {"repo": "git+a", "options": {"pin": True}},
...     {"repo": "git+b"},
... )
<MergeAction.KEEP_EXISTING: 'keep_existing'>

Both pinned — first-occurrence-wins:

>>> _classify_merge_action(
...     {"repo": "git+a", "options": {"pin": True}},
...     {"repo": "git+b", "options": {"pin": True}},
... )
<MergeAction.KEEP_EXISTING: 'keep_existing'>
vcspull.config.merge_duplicate_workspace_root_entries(label, occurrences)
function[source]
function[source]
vcspull.config.merge_duplicate_workspace_root_entries(label, occurrences)

Merge duplicate entries for a single workspace root.

Parameters:
Return type:

tuple[Any, list[str], int]

vcspull.config.merge_duplicate_workspace_roots(config_data, duplicate_roots)
function[source]
function[source]
vcspull.config.merge_duplicate_workspace_roots(config_data, duplicate_roots)

Merge duplicate workspace root sections captured during load.

Parameters:
Return type:

tuple[dict[str, Any], list[str], int, list[tuple[str, int]]]

vcspull.config.canonicalize_workspace_path(label, *, cwd=None)
function[source]
function[source]
vcspull.config.canonicalize_workspace_path(label, *, cwd=None)

Convert a workspace root label to an absolute canonical path.

Parameters:
Return type:

Path

vcspull.config.workspace_root_label(workspace_path, *, cwd=None, home=None, preserve_cwd_label=True)
function[source]
function[source]
vcspull.config.workspace_root_label(workspace_path, *, cwd=None, home=None, preserve_cwd_label=True)

Create a normalized label for a workspace root path.

Parameters:
Return type:

str

vcspull.config.normalize_workspace_roots(config_data, *, cwd=None, home=None, preserve_cwd_label=True)
function[source]
function[source]
vcspull.config.normalize_workspace_roots(config_data, *, cwd=None, home=None, preserve_cwd_label=True)

Normalize workspace root labels and merge duplicate sections.

Parameters:
Return type:

tuple[dict[str, Any], dict[Path, str], list[str], int]