"""Image deploy import logic: copy/move from a USB or upload-dir source into ``SAMBA_SHARE//Deploy/`` while merging shared subdirs (``Out-of-box Drivers`` etc.) into ``SAMBA_SHARE/_shared/`` and replacing the per-image copies with symlinks. This is what lets two image types re-use the same multi-GB driver tree without doubling disk usage. """ import os import shutil import config from services.system import find_usb_mounts def _replace_with_symlink(link_path, target_path): """Replace a file/dir/symlink at link_path with a symlink to target_path.""" if os.path.islink(link_path): os.remove(link_path) elif os.path.isdir(link_path): shutil.rmtree(link_path) os.symlink(target_path, link_path) def _merge_tree(src, dst, move=False): """Recursively merge src tree into dst, overwriting existing files. When move=True, files are moved instead of copied (saves disk space on imports from the local upload-dir). """ _transfer = shutil.move if move else shutil.copy2 _transfer_tree = shutil.move if move else shutil.copytree for item in os.listdir(src): s = os.path.join(src, item) d = os.path.join(dst, item) if os.path.isdir(s): if os.path.isdir(d): _merge_tree(s, d, move=move) else: if os.path.exists(d): os.remove(d) _transfer_tree(s, d) else: os.makedirs(os.path.dirname(d), exist_ok=True) _transfer(s, d) def import_deploy(src_deploy, dst_deploy, target="", move=False): """Import Deploy/ contents, redirecting shared subdirs into _shared/.""" scoped_shared = [] prefix_key = "" for prefix, dirs in config.SHARED_DEPLOY_SCOPED.items(): if target.startswith(prefix): scoped_shared = dirs prefix_key = prefix break _transfer = shutil.move if move else shutil.copy2 _transfer_tree = shutil.move if move else shutil.copytree os.makedirs(dst_deploy, exist_ok=True) for item in os.listdir(src_deploy): src_item = os.path.join(src_deploy, item) dst_item = os.path.join(dst_deploy, item) if not os.path.isdir(src_item): _transfer(src_item, dst_item) continue if item in config.SHARED_DEPLOY_GLOBAL: shared_dest = os.path.join(config.SHARED_DIR, item) os.makedirs(shared_dest, exist_ok=True) _merge_tree(src_item, shared_dest, move=move) _replace_with_symlink(dst_item, shared_dest) continue if item in scoped_shared: shared_dest = os.path.join(config.SHARED_DIR, f"{prefix_key}{item}") os.makedirs(shared_dest, exist_ok=True) _merge_tree(src_item, shared_dest, move=move) _replace_with_symlink(dst_item, shared_dest) continue if os.path.isdir(dst_item): _merge_tree(src_item, dst_item, move=move) else: _transfer_tree(src_item, dst_item) def allowed_import_source(source): """True if source is a USB mount or under the upload dir.""" usb = find_usb_mounts() if any(source == m or source.startswith(m + "/") for m in usb): return True if source == config.UPLOAD_DIR or source.startswith(config.UPLOAD_DIR + "/"): return os.path.isdir(source) return False