from pathlib import Path
from textwrap import dedent
from typing import List
import click
from latch.ldata._transfer.download import download as _download
from latch.ldata._transfer.progress import Progress
from latch.ldata._transfer.remote_copy import remote_copy as _remote_copy
from latch.ldata._transfer.upload import upload as _upload
from latch.ldata.type import LatchPathError
from latch_cli.services.cp.glob import expand_pattern
from latch_cli.utils import human_readable_time, with_si_suffix
from latch_cli.utils.path import get_path_error, is_remote_path
def _copy_and_print(src: str, dst: str, progress: Progress) -> None:
_remote_copy(src, dst)
if progress != Progress.none:
click.echo(dedent(f"""
{click.style("Copy Requested.", fg="green")}
{click.style("Source: ", fg="blue")}{(src)}
{click.style("Destination: ", fg="blue")}{(dst)}"""))
def _download_and_print(src: str, dst: Path, progress: Progress, verbose: bool) -> None:
if progress != Progress.none:
click.secho(f"Downloading {dst.name}", fg="blue")
res = _download(src, dst, progress, verbose)
if progress != Progress.none:
click.echo(dedent(f"""
{click.style("Download Complete", fg="green")}
{click.style("Time Elapsed: ", fg="blue")}{human_readable_time(res.total_time)}
{click.style("Files Downloaded: ", fg="blue")}{res.num_files} ({with_si_suffix(res.total_bytes)})
"""))
# todo(ayush): come up with a better behavior scheme than unix cp
[docs]def cp(
srcs: List[str],
dest: str,
*,
progress: Progress,
verbose: bool,
expand_globs: bool,
):
dest_remote = is_remote_path(dest)
for src in srcs:
src_remote = is_remote_path(src)
try:
if src_remote and not dest_remote:
if expand_globs:
[
_download_and_print(p, Path(dest), progress, verbose)
for p in expand_pattern(src)
]
else:
_download_and_print(src, Path(dest), progress, verbose)
elif not src_remote and dest_remote:
if progress != Progress.none:
click.secho(f"Uploading {src}", fg="blue")
res = _upload(src, dest, progress=progress, verbose=verbose)
if progress != Progress.none:
click.echo(dedent(f"""
{click.style("Upload Complete", fg="green")}
{click.style("Time Elapsed: ", fg="blue")}{human_readable_time(res.total_time)}
{click.style("Files Uploaded: ", fg="blue")}{res.num_files} ({with_si_suffix(res.total_bytes)})
"""))
elif src_remote and dest_remote:
if expand_globs:
[_copy_and_print(p, dest, progress) for p in expand_pattern(src)]
else:
_copy_and_print(src, dest, progress)
else:
raise ValueError(
dedent(f"""
`latch cp` cannot be used for purely local file copying.
Please ensure at least one of your arguments is a remote path (beginning with `latch://`)
""").strip("\n"),
)
except LatchPathError as e:
click.secho(get_path_error(e.remote_path, e.message, e.acc_id), fg="red")
raise click.exceptions.Exit(1) from e
except Exception as e:
click.secho(str(e), fg="red")
raise click.exceptions.Exit(1) from e