|
@@ -0,0 +1,85 @@ |
|
|
|
|
|
import glob |
|
|
|
|
|
import hashlib |
|
|
|
|
|
import os.path |
|
|
|
|
|
import sys |
|
|
|
|
|
|
|
|
|
|
|
from importlib.abc import MetaPathFinder, Loader |
|
|
|
|
|
from importlib.machinery import ModuleSpec |
|
|
|
|
|
|
|
|
|
|
|
class FileDirCAS(object): |
|
|
|
|
|
def __init__(self, path): |
|
|
|
|
|
self._path = path |
|
|
|
|
|
self._hashes = {} |
|
|
|
|
|
|
|
|
|
|
|
for i in glob.glob(os.path.join(path, '*.py')): |
|
|
|
|
|
_, hash = self.read_hash_file(i) |
|
|
|
|
|
self._hashes[hash] = i |
|
|
|
|
|
|
|
|
|
|
|
def read_hash_file(self, fname): |
|
|
|
|
|
with open(fname, 'rb') as fp: |
|
|
|
|
|
data = fp.read() |
|
|
|
|
|
hash = hashlib.sha256(data).hexdigest() |
|
|
|
|
|
|
|
|
|
|
|
return data, hash |
|
|
|
|
|
|
|
|
|
|
|
def is_package(self, hash): |
|
|
|
|
|
return False |
|
|
|
|
|
|
|
|
|
|
|
def exec_module(self, hash, module): |
|
|
|
|
|
parts = hash.split('_', 2) |
|
|
|
|
|
fname = self._hashes[parts[2]] |
|
|
|
|
|
|
|
|
|
|
|
data, fhash = self.read_hash_file(fname) |
|
|
|
|
|
|
|
|
|
|
|
if fhash != parts[2]: |
|
|
|
|
|
raise ValueError('file no longer matches hash on disk') |
|
|
|
|
|
|
|
|
|
|
|
exec(data, module.__dict__) |
|
|
|
|
|
|
|
|
|
|
|
class CASFinder(MetaPathFinder, Loader): |
|
|
|
|
|
def __init__(self): |
|
|
|
|
|
self._loaders = [] |
|
|
|
|
|
|
|
|
|
|
|
sys.meta_path.append(self) |
|
|
|
|
|
|
|
|
|
|
|
def register(self, loader): |
|
|
|
|
|
self._loaders.append(loader) |
|
|
|
|
|
|
|
|
|
|
|
# MetaPathFinder methods |
|
|
|
|
|
def find_spec(self, fullname, path, target=None): |
|
|
|
|
|
if path is None: |
|
|
|
|
|
ms = ModuleSpec(fullname, self, is_package=True) |
|
|
|
|
|
else: |
|
|
|
|
|
parts = fullname.split('.') |
|
|
|
|
|
for l in self._loaders: |
|
|
|
|
|
ispkg = l.is_package(parts[1]) |
|
|
|
|
|
break |
|
|
|
|
|
|
|
|
|
|
|
ms = ModuleSpec(fullname, self, is_package=True, loader_state=(parts[1], l)) |
|
|
|
|
|
|
|
|
|
|
|
return ms |
|
|
|
|
|
|
|
|
|
|
|
def invalidate_caches(self): |
|
|
|
|
|
return None |
|
|
|
|
|
|
|
|
|
|
|
# Loader methods |
|
|
|
|
|
def exec_module(self, module): |
|
|
|
|
|
if module.__name__ == 'cas': |
|
|
|
|
|
pass |
|
|
|
|
|
else: |
|
|
|
|
|
hash, load = module.__spec__.loader_state |
|
|
|
|
|
load.exec_module(hash, module) |
|
|
|
|
|
|
|
|
|
|
|
import unittest |
|
|
|
|
|
|
|
|
|
|
|
class Test(unittest.TestCase): |
|
|
|
|
|
def test_casimport(self): |
|
|
|
|
|
f = CASFinder() |
|
|
|
|
|
f.register(FileDirCAS(os.path.join(os.path.dirname(__file__), '..', 'fixtures'))) |
|
|
|
|
|
|
|
|
|
|
|
import cas |
|
|
|
|
|
|
|
|
|
|
|
from cas.v1_f_330884aa2febb5e19fb7194ec6a69ed11dd3d77122f1a5175ee93e73cf0161c3 import hello |
|
|
|
|
|
|
|
|
|
|
|
name = 'Olof' |
|
|
|
|
|
self.assertEqual(hello(name), 'hello ' + name) |