diff --git a/src/python/jw/pkg/lib/util.py b/src/python/jw/pkg/lib/util.py index c585708a..8e2e075e 100644 --- a/src/python/jw/pkg/lib/util.py +++ b/src/python/jw/pkg/lib/util.py @@ -101,29 +101,29 @@ async def run_sudo(cmd: list[str], *args, interactive: bool=True, ec: ExecContex ec = Local(interactive=interactive) return await ec.sudo(cmd, *args, **kwargs) -async def copy(src_uri: str, dst_uri: str, owner: str|None=None, group: str|None=None, mode: int|None=None, throw=True) -> Exception|str: - from .ExecContext import ExecContext - src: ExecContext|None = None - dst: ExecContext|None = None - def __ec(uri: str) -> tuple[ExecContext, str]: - return ExecContext.create(uri), urlparse(uri).path - try: - src, src_path = __ec(src_uri) - content = (await src.get(src_path, throw=True)).stdout - dst, dst_path = __ec(dst_uri) - if await dst.is_dir(path): - dst_path += os.path.basename(src_path) - await dst.put(path=dst_path, content=content, owner=owner, group=group, mode=mode, throw=True) - except Exception as e: - if throw: - raise - log(ERR, f'Failed to copy {src_uri} -> {dst_uri} ({str(e)})') - return e - finally: - for ec in [src, dst]: - if ec is not None: - await ec.close() - return dst_path +async def copy(src_uri: str|Iterable[str], dst: str|FileContext, owner: str|None=None, group: str|None=None, mode: int|None=None, throw=True) -> Exception|str|list[str]: + if not isinstance(src_uri, str): + ret: list[str] = [] + for uri in src_uri: # TODO: Group identical netlocs into one CopyContext + rr = ret.append(await copy(uri, dst, owner, group, mode, throw)) + if isinstance(rr, Exception): + return rr + return ret + from .CopyContext import CopyContext + async with CopyContext(src_uri, dst) as ctx: + try: + content = (await ctx.src.get(ctx.src.root, throw=True)).stdout + dst_path = ctx.dst.root + if await ctx.dst.is_dir(ctx.dst.root): + dst_path += '/' + os.path.basename(src_uri) + await ctx.dst.put(path=dst_path, content=content, owner=owner, group=group, mode=mode, throw=True) + return dst_path + except Exception as e: + if throw: + raise + log(ERR, f'Failed to copy {src_uri} -> {dst} ({str(e)})') + return e + assert False, 'Unreachable code' async def get_username(args: Namespace|None=None, url: str|None=None, askpass_env: list[str]=[], ec: ExecContext|None=None) -> str: # export url_user = None if url is None else Uri(url).username