forked from curly60e/pyblock
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmigrate_config.py
More file actions
147 lines (116 loc) Β· 3.84 KB
/
Copy pathmigrate_config.py
File metadata and controls
147 lines (116 loc) Β· 3.84 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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#!/usr/bin/env python3
"""
Migration script: Convert PyBLOCK config files from pickle to JSON format.
This script finds all .conf files used by PyBLOCK, reads them as pickle,
and rewrites them as JSON. A backup of each original file is created
with a .pickle.bak extension.
Usage:
python3 migrate_config.py [directory]
If no directory is specified, it searches the current directory and
common PyBLOCK config locations.
"""
import io
import json
import os
import pickle
import shutil
import sys
class SafeUnpickler(pickle.Unpickler):
"""Restricted unpickler that only allows basic Python types."""
SAFE_CLASSES = {
('builtins', 'dict'),
('builtins', 'list'),
('builtins', 'set'),
('builtins', 'tuple'),
('builtins', 'str'),
('builtins', 'int'),
('builtins', 'float'),
('builtins', 'bool'),
('builtins', 'bytes'),
('builtins', 'type'),
}
def find_class(self, module, name):
if (module, name) not in self.SAFE_CLASSES:
raise pickle.UnpicklingError(
f"Blocked unsafe class: {module}.{name}"
)
return super().find_class(module, name)
def safe_pickle_load(f):
"""Load pickle data using restricted unpickler."""
return SafeUnpickler(f).load()
def find_conf_files(search_dirs):
"""Find all .conf files in the given directories."""
conf_files = []
for search_dir in search_dirs:
if not os.path.isdir(search_dir):
continue
for root, _, files in os.walk(search_dir):
for f in files:
if f.endswith('.conf'):
conf_files.append(os.path.join(root, f))
return conf_files
def is_pickle_file(filepath):
"""Check if a file is in pickle format (not valid JSON)."""
try:
with open(filepath, 'r') as f:
json.load(f)
return False # Already JSON
except (json.JSONDecodeError, UnicodeDecodeError, ValueError):
try:
with open(filepath, 'rb') as f:
safe_pickle_load(f)
return True # Valid pickle
except Exception:
return False # Neither pickle nor JSON
def migrate_file(filepath):
"""Migrate a single .conf file from pickle to JSON."""
if not is_pickle_file(filepath):
return False, "already JSON or not a valid pickle file"
try:
# Read pickle data using safe unpickler
with open(filepath, 'rb') as f:
data = safe_pickle_load(f)
# Create backup
backup_path = filepath + '.pickle.bak'
shutil.copy2(filepath, backup_path)
# Write as JSON
with open(filepath, 'w') as f:
json.dump(data, f, indent=2, default=str)
return True, f"migrated (backup: {backup_path})"
except Exception as e:
return False, f"error: {e}"
def main():
if len(sys.argv) > 1:
search_dirs = [sys.argv[1]]
else:
# Search common PyBLOCK config locations
search_dirs = [
'.',
'config',
'pybitblock',
'pybitblock/config',
'pybitblock/SPV',
'pybitblock/SPV/config',
]
conf_files = find_conf_files(search_dirs)
if not conf_files:
print("No .conf files found.")
return
print(f"Found {len(conf_files)} config file(s):\n")
migrated = 0
skipped = 0
errors = 0
for filepath in sorted(conf_files):
success, message = migrate_file(filepath)
status = "OK" if success else "SKIP"
if "error" in message:
status = "ERR"
errors += 1
elif success:
migrated += 1
else:
skipped += 1
print(f" [{status}] {filepath} - {message}")
print(f"\nResults: {migrated} migrated, {skipped} skipped, {errors} errors")
if __name__ == '__main__':
main()