1+ import hashlib
2+ import json
3+ import platform
4+ import shutil
5+ from datetime import datetime , timezone
6+ from pathlib import Path
7+
8+ from concore_cli import __version__
9+
10+
11+ def _checksum_file (path : Path ) -> str :
12+ hasher = hashlib .sha256 ()
13+ with path .open ("rb" ) as handle :
14+ for chunk in iter (lambda : handle .read (8192 ), b"" ):
15+ hasher .update (chunk )
16+ return f"sha256:{ hasher .hexdigest ()} "
17+
18+
19+ def _detect_tools () -> dict :
20+ tool_candidates = {
21+ "python" : ["python" , "python3" ],
22+ "g++" : ["g++" ],
23+ "docker" : ["docker" ],
24+ "octave" : ["octave" ],
25+ "iverilog" : ["iverilog" ],
26+ }
27+ detected = {}
28+ for tool_name , candidates in tool_candidates .items ():
29+ detected_path = None
30+ for candidate in candidates :
31+ detected_path = shutil .which (candidate )
32+ if detected_path :
33+ break
34+ detected [tool_name ] = detected_path or "not found"
35+ return detected
36+
37+
38+ def write_study_metadata (study_path : Path , generated_by : str , workflow_file : Path = None ):
39+ checksums = {}
40+ checksum_candidates = [
41+ "workflow.graphml" ,
42+ "docker-compose.yml" ,
43+ "concore.toml" ,
44+ "runner.py" ,
45+ "README.md" ,
46+ "build" ,
47+ "run" ,
48+ "build.bat" ,
49+ "run.bat" ,
50+ ]
51+
52+ if workflow_file is not None and workflow_file .exists ():
53+ checksums [workflow_file .name ] = _checksum_file (workflow_file )
54+
55+ for relative_name in checksum_candidates :
56+ file_path = study_path / relative_name
57+ if file_path .exists () and file_path .is_file ():
58+ checksums [relative_name ] = _checksum_file (file_path )
59+
60+ metadata = {
61+ "generated_by" : generated_by ,
62+ "concore_version" : __version__ ,
63+ "timestamp" : datetime .now (timezone .utc ).replace (microsecond = 0 ).isoformat (),
64+ "python_version" : platform .python_version (),
65+ "platform" : platform .platform (),
66+ "study_name" : study_path .name ,
67+ "working_directory" : str (study_path .resolve ()),
68+ "tools_detected" : _detect_tools (),
69+ "checksums" : checksums ,
70+ "schema_version" : 1 ,
71+ }
72+
73+ metadata_path = study_path / "STUDY.json"
74+ metadata_path .write_text (json .dumps (metadata , indent = 2 ) + "\n " , encoding = "utf-8" )
75+ return metadata_path
0 commit comments