Browse Source

parameterize the filename

main
John-Mark Gurney 5 years ago
parent
commit
56da697d94
1 changed files with 217 additions and 0 deletions
  1. +217
    -0
      ui/cli.py

+ 217
- 0
ui/cli.py View File

@@ -0,0 +1,217 @@
#!/usr/bin/env python

import hashlib
import pasn1
import os.path
import shutil
import string
import tempfile
import unittest
import uuid

_validhashes = set([ 'sha256', 'sha512' ])
_hashlengths = { len(getattr(hashlib, x)().hexdigest()): x for x in _validhashes }

# XXX - add validation
class ObjWrap(object):
'''This is a simple wrapper that turns a JSON object into a pythonesc
object where attribute accesses work.'''

def __init__(self, obj):
self._obj = obj

def __getattr__(self, k):
return self._obj[k]

def __getitem__(self, k):
return self._obj[k]

def __to_dict__(self):
return self._obj

def __eq__(self, o):
return cmp(self._obj, o) == 0

def _trytodict(o):
try:
return 'dict', o.__to_dict__()
except Exception:
raise TypeError('unable to find __to_dict__ on %s' % type(o))

_asn1coder = pasn1.ASN1DictCoder(coerce=_trytodict)

class ObjectStore(object):
'''A container to store for the various Metadata objects.'''

def __init__(self):
self._uuids = {}
self._hashes = {}

@staticmethod
def makehash(hashstr, strict=True):
'''Take a hash string, and return a valid hash string from it.

This makes sure that it is of the correct type and length.

If strict is False, the function will detect the length and
return a valid hash if one can be found.'''

try:
hash, value = hashstr.split(':')
except ValueError:
if strict:
raise

hash = _hashlengths[len(hashstr)]
value = hashstr

if strict and len(str(value).translate(None, string.hexdigits.lower())) != 0:
raise ValueError('value has invalid hex digits (must be lower case)', value)

if hash in _validhashes:
return ':'.join((hash, value))

raise ValueError

def __len__(self):
return len(self._uuids)

def store(self, fname):
'''Write out the objects in the store to the file named
fname.'''

with open(fname, 'w') as fp:
fp.write(_asn1coder.dumps(self._uuids.values()))

def loadobj(self, obj):
'''Load obj into the data store.'''

if not isinstance(obj, ObjWrap):
obj = ObjWrap(obj)

id = uuid.UUID(obj.uuid)
self._uuids[id] = obj
for j in obj.hashes:
h = self.makehash(j)
self._hashes.setdefault(h, []).append(obj)

def load(self, fname):
'''Load objects from the provided file name.

Basic validation will be done on the objects in the file.

The objects will be accessible via other methods.'''

with open(fname) as fp:
objs = _asn1coder.loads(fp.read())

for i in objs:
self.loadobj(i)

def by_id(self, id):
'''Look up an object by it's UUID.'''

uid = uuid.UUID(id)
return self._uuids[uid]

def by_hash(self, hash):
'''Look up an object by it's hash value.'''

h = self.makehash(hash, strict=False)
return self._hashes[h]

class FileObject(object):
def __init__(self, _dir, filename):
self._dir = _dir
self._fname = filename

@property
def filename(self):
'''The name of the file.'''

return self._fname

@property
def dir(self):
'''The directory of the file.'''

return self._dir

@property
def id(self):
'''The UUID of the path to this file.'''

# XXX make sure this is correct
return uuid.uuid5(uuid.NAMESPACE_URL, 'someurl' + '/'.join(os.path.split(self._dir) + ( self._fname, )))

def enumeratedir(_dir):
'''Enumerate all the files and directories (not recursive) in _dir.

Returned is a list of FileObjects.'''

return map(lambda x: FileObject(_dir, x), os.listdir(_dir))

class _TestCases(unittest.TestCase):
def setUp(self):
d = tempfile.mkdtemp()
self.basetempdir = d
self.tempdir = os.path.join(d, 'subdir')

shutil.copytree(os.path.join('fixtures', 'testfiles'),
self.tempdir)

def tearDown(self):
shutil.rmtree(self.basetempdir)
self.tempdir = None

def test_makehash(self):
self.assertRaises(ValueError, ObjectStore.makehash, 'slkj')
self.assertRaises(ValueError, ObjectStore.makehash, 'sha256:91751cee0a1ab8414400238a761411daa29643ab4b8243e9a91649e25be53ADA')

self.assertEqual(ObjectStore.makehash('cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e', strict=False), 'sha512:cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e')
self.assertEqual(ObjectStore.makehash('e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855', strict=False), 'sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855')

def test_enumeratedir(self):
files = enumeratedir(self.tempdir)
ftest = files[0]
fname = 'test.txt'

self.assertEqual(ftest.filename, fname)
self.assertEqual(ftest.dir, self.tempdir)
self.assertEqual(ftest.id, uuid.uuid5(uuid.NAMESPACE_URL,
'someurl' + '/'.join(os.path.split(self.tempdir) +
( fname, ))))

def test_objectstore(self):
objst = ObjectStore()

objst.load(os.path.join('fixtures', 'sample.data.pasn1'))

objst.loadobj({
'type': 'metadata',
'uuid': 'c9a1d1e2-3109-4efd-8948-577dc15e44e7',
'hashes': [ 'sha256:91751cee0a1ab8414400238a761411daa29643ab4b8243e9a91649e25be53ada' ],
'lang': 'en',
})

lst = objst.by_hash('91751cee0a1ab8414400238a761411daa29643ab4b8243e9a91649e25be53ada')
self.assertEqual(len(lst), 2)

byid = objst.by_id('3e466e06-45de-4ecc-84ba-2d2a3d970e96')

self.assertIn(byid, lst)

r = byid

self.assertEqual(r.uuid, '3e466e06-45de-4ecc-84ba-2d2a3d970e96')
self.assertEqual(r['dc:author'], 'John-Mark Gurney')

objst.store('testfile.pasn1')

with open('testfile.pasn1') as fp:
objs = _asn1coder.loads(fp.read())

self.assertEqual(len(objs), len(objst))

for i in objs:
self.assertEqual(objst.by_id(i['uuid']), i)

Loading…
Cancel
Save