from pathlib import Path
import hashlib,json,shutil,subprocess,tomllib
here=Path(__file__).resolve().parent; working=here/'working'; root=working/'workspace'
def h(p):
 x=hashlib.sha256(); x.update(p.read_bytes()); return x.hexdigest()
def cmd(args):
 exe=shutil.which(args[0])
 if not exe: return {'available':False,'executable':None,'rc':None,'output':None}
 p=subprocess.run(args,cwd=root,capture_output=True,text=True,timeout=10)
 return {'available':True,'executable':exe,'rc':p.returncode,'output':(p.stdout+p.stderr).strip()[-2000:]}
def rel(p):
 try: return p.resolve().relative_to(working.resolve()).as_posix()
 except Exception: return p.resolve().as_posix()
if not (root/'Cargo.toml').exists(): raise SystemExit('run setup_fixture.py first')
manifest=tomllib.loads((root/'Cargo.toml').read_text())
members=manifest.get('workspace',{}).get('members',[])
member_paths={(root/m).resolve() for m in members}
local=[]
for m in members:
 mp=root/m/'Cargo.toml'
 if not mp.exists(): continue
 data=tomllib.loads(mp.read_text())
 for sec in ('dependencies','dev-dependencies','build-dependencies'):
  for name,spec in data.get(sec,{}).items():
   if isinstance(spec,dict) and 'path' in spec:
    target=(mp.parent/spec['path']).resolve()
    local.append({'member':m,'dependency':name,'declared_path':spec['path'],'resolved_path':rel(target),'exists':target.exists(),'is_workspace_member':target in member_paths})
print(json.dumps({
 'workspace_exists':root.exists(),
 'workspace_members':members,
 'cargo_lock_hash':h(root/'Cargo.lock') if (root/'Cargo.lock').exists() else None,
 'toolchain_file_hash':h(root/'rust-toolchain.toml') if (root/'rust-toolchain.toml').exists() else None,
 'local_dependency_boundary':local,
 'cargo':cmd(['cargo','--version']), 'rustc':cmd(['rustc','--version']),
 'rustup_show_active':cmd(['rustup','show','active-toolchain']), 'rustup_toolchain_list':cmd(['rustup','toolchain','list'])
},indent=2))
