cmdlet refactor

This commit is contained in:
2026-05-04 18:41:01 -07:00
parent 3ce339b3c1
commit 24f983473f
44 changed files with 1320 additions and 309 deletions
+45
View File
@@ -549,6 +549,8 @@ class FTP(Provider):
if not local_path.exists() or not local_path.is_file():
raise FileNotFoundError(f"File not found: {local_path}")
pipe_obj = kwargs.get("pipe_obj")
settings = self._resolve_settings(
instance_name=str(kwargs.get("instance") or kwargs.get("store") or "").strip() or None,
require_explicit=bool(kwargs.get("instance") or kwargs.get("store")),
@@ -569,6 +571,19 @@ class FTP(Provider):
ftp = self._connect(settings=settings)
try:
self._ensure_directory(ftp, remote_dir, base_path=str(settings.get("base_path") or "/"))
# FTP duplicate check is filename-based at the destination directory.
# If the exact filename already exists remotely, skip re-upload.
if self._remote_filename_exists(ftp, remote_dir, remote_name):
try:
if pipe_obj is not None:
if not isinstance(getattr(pipe_obj, "extra", None), dict):
pipe_obj.extra = {}
pipe_obj.extra["upload_duplicate"] = True
pipe_obj.extra["upload_duplicate_rule"] = "filename"
pipe_obj.extra["upload_duplicate_target"] = remote_path
except Exception:
pass
return self._build_url(remote_path, settings=settings)
with local_path.open("rb") as handle:
ftp.storbinary(f"STOR {remote_path}", handle)
finally:
@@ -930,6 +945,36 @@ class FTP(Provider):
if not self._is_directory(ftp, partial):
raise
def _remote_filename_exists(self, ftp: ftplib.FTP, remote_dir: str, filename: str) -> bool:
target_name = str(filename or "").strip()
if not target_name:
return False
normalized_dir = self._normalize_remote_path(remote_dir, default=self._base_path)
try:
for name, facts in ftp.mlsd(normalized_dir):
_ = facts
if str(name or "").strip() == target_name:
return True
except Exception:
pass
try:
entries = ftp.nlst(normalized_dir)
except Exception:
entries = []
for entry in entries or []:
entry_text = str(entry or "").strip().rstrip("/")
if not entry_text:
continue
entry_name = posixpath.basename(entry_text)
if entry_name == target_name:
return True
return False
def _item_metadata(self, item: Any, *, pipe_obj: Any = None) -> Dict[str, Any]:
metadata: Dict[str, Any] = {}
for source in (item, pipe_obj):