# ----------------------------------------------------------------------
# import: B -> A (mkdir, cp, and "other" list), using in_between_newer
# ----------------------------------------------------------------------
-def build_import_commands(
- A_tree: TreeDict,
- B_tree: TreeDict,
- A_root: str,
- B_root: str
-) -> Tuple[List[str], List[str], List[str]]:
- """
- NEW IMPORT SEMANTICS:
- • Directory nodes in B_tree:
- - If missing in A: emit `cp -a B_dir A_parent/`
- - If exists: skip
- • File nodes:
- - If missing in A: cp --parents -a
- - If both files & B newer: cp --parents -a
- - If type mismatch: other_list
- """
-
- cp_cmds: List[str] = []
- other_list: List[str] = []
-
- for rel_path, b_info in B_tree.items():
- b_type = b_info.get("node_type")
- rel_display = rel_path if rel_path else "."
-
- A_info = A_tree.get(rel_path)
- A_type = A_info.get("node_type") if A_info is not None else "MISSING"
-
- # Anything not file or directory
- if b_type not in ("file", "directory"):
- other_list.append(f"{rel_display}: A={A_type}, B={b_type}")
- continue
-
- # DIRECTORY CASE
- if b_type == "directory":
- A_path = Path(A_root) / rel_path
- B_path = Path(B_root) / rel_path
-
- if A_info is None:
- # Directory missing in A → proper directory import
- parent = A_path.parent
- cp_cmds.append(
- f"cp -a {shell_quote(str(B_path))} {shell_quote(str(parent))}/"
- )
- else:
- # Exists but should be directory
- if A_type != "directory":
- other_list.append(
- f"{rel_display}: A={A_type}, B=directory"
- )
- continue
-
- # FILE CASE
- if b_type == "file":
- B_path = os.path.join(B_root, rel_path)
- A_path = os.path.join(A_root, rel_path)
-
- # Missing in A → simple copy
- if A_info is None:
- cp_cmds.append(
- f"cp --parents -a {shell_quote(B_path)} {shell_quote(A_root)}/"
- )
- continue
-
- # Exists, but wrong type
- if A_type != "file":
- other_list.append(
- f"{rel_display}: A={A_type}, B=file"
- )
- continue
-
- # Compare mtimes
- a_m = A_info.get("mtime")
- b_m = b_info.get("mtime")
-
- if isinstance(a_m, (int, float)) and isinstance(b_m, (int, float)):
- if b_m > a_m:
- cp_cmds.append(
- f"cp --parents -a {shell_quote(B_path)} {shell_quote(A_root)}/"
- )
-
- # No mkdir list in this new design — we removed it.
- return [], cp_cmds, other_list
+
def build_import_commands(
A_tree: TreeDict
if a_info is None:
# Missing in A: copy the directory recursively.
src = os.path.join(B_root, rel_path) if rel_path else B_root
- # The destination should be A_root, as cp -a B_dir A_root/ will copy B_dir into A_root
- dst = A_root
+ # The destination should be the parent directory in A.
+ # os.path.join(A_root, rel_path) gives the full path to the new directory in A.
+ # os.path.dirname of that gives the parent directory.
+ dst = os.path.dirname(os.path.join(A_root, rel_path))
mkdir_cmds.append(
- f"cp -a {shell_quote(src)} {shell_quote(dst)}/"
+ f"cp -a {shell_quote(src)} {shell_quote(dst + os.sep)}"
)
else:
# Exists in A: must also be a directory to be "structurally OK"
if a_info is None:
# B-only file
src = os.path.join(B_root, rel_path) if rel_path else B_root
- dst = os.path.join(A_root, rel_path) if rel_path else A_root
+ # Destination is the parent directory in A, with a trailing slash
+ dst = os.path.dirname(os.path.join(A_root, rel_path))
cp_cmds.append(
- f"cp -a {shell_quote(src)} {shell_quote(dst)}"
+ f"cp -a {shell_quote(src)} {shell_quote(dst + os.sep)}"
)
continue
if isinstance(a_mtime, (int, float)) and isinstance(b_mtime, (int, float)):
if b_mtime > a_mtime:
src = os.path.join(B_root, rel_path) if rel_path else B_root
- dst = os.path.join(A_root, rel_path) if rel_path else A_root
+ # Destination is the parent directory in A, with a trailing slash
+ dst = os.path.dirname(os.path.join(A_root, rel_path))
cp_cmds.append(
- f"cp -a {shell_quote(src)} {shell_quote(dst)}"
+ f"cp -a {shell_quote(src)} {shell_quote(dst + os.sep)}"
)
return mkdir_cmds, cp_cmds, other_list