vcspull add - vcspull.cli.add

Add single repository functionality for vcspull.

class vcspull.cli.add.AddAction[source]

Bases: Enum

Action resolved for a single repo during vcspull add.

ADD = 'add'
SKIP_EXISTING = 'skip_existing'
SKIP_PINNED = 'skip_pinned'
vcspull.cli.add._classify_add_action(existing_entry)[source]

Classify the add action for a single repository.

Return type:

AddAction

Parameters:

existing_entry (Any) – Current config entry for this repo name, or None if absent.

Examples

Not in config:

>>> _classify_add_action(None)
<AddAction.ADD: 'add'>

Already exists (unpinned):

>>> _classify_add_action({"repo": "git+ssh://x"})
<AddAction.SKIP_EXISTING: 'skip_existing'>

Pinned for add:

>>> _classify_add_action({"repo": "git+ssh://x", "options": {"pin": True}})
<AddAction.SKIP_PINNED: 'skip_pinned'>
>>> entry = {"repo": "git+ssh://x", "options": {"pin": {"add": True}}}
>>> _classify_add_action(entry)
<AddAction.SKIP_PINNED: 'skip_pinned'>

Pinned for import only — not pinned for add:

>>> entry = {"repo": "git+ssh://x", "options": {"pin": {"import": True}}}
>>> _classify_add_action(entry)
<AddAction.SKIP_EXISTING: 'skip_existing'>
vcspull.cli.add.create_add_subparser(parser)[source]

Create vcspull add argument subparser.

Return type:

None

Parameters:

parser (argparse.ArgumentParser) – The parser to configure

vcspull.cli.add._resolve_workspace_path(workspace_root, repo_path_str, *, cwd)[source]

Resolve workspace path from arguments.

Return type:

Path

Parameters:
  • workspace_root (str | None) – Workspace root path from user

  • repo_path_str (str | None) – Repo path from user

  • cwd (pathlib.Path) – Current working directory

Returns:

Resolved workspace path

Return type:

pathlib.Path

vcspull.cli.add._detect_git_remote(repo_path)[source]

Return the origin remote URL for a Git repository if available.

Return type:

str | None

Parameters:

repo_path (Path)

vcspull.cli.add._normalize_detected_url(remote)[source]

Return display and config URLs derived from a detected remote.

Return type:

tuple[str, str]

Parameters:

remote (str | None)

vcspull.cli.add._build_ordered_items(top_level_items, raw_config)[source]

Return deep-copied top-level items preserving original ordering.

Return type:

list[dict[str, Any]]

Parameters:
vcspull.cli.add._aggregate_from_ordered_items(items)[source]

Collapse ordered top-level items into a mapping grouped by label.

Return type:

dict[str, Any]

Parameters:

items (list[dict[str, Any]])

vcspull.cli.add._collapse_ordered_items_to_dict(ordered_items)[source]

Collapse ordered items into a flat dict for JSON serialization.

JSON does not support duplicate keys, so sections with the same workspace label are merged at the repo level via dict.update() (last occurrence of a repo name wins).

Return type:

dict[str, Any]

Parameters:

ordered_items (list[dict[str, Any]])

Examples

Distinct labels pass through unchanged:

>>> _collapse_ordered_items_to_dict([
...     {"label": "~/code/", "section": {"repo1": {"repo": "git+x"}}},
...     {"label": "~/work/", "section": {"repo2": {"repo": "git+y"}}},
... ])
{'~/code/': {'repo1': {'repo': 'git+x'}}, '~/work/': {'repo2': {'repo': 'git+y'}}}

Duplicate labels are merged (repos from both sections appear):

>>> result = _collapse_ordered_items_to_dict([
...     {"label": "~/code/", "section": {"repo1": {"repo": "git+a"}}},
...     {"label": "~/code/", "section": {"repo2": {"repo": "git+b"}}},
... ])
>>> sorted(result["~/code/"].keys())
['repo1', 'repo2']
vcspull.cli.add._collect_duplicate_sections(items)[source]

Return mapping of labels to their repeated sections (>= 2 occurrences).

Return type:

dict[str, list[Any]]

Parameters:

items (list[dict[str, Any]])

vcspull.cli.add._save_ordered_items(config_file_path, ordered_items)[source]

Persist ordered items in the format matching the config file extension.

Return type:

None

Parameters:
  • config_file_path (pathlib.Path) – Path to config file (.yaml or .json).

  • ordered_items (list of dict) – Each dict has "label" and "section" keys.

Examples

YAML output:

>>> import pathlib
>>> config_file = tmp_path / "test.yaml"
>>> items = [{"label": "~/code/", "section": {"myrepo": "git+https://example.com/r.git"}}]
>>> _save_ordered_items(config_file, items)
>>> config_file.read_text().strip()
'~/code/...'

JSON output:

>>> config_file = tmp_path / "test.json"
>>> _save_ordered_items(config_file, items)
>>> import json
>>> data = json.loads(config_file.read_text())
>>> "~/code/" in data
True
vcspull.cli.add.handle_add_command(args)[source]

Entry point for the vcspull add CLI command.

Return type:

None

Parameters:

args (Namespace)

vcspull.cli.add.add_repo(name, url, config_file_path_str, path, workspace_root_path, dry_run, *, merge_duplicates=True)[source]

Add a repository to the vcspull configuration.

Return type:

None

Parameters:
  • name (str) – Repository name for the config

  • url (str) – Repository URL

  • config_file_path_str (str | None) – Path to config file, or None to use default

  • path (str | None) – Local path where repo will be cloned

  • workspace_root_path (str | None) – Workspace root to use in config

  • dry_run (bool) – If True, preview changes without writing

  • merge_duplicates (bool)