-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpaths.py
More file actions
88 lines (67 loc) · 2.38 KB
/
paths.py
File metadata and controls
88 lines (67 loc) · 2.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
"""Centralised path resolution for Bifrost.
Handles the difference between running from source and running as a
frozen PyInstaller executable:
Frozen layout (next to bifrost.exe):
bifrost.exe
addons/ <- addon packages (discovered at runtime)
calibration/ <- writable config JSONs (created on first launch)
Dev layout (project root):
bifrost.py
addons/
*.json <- configs live in project root directly
"""
import sys
import shutil
import logging
from pathlib import Path
logger = logging.getLogger(__name__)
# Files that get copied to the calibration dir on first launch
_DEFAULT_CONFIGS = [
'dh_parameters.json',
'gripper_calibration.json',
'coordinate_frames.json',
'home_position.json',
'park_position.json',
]
def is_frozen() -> bool:
"""True when running as a PyInstaller bundle."""
return getattr(sys, 'frozen', False) and hasattr(sys, '_MEIPASS')
def get_exe_dir() -> Path:
"""Directory containing the executable (or project root in dev).
Use this for resolving external folders that live next to the exe
(addons/, calibration/).
"""
if is_frozen():
return Path(sys.executable).parent
return Path(__file__).parent
def get_bundle_dir() -> Path:
"""Read-only bundled resources (STLs, default configs).
- Frozen: PyInstaller temp extraction directory
- Dev: project root (directory containing this file)
"""
if is_frozen():
return Path(sys._MEIPASS)
return Path(__file__).parent
def get_data_dir() -> Path:
"""Writable config/data directory.
- Frozen: calibration/ folder next to the exe
- Dev: project root (no change from current behaviour)
"""
if is_frozen():
return get_exe_dir() / 'calibration'
return Path(__file__).parent
def initialize_data_dir() -> None:
"""Create the data directory and populate with default configs.
Only copies files that don't already exist, so user edits are preserved.
"""
if not is_frozen():
return # Nothing to do in dev mode
data_dir = get_data_dir()
data_dir.mkdir(exist_ok=True)
bundle_dir = get_bundle_dir()
for filename in _DEFAULT_CONFIGS:
src = bundle_dir / filename
dst = data_dir / filename
if not dst.exists() and src.exists():
shutil.copy2(src, dst)
logger.info(f"Copied default config: {filename}")