diff options
Diffstat (limited to 'packages/meshbay-cli/src/meshbay_cli/client/upload_plan.py')
| -rw-r--r-- | packages/meshbay-cli/src/meshbay_cli/client/upload_plan.py | 33 |
1 files changed, 28 insertions, 5 deletions
diff --git a/packages/meshbay-cli/src/meshbay_cli/client/upload_plan.py b/packages/meshbay-cli/src/meshbay_cli/client/upload_plan.py index 070e686..b4ec781 100644 --- a/packages/meshbay-cli/src/meshbay_cli/client/upload_plan.py +++ b/packages/meshbay-cli/src/meshbay_cli/client/upload_plan.py @@ -12,7 +12,7 @@ import stat from dataclasses import dataclass from pathlib import Path -from meshbay_common.paths import fold +from meshbay_common.paths import fold, long_path from ..errors import USAGE, CliError from ..output import safe @@ -36,7 +36,7 @@ def plan_upload(sources: list[str], recursive: bool): for src in sources: path = Path(src).expanduser() try: - st = path.stat() + st = os.stat(long_path(path)) except OSError as e: problems.append(f"{src}: {e.strerror}") continue @@ -51,18 +51,18 @@ def plan_upload(sources: list[str], recursive: bool): elif stat.S_ISDIR(st.st_mode): if not recursive: raise CliError(USAGE, f"{safe(src)} is a folder; use -R.") - for here, subdirs, names in os.walk(path): + for here, subdirs, names in _walk(path): rel = [top] + list(Path(here).relative_to(path).parts) dirs.append(rel) for d in list(subdirs): - if (Path(here) / d).is_symlink(): + if os.path.islink(long_path(Path(here) / d)): subdirs.remove(d) problems.append(f"{Path(here) / d} is a link to a folder; not " "followed") for n in names: p = Path(here) / n try: - st_n = p.stat() + st_n = os.stat(long_path(p)) except OSError as e: problems.append(f"{p}: {e.strerror}") continue @@ -74,6 +74,29 @@ def plan_upload(sources: list[str], recursive: bool): return dirs, files, problems +def _walk(top: Path): + """`os.walk` for a tree that may go past Windows' MAX_PATH: each folder is + listed under its long form (`long_path`, which only prefixes a long path, so + a short top alone would not do) and the paths given back stay plain.""" + stack = [top] + while stack: + here = stack.pop() + try: + with os.scandir(long_path(here)) as it: + entries = list(it) + except OSError: + continue + subdirs, names = [], [] + for e in entries: + try: + is_dir = e.is_dir() + except OSError: + is_dir = False + (subdirs if is_dir else names).append(e.name) + yield here, subdirs, names # the caller prunes and orders subdirs + stack.extend(here / d for d in reversed(subdirs)) + + def taken_names(tree: Tree, folder: str, names: list[str]) -> set[str]: """The names among `names` already in `folder`, compared without case.""" there = [i.name for i in tree.children(folder, include_unavailable=True)] |