Add per-share selection in interactive wizard
After parsing the archive, present a numbered list of SMB and NFS shares and let the user pick which ones to migrate. Entering nothing (or 'all') keeps everything; 'n' skips the type entirely; space- separated numbers select specific shares. Because archive_data is filtered before the dry run, only selected shares are processed in both the dry and live runs, and the dataset existence check covers exactly the chosen share paths. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1185,6 +1185,57 @@ def _confirm(label: str) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
def _select_shares(shares: list[dict], share_type: str) -> list[dict]:
|
||||
"""
|
||||
Display a numbered list of *shares* and return only those the user selects.
|
||||
Enter (or 'all') returns all shares unchanged. 'n' / 'none' returns [].
|
||||
"""
|
||||
if not shares:
|
||||
return shares
|
||||
|
||||
print(f"\n {_bold(f'{share_type} shares in archive ({len(shares)}):')} \n")
|
||||
for i, share in enumerate(shares, 1):
|
||||
if share_type == "SMB":
|
||||
name = share.get("name", "<unnamed>")
|
||||
path = share.get("path", "")
|
||||
print(f" {_cyan(str(i) + '.')} {name:<22} {_dim(path)}")
|
||||
else: # NFS
|
||||
pl = share.get("paths") or []
|
||||
path = share.get("path") or (pl[0] if pl else "")
|
||||
extra = f" {_dim('+ ' + str(len(pl) - 1) + ' more')}" if len(pl) > 1 else ""
|
||||
print(f" {_cyan(str(i) + '.')} {path}{extra}")
|
||||
|
||||
print()
|
||||
raw = _prompt(
|
||||
f" Select {share_type} shares to migrate "
|
||||
"(e.g. '1 3', Enter = all, 'n' = none)",
|
||||
default="all",
|
||||
)
|
||||
|
||||
low = raw.strip().lower()
|
||||
if low in ("", "all"):
|
||||
print(f" {_green('✓')} All {len(shares)} {share_type} share(s) selected.")
|
||||
return shares
|
||||
if low in ("n", "none", "0"):
|
||||
print(f" {_yellow('–')} No {share_type} shares selected.")
|
||||
return []
|
||||
|
||||
seen: set[int] = set()
|
||||
selected: list[dict] = []
|
||||
for tok in raw.split():
|
||||
if tok.isdigit():
|
||||
idx = int(tok) - 1
|
||||
if 0 <= idx < len(shares) and idx not in seen:
|
||||
seen.add(idx)
|
||||
selected.append(shares[idx])
|
||||
|
||||
if selected:
|
||||
print(f" {_green('✓')} {len(selected)} of {len(shares)} {share_type} share(s) selected.")
|
||||
else:
|
||||
print(f" {_yellow('–')} No valid selections; skipping {share_type} shares.")
|
||||
return selected
|
||||
|
||||
|
||||
def interactive_mode() -> None:
|
||||
"""Interactive wizard: pick archive → configure → dry run → confirm → apply."""
|
||||
print(
|
||||
@@ -1258,6 +1309,13 @@ def interactive_mode() -> None:
|
||||
print()
|
||||
archive_data = parse_archive(str(chosen))
|
||||
|
||||
# 5b ── Select individual shares ───────────────────────────────────────────
|
||||
if "smb" in migrate and archive_data["smb_shares"]:
|
||||
archive_data["smb_shares"] = _select_shares(archive_data["smb_shares"], "SMB")
|
||||
if "nfs" in migrate and archive_data["nfs_shares"]:
|
||||
archive_data["nfs_shares"] = _select_shares(archive_data["nfs_shares"], "NFS")
|
||||
print()
|
||||
|
||||
base_ns = dict(
|
||||
debug_tar=str(chosen),
|
||||
dest=host,
|
||||
|
||||
Reference in New Issue
Block a user