← back to Kravet Sheet Sync 2026 04 20

sftp_probe.py

85 lines

#!/usr/bin/env python3
"""Test SFTP connection, list root, sample a few dirs to understand layout."""
import os, stat, sys
import paramiko

env = {}
with open(os.path.expanduser("~/.kravet-sftp.env")) as f:
    for line in f:
        k,_,v = line.strip().partition("=")
        if k: env[k] = v

HOST = env["KRAVET_SFTP_HOST"]
PORT = int(env["KRAVET_SFTP_PORT"])
USER = env["KRAVET_SFTP_USER"]
PASS = env["KRAVET_SFTP_PASS"]

print(f"connecting to {USER}@{HOST}:{PORT} ...", flush=True)
t = paramiko.Transport((HOST, PORT))
try:
    t.connect(username=USER, password=PASS)
except paramiko.ssh_exception.BadAuthenticationType as e:
    # Server may advertise only keyboard-interactive; retry with handler
    print(f"  plain password rejected — trying keyboard-interactive: {e}")
    def handler(title, instr, prompts):
        return [PASS for _ in prompts]
    t.auth_interactive(USER, handler)
sftp = paramiko.SFTPClient.from_transport(t)
print("connected.")
print(f"cwd: {sftp.getcwd() or sftp.normalize('.')}")

def walk_shallow(path="/", depth=0, max_depth=2):
    try:
        entries = sftp.listdir_attr(path)
    except Exception as e:
        print(f"  {'  '*depth}[err] {path}: {e}")
        return
    # Sort: dirs first, then files; cap listing
    entries.sort(key=lambda a: (0 if stat.S_ISDIR(a.st_mode or 0) else 1, a.filename))
    for i, a in enumerate(entries):
        kind = "d" if stat.S_ISDIR(a.st_mode or 0) else "-"
        print(f"  {'  '*depth}{kind} {a.st_size or 0:>12}  {a.filename}")
        if depth < max_depth and stat.S_ISDIR(a.st_mode or 0) and i < 6:
            sub = (path.rstrip("/") + "/" + a.filename)
            walk_shallow(sub, depth+1, max_depth)

print("\nroot listing:")
walk_shallow(".", 0, 2)

# Try the paths the sheet references: /LJ/HIRES/...
# Full root — top-level brands
print("\nTOP-LEVEL brand dirs and file counts / sizes:")
total_files = 0
total_bytes = 0
brand_totals = []
for a in sorted(sftp.listdir_attr("."), key=lambda x: x.filename):
    if stat.S_ISDIR(a.st_mode or 0):
        brand = a.filename
        fc, sz = 0, 0
        for sub in sftp.listdir_attr(brand):
            if stat.S_ISDIR(sub.st_mode or 0):
                for f in sftp.listdir_attr(brand + "/" + sub.filename):
                    if not stat.S_ISDIR(f.st_mode or 0):
                        fc += 1; sz += f.st_size or 0
            else:
                fc += 1; sz += a.st_size or 0
        brand_totals.append((brand, fc, sz))
        total_files += fc; total_bytes += sz
        print(f"  {brand:10s}  {fc:>8,} files  {sz/1024/1024:>10.1f} MB")
    else:
        print(f"  (file) {a.st_size:>10,}  {a.filename}")

print(f"\nTOTAL: {total_files:,} files, {total_bytes/1024/1024/1024:.2f} GB")

print("\nsample /LJ/HIRES (first 5):")
try:
    for i, a in enumerate(sorted(sftp.listdir_attr("/LJ/HIRES"), key=lambda x: x.filename)):
        if i >= 5: break
        print(f"  {a.st_size:>10}  {a.filename}")
    print(f"  /LJ/HIRES total: {len(sftp.listdir('/LJ/HIRES')):,}")
except Exception as e:
    print(f"  error: {e}")

sftp.close(); t.close()
print("done.")