diff options
author | Lars Wirzenius <liw@liw.fi> | 2011-07-15 17:45:20 +0300 |
---|---|---|
committer | Lars Wirzenius <liw@liw.fi> | 2011-07-15 17:45:20 +0300 |
commit | c0e137d0e003ce2f9bf11a3a08c4aaf4f6b37825 (patch) | |
tree | 2cffcef476d60a3782f8586ee15dbff7a339b0d6 | |
parent | 9923407a330f84b2c6c74a600644d3fccfc1f39c (diff) | |
download | obnam-c0e137d0e003ce2f9bf11a3a08c4aaf4f6b37825.tar.gz |
Move metadata encoding and decoding into the metadata module.
That's where it belongs.
-rwxr-xr-x | metadata-speed | 6 | ||||
-rw-r--r-- | obnamlib/__init__.py | 2 | ||||
-rw-r--r-- | obnamlib/clientmetadatatree_tests.py | 4 | ||||
-rw-r--r-- | obnamlib/metadata.py | 97 | ||||
-rw-r--r-- | obnamlib/metadata_tests.py | 36 | ||||
-rw-r--r-- | obnamlib/repo.py | 98 | ||||
-rw-r--r-- | obnamlib/repo_tests.py | 36 |
7 files changed, 141 insertions, 138 deletions
diff --git a/metadata-speed b/metadata-speed index 6d93cad6..3b6525cf 100755 --- a/metadata-speed +++ b/metadata-speed @@ -37,10 +37,10 @@ def main(): fs = obnamlib.LocalFS('.') fs.connect() metadata = obnamlib.read_metadata(fs, '.') - encoded = obnamlib.repo.encode_metadata(metadata) + encoded = obnamlib.encode_metadata(metadata) calibrate = measure(n, lambda: None) - encode = measure(n, lambda: obnamlib.repo.encode_metadata(metadata)) - decode = measure(n, lambda: obnamlib.repo.decode_metadata(encoded)) + encode = measure(n, lambda: obnamlib.encode_metadata(metadata)) + decode = measure(n, lambda: obnamlib.decode_metadata(encoded)) print 'encode: %.1f s' % (n/(encode - calibrate)) print 'decode: %.1f s' % (n/(decode - calibrate)) diff --git a/obnamlib/__init__.py b/obnamlib/__init__.py index cdbc8f60..da5b8c3c 100644 --- a/obnamlib/__init__.py +++ b/obnamlib/__init__.py @@ -56,7 +56,7 @@ from pluginbase import ObnamPlugin from vfs import VirtualFileSystem, VfsFactory, VfsTests from vfs_local import LocalFS from metadata import (read_metadata, set_metadata, Metadata, metadata_fields, - metadata_verify_fields) + metadata_verify_fields, encode_metadata, decode_metadata) from repo_tree import RepositoryTree from chunklist import ChunkList from clientlist import ClientList diff --git a/obnamlib/clientmetadatatree_tests.py b/obnamlib/clientmetadatatree_tests.py index 2fe02a28..dd3503c9 100644 --- a/obnamlib/clientmetadatatree_tests.py +++ b/obnamlib/clientmetadatatree_tests.py @@ -150,9 +150,9 @@ class ClientMetadataTreeFileOpsTests(unittest.TestCase): self.client.start_generation() self.clientid = self.client.get_generation_id(self.client.tree) self.file_metadata = obnamlib.Metadata(st_mode=stat.S_IFREG | 0666) - self.file_encoded = obnamlib.repo.encode_metadata(self.file_metadata) + self.file_encoded = obnamlib.encode_metadata(self.file_metadata) self.dir_metadata = obnamlib.Metadata(st_mode=stat.S_IFDIR | 0777) - self.dir_encoded = obnamlib.repo.encode_metadata(self.dir_metadata) + self.dir_encoded = obnamlib.encode_metadata(self.dir_metadata) def tearDown(self): shutil.rmtree(self.tempdir) diff --git a/obnamlib/metadata.py b/obnamlib/metadata.py index e81852f0..0fd25032 100644 --- a/obnamlib/metadata.py +++ b/obnamlib/metadata.py @@ -18,6 +18,9 @@ import grp import os import pwd import stat +import struct + +import obnamlib metadata_verify_fields = ( @@ -146,4 +149,98 @@ def set_metadata(fs, filename, metadata, getuid=None): getuid = getuid or os.getuid if getuid() == 0: fs.lchown(filename, metadata.st_uid, metadata.st_gid) + + +metadata_format = struct.Struct('!Q' + # flags + 'Q' + # st_mode + 'QQ' + # st_mtime (as two integers) + 'QQ' + # st_atime (as two integers) + 'Q' + # st_nlink + 'Q' + # st_size + 'Q' + # st_uid + 'Q' + # st_gid + 'Q' + # st_dev + 'Q' + # st_ino + 'Q' + # st_blocks + 'Q' + # len of groupname + 'Q' + # len of username + 'Q' + # len of symlink target + '') + +def encode_metadata(metadata): + flags = 0 + for i, name in enumerate(obnamlib.metadata_fields): + if getattr(metadata, name) is not None: + flags |= (1 << i) + + if metadata.st_mtime is None: + mtime_a, mtime_b = 0, 0 + else: + mtime_a, mtime_b = metadata.st_mtime.as_integer_ratio() + if metadata.st_atime is None: + atime_a, atime_b = 0, 0 + else: + atime_a, atime_b = metadata.st_atime.as_integer_ratio() + packed = metadata_format.pack(flags, + metadata.st_mode or 0, + mtime_a, mtime_b, + atime_a, atime_b, + metadata.st_nlink or 0, + metadata.st_size or 0, + metadata.st_uid or 0, + metadata.st_gid or 0, + metadata.st_dev or 0, + metadata.st_ino or 0, + metadata.st_blocks or 0, + len(metadata.groupname or ''), + len(metadata.username or ''), + len(metadata.target or '')) + return (packed + + (metadata.groupname or '') + + (metadata.username or '') + + (metadata.target or '')) + +def decode_metadata(encoded): + + items = metadata_format.unpack_from(encoded) + flags = items[0] + pos = [1, metadata_format.size] + metadata = obnamlib.Metadata() + + def is_present(field): + i = obnamlib.metadata_fields.index(field) + return (flags & (1 << i)) != 0 + + def decode(field, num_items, inc_offset, getvalue): + if is_present(field): + value = getvalue(pos[0], pos[1]) + setattr(metadata, field, value) + if inc_offset: + pos[1] += len(value) + pos[0] += num_items + + def decode_integer(field): + decode(field, 1, False, lambda i, o: items[i]) + + def decode_float(field): + decode(field, 2, False, lambda i, o: float(items[i]) / items[i+1]) + + def decode_string(field): + decode(field, 1, True, lambda i, o: encoded[o:o + items[i]]) + + decode_integer('st_mode') + decode_float('st_mtime') + decode_float('st_atime') + decode_integer('st_nlink') + decode_integer('st_size') + decode_integer('st_uid') + decode_integer('st_gid') + decode_integer('st_dev') + decode_integer('st_ino') + decode_integer('st_blocks') + decode_string('groupname') + decode_string('username') + decode_string('target') + + return metadata diff --git a/obnamlib/metadata_tests.py b/obnamlib/metadata_tests.py index 2d356cca..c57ee303 100644 --- a/obnamlib/metadata_tests.py +++ b/obnamlib/metadata_tests.py @@ -206,3 +206,39 @@ class SetMetadataTests(unittest.TestCase): self.assertEqual(st.st_mode, self.metadata.st_mode) self.assertEqual(st.st_mtime, self.metadata.st_mtime) + +class MetadataCodingTests(unittest.TestCase): + + def test_round_trip(self): + metadata = obnamlib.metadata.Metadata(st_mode=1, + st_mtime=2.12756, + st_nlink=3, + st_size=4, + st_uid=5, + st_blocks=6, + st_dev=7, + st_gid=8, + st_ino=9, + st_atime=10.123, + groupname='group', + username='user', + target='target') + encoded = obnamlib.encode_metadata(metadata) + decoded = obnamlib.decode_metadata(encoded) + for name in dir(metadata): + if name in obnamlib.metadata.metadata_fields: + self.assertEqual(getattr(metadata, name), + getattr(decoded, name), + 'attribute %s must be equal (%s vs %s)' % + (name, getattr(metadata, name), + getattr(decoded, name))) + + def test_round_trip_for_None_values(self): + metadata = obnamlib.metadata.Metadata() + encoded = obnamlib.encode_metadata(metadata) + decoded = obnamlib.decode_metadata(encoded) + for name in dir(metadata): + if name in obnamlib.metadata.metadata_fields: + self.assertEqual(getattr(decoded, name), None, + 'attribute %s must be None' % name) + diff --git a/obnamlib/repo.py b/obnamlib/repo.py index 36651423..b7204f98 100644 --- a/obnamlib/repo.py +++ b/obnamlib/repo.py @@ -83,100 +83,6 @@ def require_started_generation(method): return method(self, *args, **kwargs) return helper - - -metadata_format = struct.Struct('!Q' + # flags - 'Q' + # st_mode - 'QQ' + # st_mtime (as two integers) - 'QQ' + # st_atime (as two integers) - 'Q' + # st_nlink - 'Q' + # st_size - 'Q' + # st_uid - 'Q' + # st_gid - 'Q' + # st_dev - 'Q' + # st_ino - 'Q' + # st_blocks - 'Q' + # len of groupname - 'Q' + # len of username - 'Q' + # len of symlink target - '') - -def encode_metadata(metadata): - flags = 0 - for i, name in enumerate(obnamlib.metadata_fields): - if getattr(metadata, name) is not None: - flags |= (1 << i) - - if metadata.st_mtime is None: - mtime_a, mtime_b = 0, 0 - else: - mtime_a, mtime_b = metadata.st_mtime.as_integer_ratio() - if metadata.st_atime is None: - atime_a, atime_b = 0, 0 - else: - atime_a, atime_b = metadata.st_atime.as_integer_ratio() - packed = metadata_format.pack(flags, - metadata.st_mode or 0, - mtime_a, mtime_b, - atime_a, atime_b, - metadata.st_nlink or 0, - metadata.st_size or 0, - metadata.st_uid or 0, - metadata.st_gid or 0, - metadata.st_dev or 0, - metadata.st_ino or 0, - metadata.st_blocks or 0, - len(metadata.groupname or ''), - len(metadata.username or ''), - len(metadata.target or '')) - return (packed + - (metadata.groupname or '') + - (metadata.username or '') + - (metadata.target or '')) - -def decode_metadata(encoded): - - items = metadata_format.unpack_from(encoded) - flags = items[0] - pos = [1, metadata_format.size] - metadata = obnamlib.Metadata() - - def is_present(field): - i = obnamlib.metadata_fields.index(field) - return (flags & (1 << i)) != 0 - - def decode(field, num_items, inc_offset, getvalue): - if is_present(field): - value = getvalue(pos[0], pos[1]) - setattr(metadata, field, value) - if inc_offset: - pos[1] += len(value) - pos[0] += num_items - - def decode_integer(field): - decode(field, 1, False, lambda i, o: items[i]) - - def decode_float(field): - decode(field, 2, False, lambda i, o: float(items[i]) / items[i+1]) - - def decode_string(field): - decode(field, 1, True, lambda i, o: encoded[o:o + items[i]]) - - decode_integer('st_mode') - decode_float('st_mtime') - decode_float('st_atime') - decode_integer('st_nlink') - decode_integer('st_size') - decode_integer('st_uid') - decode_integer('st_gid') - decode_integer('st_dev') - decode_integer('st_ino') - decode_integer('st_blocks') - decode_string('groupname') - decode_string('username') - decode_string('target') - - return metadata class HookedFS(object): @@ -601,12 +507,12 @@ class Repository(object): encoded = self.client.get_metadata(gen, filename) except KeyError: raise obnamlib.Error('%s does not exist' % filename) - return decode_metadata(encoded) + return obnamlib.decode_metadata(encoded) @require_started_generation def create(self, filename, metadata): '''Create a new (empty) file in the new generation.''' - encoded = encode_metadata(metadata) + encoded = obnamlib.encode_metadata(metadata) self.client.create(filename, encoded) @require_started_generation diff --git a/obnamlib/repo_tests.py b/obnamlib/repo_tests.py index 8729160b..c5b563f7 100644 --- a/obnamlib/repo_tests.py +++ b/obnamlib/repo_tests.py @@ -24,42 +24,6 @@ import unittest import obnamlib -class MetadataCodingTests(unittest.TestCase): - - def test_round_trip(self): - metadata = obnamlib.metadata.Metadata(st_mode=1, - st_mtime=2.12756, - st_nlink=3, - st_size=4, - st_uid=5, - st_blocks=6, - st_dev=7, - st_gid=8, - st_ino=9, - st_atime=10.123, - groupname='group', - username='user', - target='target') - encoded = obnamlib.repo.encode_metadata(metadata) - decoded = obnamlib.repo.decode_metadata(encoded) - for name in dir(metadata): - if name in obnamlib.metadata.metadata_fields: - self.assertEqual(getattr(metadata, name), - getattr(decoded, name), - 'attribute %s must be equal (%s vs %s)' % - (name, getattr(metadata, name), - getattr(decoded, name))) - - def test_round_trip_for_None_values(self): - metadata = obnamlib.metadata.Metadata() - encoded = obnamlib.repo.encode_metadata(metadata) - decoded = obnamlib.repo.decode_metadata(encoded) - for name in dir(metadata): - if name in obnamlib.metadata.metadata_fields: - self.assertEqual(getattr(decoded, name), None, - 'attribute %s must be None' % name) - - class RepositoryRootNodeTests(unittest.TestCase): def setUp(self): |