This commit is contained in:
2026-04-17 16:17:16 -07:00
parent 343a7b37a0
commit d9e736172a
4 changed files with 322 additions and 29 deletions
+148 -18
View File
@@ -234,8 +234,13 @@ class Add_File(Cmdlet):
try:
candidate_dir = Path(str(path_arg))
if candidate_dir.exists() and candidate_dir.is_dir():
debug(
f"[add-file] Treating -path directory as destination: {candidate_dir}"
debug_panel(
"add-file destination",
[
("mode", "local export"),
("path", candidate_dir),
],
border_style="cyan",
)
location = str(candidate_dir)
path_arg = None
@@ -350,6 +355,13 @@ class Add_File(Cmdlet):
else:
items_to_process = [result]
if result is None and not path_arg and not explicit_path_list_results and not dir_scan_results:
try:
if ctx.get_stage_context() is not None:
return 0
except Exception:
pass
total_items = len(items_to_process) if isinstance(items_to_process, list) else 0
processed_items = 0
try:
@@ -580,7 +592,12 @@ class Add_File(Cmdlet):
progress.step("resolving source")
media_path, file_hash, temp_dir_to_cleanup = self._resolve_source(
item, path_arg, pipe_obj, config, store_instance=storage_registry
item,
path_arg,
pipe_obj,
config,
export_destination=(Path(location) if location and not is_storage_backend_location else None),
store_instance=storage_registry,
)
if not media_path and provider_name:
media_path, file_hash, temp_dir_to_cleanup = Add_File._download_provider_source(
@@ -1103,6 +1120,70 @@ class Add_File(Cmdlet):
pass
return None, None
@staticmethod
def _download_remote_backend_url(
remote_url: str,
pipe_obj: models.PipeObject,
*,
file_hash: Optional[str] = None,
output_dir: Optional[Path] = None,
) -> Tuple[Optional[Path], Optional[Path]]:
"""Best-effort fetch of a remote backend URL.
Returns (downloaded_path, temp_dir_to_cleanup).
When ``output_dir`` is provided, the file is downloaded directly there and no
temp cleanup path is returned.
"""
url_text = str(remote_url or "").strip()
if not url_text:
return None, None
if not url_text.lower().startswith(_REMOTE_URL_PREFIXES):
return None, None
tmp_dir: Optional[Path] = None
try:
download_root = output_dir
if download_root is None:
tmp_dir = Path(tempfile.mkdtemp(prefix="add-file-src-"))
download_root = tmp_dir
suggested_name = Add_File._build_provider_filename(
pipe_obj,
fallback_hash=file_hash,
source_url=url_text,
)
pipeline_progress = PipelineProgress(ctx)
downloaded = _download_direct_file(
url_text,
download_root,
quiet=False,
suggested_filename=suggested_name,
pipeline_progress=pipeline_progress,
)
downloaded_path = getattr(downloaded, "path", None)
if isinstance(downloaded_path, Path) and downloaded_path.exists():
if output_dir is not None:
pipe_obj.is_temp = False
if isinstance(pipe_obj.extra, dict):
pipe_obj.extra["_direct_export_download"] = True
else:
pipe_obj.extra = {"_direct_export_download": True}
return downloaded_path, None
pipe_obj.is_temp = True
return downloaded_path, tmp_dir
except Exception:
pass
if tmp_dir is not None:
try:
shutil.rmtree(tmp_dir, ignore_errors=True)
except Exception:
pass
return None, None
@staticmethod
def _build_provider_filename(
pipe_obj: models.PipeObject,
@@ -1188,6 +1269,7 @@ class Add_File(Cmdlet):
pipe_obj: models.PipeObject,
config: Dict[str,
Any],
export_destination: Optional[Path] = None,
store_instance: Optional[Any] = None,
) -> Tuple[Optional[Path],
Optional[str],
@@ -1228,12 +1310,30 @@ class Add_File(Cmdlet):
pipe_obj.path = str(mp)
return mp, str(r_hash), None
if isinstance(mp, str) and mp.strip():
try:
mp_path = Path(str(mp))
except Exception:
mp_path = None
if mp_path is not None and mp_path.exists() and mp_path.is_file():
pipe_obj.path = str(mp_path)
return mp_path, str(r_hash), None
dl_path, tmp_dir = Add_File._maybe_download_backend_file(
backend, str(r_hash), pipe_obj
)
if dl_path and dl_path.exists():
pipe_obj.path = str(dl_path)
return dl_path, str(r_hash), tmp_dir
dl_path, tmp_dir = Add_File._download_remote_backend_url(
str(mp),
pipe_obj,
file_hash=str(r_hash),
output_dir=export_destination,
)
if dl_path and dl_path.exists():
pipe_obj.path = str(dl_path)
return dl_path, str(r_hash), tmp_dir
except Exception as exc:
debug(f"[add-file] _resolve_source backend fetch failed for {r_store}/{r_hash}: {exc}")
@@ -1657,12 +1757,22 @@ class Add_File(Cmdlet):
@staticmethod
def _emit_pipe_object(pipe_obj: models.PipeObject) -> None:
from SYS.result_table import format_result
log(format_result(pipe_obj, title="Result"), file=sys.stderr)
ctx.emit(pipe_obj.to_dict())
payload = pipe_obj.to_dict()
ctx.emit(payload)
ctx.set_current_stage_table(None)
stage_ctx = ctx.get_stage_context()
is_last = (stage_ctx is None) or bool(getattr(stage_ctx, "is_last_stage", False))
if not is_last:
return
try:
from ._shared import display_and_persist_items
display_and_persist_items([payload], title="Result", subject=payload)
except Exception:
pass
@staticmethod
def _emit_storage_result(
payload: Dict[str,
@@ -1925,7 +2035,24 @@ class Add_File(Cmdlet):
log(f"❌ Invalid destination path '{location}': {exc}", file=sys.stderr)
return 1
log(f"Exporting to local path: {destination_root}", file=sys.stderr)
direct_export_download = False
try:
if isinstance(pipe_obj.extra, dict):
direct_export_download = bool(pipe_obj.extra.pop("_direct_export_download", False))
except Exception:
direct_export_download = False
try:
debug_panel(
"add-file export",
[
("destination", destination_root),
("source", media_path),
],
border_style="green",
)
except Exception:
pass
result = None
tags, url, title, f_hash = Add_File._prepare_metadata(result, media_path, pipe_obj, config)
@@ -1961,18 +2088,21 @@ class Add_File(Cmdlet):
destination_root.mkdir(parents=True, exist_ok=True)
target_path = destination_root / new_name
if target_path.exists():
target_path = unique_path(target_path)
if direct_export_download:
target_path = media_path
else:
if target_path.exists():
target_path = unique_path(target_path)
# COPY Operation (Safe Export)
try:
shutil.copy2(str(media_path), target_path)
except Exception as exc:
log(f"❌ Failed to export file: {exc}", file=sys.stderr)
return 1
# COPY Operation (Safe Export)
try:
shutil.copy2(str(media_path), target_path)
except Exception as exc:
log(f"❌ Failed to export file: {exc}", file=sys.stderr)
return 1
# Copy Sidecars
Add_File._copy_sidecars(media_path, target_path)
# Copy Sidecars
Add_File._copy_sidecars(media_path, target_path)
# Ensure hash for exported copy
if not f_hash: