adesse

Signed testimonials for certifications.
Log | Files | Refs

commit 949879bd36dd77d54cba35a5dc1658dc92dc1d44
parent ca78e2ef2ab956963ca03cd05b8e7624dd667848
Author: lash <dev@holbrook.no>
Date:   Mon,  7 Sep 2026 08:07:50 -0600

Add filesystem store implementation

Diffstat:
Madesse/attachment.py | 16+++++++++++++++-
Aadesse/store/__init__.py | 1+
Aadesse/store/base.py | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aadesse/store/fs.py | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atest/test_store.py | 45+++++++++++++++++++++++++++++++++++++++++++++
Mtest/test_xmp.py | 1-
6 files changed, 171 insertions(+), 2 deletions(-)

diff --git a/adesse/attachment.py b/adesse/attachment.py @@ -10,7 +10,7 @@ from adesse.ns import DF class Attachment(Entity): - def __init__(self, title, description, date, mime, typ=None, lang=None, uu=None): + def __init__(self, title, description, date, mime, typ=None, lang=None, uu=None, opener=None): super().__init__(title, uu=uu) self.description = description self.dt = date.astimezone(datetime.timezone.utc) @@ -18,6 +18,20 @@ class Attachment(Entity): self.typ = typ self.sum = None self.tag = [] + self.opener = opener + self.source = [] + + + def srcadd(self, v): + self.source.append(v) + + + def srcopen(self): + for v in self.source: + f = self.opener(v) + if f != None: + return f + raise FileNotFoundError() def set_sum(self, v, typ=None): diff --git a/adesse/store/__init__.py b/adesse/store/__init__.py @@ -0,0 +1 @@ +from .fs import FsStore diff --git a/adesse/store/base.py b/adesse/store/base.py @@ -0,0 +1,55 @@ +import hashlib +import uuid + + +def hash_for_io(f, hasher): + h = hasher() + h.update(f.read()) + z = h.digest() + return z + + +def sha256_for_path(filepath): + f = open(filepath, 'rb') + z = hash_for_io(f, hashlib.sha256) + f.close() + return z + + +def sha512_for_path(filepath): + f = open(filepath, 'rb') + z = hash_for_io(f, hashlib.sha512) + f.close() + return z + + +class BaseStore: + + def __init__(self, seed=None): + self.transformers = {} + if seed == None: + seed = uuid.uuid4() + self.seed = seed + self.register_uuid() + self.canon = 'uuid' + + + def register(self, key, transformer): + self.transformers[key] = transformer + + + def register_sha256(self): + self.transformers['sha256'] = sha256_for_path + + + def register_sha512(self): + self.transformers['sha512'] = sha512_for_path + + + def register_uuid(self): + self.transformers['uuid'] = self.uuid_for_sum + + + def uuid_for_sum(self, v): + r = uuid.uuid5(self.seed, v) + return r.bytes diff --git a/adesse/store/fs.py b/adesse/store/fs.py @@ -0,0 +1,55 @@ +import os +import shutil +import logging +import tempfile + +from .base import BaseStore + +logg = logging.getLogger('store.fs') + + +class FsStore(BaseStore): + + def __init__(self, path, seed=None): + super(FsStore, self).__init__(seed=seed) + self.path = os.path.realpath(path) + self.state = 0 + self.canon_path = os.path.join(self.path, self.canon) + + + def _ensure_path(self): + if self.state & 1 == 0: + for k in self.transformers.keys(): + d = os.path.join(self.path, k) + os.makedirs(d, exist_ok=True) + logg.info('created store dir {}'.format(d)) + self.state = 1 + + + def put(self, attachment): + self._ensure_path() + (f, fp) = tempfile.mkstemp() + w = os.fdopen(f, 'wb') + f = attachment.srcopen() + while True: + v = f.read() + if len(v) == 0: + break + w.write(v) + w.close() + f.close() + logg.debug('file contents in {}'.format(fp)) + + v = self.transformers[self.canon](fp) + dst = os.path.join(self.canon_path, v.hex()) + shutil.copyfile(fp, dst) + logg.info('canon file to {}'.format(dst)) + + for k in self.transformers.keys(): + v = self.transformers[k](fp) + if k == self.canon: + continue + else: + src = os.path.join(self.path, k, v.hex()) + os.symlink(dst, src) + logg.info('file link {} is {}'.format(k, src)) diff --git a/test/test_store.py b/test/test_store.py @@ -0,0 +1,45 @@ +import unittest +import tempfile +import shutil +import os +import logging +import uuid +import datetime + +from adesse.store import FsStore +from adesse import Attachment + +thisdir = os.path.realpath(os.path.dirname(__file__)) + +logging.basicConfig(level=logging.DEBUG) + + +def testopener(v): + f = open(v, 'rb') + return f + + +class TestFsStore(unittest.TestCase): + + def setUp(self): + self.uubase = uuid.UUID('f253542c-78d1-4187-84f6-e15f3e686591') + self.storedir = tempfile.mkdtemp() + self.store = FsStore(self.storedir, seed=self.uubase) + self.store.register_sha256() + self.store.register_sha512() + + + def tearDown(self): + #shutil.rmtree(self.storedir) + pass + + + def test_put(self): + o = Attachment('title', 'description', datetime.datetime.now(datetime.UTC), 'application/pdf', lang='es', opener=testopener) + fp = os.path.join(thisdir, 'import.pdf') + o.srcadd(fp) + self.store.put(o) + + +if __name__ == '__main__': + unittest.main() diff --git a/test/test_xmp.py b/test/test_xmp.py @@ -27,7 +27,6 @@ class TestXmpLoad(unittest.TestCase): r = xmp.attachment_from_xmp(fp, resource_file='import.pdf', search_dir=[thisdir], uuidns=self.uubase) z = Serializer() r.apply(z) - print(z) if __name__ == '__main__':