diff options
author | Lars Wirzenius <liw@liw.fi> | 2015-07-10 12:58:13 +0300 |
---|---|---|
committer | Lars Wirzenius <liw@liw.fi> | 2015-07-10 12:58:13 +0300 |
commit | 33afd1fd235158f4128559338ed9ebd963fca5ee (patch) | |
tree | 336be3092906de56fbc99be68db84e366d86161d | |
parent | 4471eb99a4834fd2bddfaf0cee7331b9ec36c21a (diff) | |
download | obnam-33afd1fd235158f4128559338ed9ebd963fca5ee.tar.gz |
Buffer added files until st_mode is known
Green Albatross needs to know if it the added file is a directory,
before it can add it.
-rw-r--r-- | obnamlib/fmt_ga/client.py | 94 | ||||
-rw-r--r-- | obnamlib/repo_interface.py | 16 |
2 files changed, 99 insertions, 11 deletions
diff --git a/obnamlib/fmt_ga/client.py b/obnamlib/fmt_ga/client.py index 8a2629de..b49774cb 100644 --- a/obnamlib/fmt_ga/client.py +++ b/obnamlib/fmt_ga/client.py @@ -67,6 +67,8 @@ class GAClient(object): def _save_file_metadata(self): for gen in self._generations: metadata = gen.get_file_metadata() + assert not metadata.has_unflushed_added_files(), \ + repr(metadata._added_files._files) gen.set_file_metadata_id(metadata.get_blob_id()) def _get_blob_store(self): @@ -397,6 +399,10 @@ class GAFileMetadata(object): def __init__(self): self._blob_store = None self._blob_id = None + self._added_files = AddedFiles() + + def has_unflushed_added_files(self): + return len(self._added_files) > 0 def set_blob_store(self, blob_store): self._blob_store = blob_store @@ -419,46 +425,112 @@ class GAFileMetadata(object): self._blob_id = self._blob_store.put_blob(blob) def __iter__(self): + for filename in self._added_files: + yield filename for filename in self._load(): yield filename def file_exists(self, filename): - return filename in self._load() + return filename in self._added_files or filename in self._load() def add_file(self, filename): - files = self._load() - if filename not in files: - files[filename] = { - 'keys': {}, - 'chunks': [], - } - self._save(files) + if filename not in self._added_files and filename not in self._load(): + self._added_files.add_file(filename) def remove_file(self, filename): + if filename in self._added_files: + self._added_files.remove_file(filename) files = self._load() if filename in files: del files[filename] self._save(files) def get_file_key(self, filename, key): + if filename in self._added_files: + return self._added_files.get_file_key(filename, key) files = self._load() return files[filename]['keys'].get(key) def set_file_key(self, filename, key, value): - files = self._load() - files[filename]['keys'][key] = value - self._save(files) + if filename in self._added_files: + self._added_files.set_file_key(filename, key, value) + mode_key_name = obnamlib.repo_key_name(obnamlib.REPO_FILE_MODE) + if key == mode_key_name: + files = self._load() + files[filename] = self._added_files.get_file_dict(filename) + self._save(files) + self._added_files.remove_file(filename) + else: + files = self._load() + files[filename]['keys'][key] = value + self._save(files) def get_file_chunk_ids(self, filename): + if filename in self._added_files: + return self._added_files.get_file_chunk_ids(filename) files = self._load() return files[filename]['chunks'] def append_file_chunk_id(self, filename, chunk_id): + if filename in self._added_files: + self._added_files.append_file_chunk_id(filename, chunk_id) + return files = self._load() files[filename]['chunks'].append(chunk_id) self._save(files) def clear_file_chunk_ids(self, filename): + if filename in self._added_files: + self._added_files.clear_file_chunk_ids(filename) + return files = self._load() files[filename]['chunks'] = [] self._save(files) + + +class AddedFiles(object): + + def __init__(self): + self.clear() + + def clear(self): + self._files = {} + + def __contains__(self, filename): + return filename in self._files + + def __iter__(self): + for filename in self._files: + yield filename + + def __len__(self): + return len(self._files) + + def get_file_dict(self, filename): + return self._files[filename] + + def add_file(self, filename): + assert filename not in self._files + self._files[filename] = { + 'keys': {}, + 'chunks': [], + } + + def remove_file(self, filename): + assert filename in self._files + del self._files[filename] + + def get_file_key(self, filename, key): + return self._files[filename]['keys'].get(key) + + def set_file_key(self, filename, key, value): + self._files[filename]['keys'][key] = value + + def get_file_chunk_ids(self, filename): + return self._files[filename]['chunks'] + + def append_file_chunk_id(self, filename, chunk_id): + self._files[filename]['chunks'].append(chunk_id) + + def clear_file_chunk_ids(self, filename): + self._files[filename]['chunks'] = [] diff --git a/obnamlib/repo_interface.py b/obnamlib/repo_interface.py index 59f92d95..1d6910e2 100644 --- a/obnamlib/repo_interface.py +++ b/obnamlib/repo_interface.py @@ -1526,12 +1526,16 @@ class RepositoryInterfaceTests(unittest.TestCase): # pragma: no cover def test_committing_remembers_file_add(self): gen_id = self.create_generation() self.repo.add_file(gen_id, '/foo/bar') + self.repo.set_file_key( + gen_id, '/foo/bar', obnamlib.REPO_FILE_MODE, stat.S_IFREG) self.repo.commit_client('fooclient') self.assertTrue(self.repo.file_exists(gen_id, '/foo/bar')) def test_creating_generation_clones_previous_one(self): gen_id = self.create_generation() self.repo.add_file(gen_id, '/foo/bar') + self.repo.set_file_key( + gen_id, '/foo/bar', obnamlib.REPO_FILE_MODE, stat.S_IFREG) self.repo.commit_client('fooclient') self.repo.lock_client('fooclient') @@ -1547,6 +1551,8 @@ class RepositoryInterfaceTests(unittest.TestCase): # pragma: no cover def test_unlocking_forgets_file_removal(self): gen_id = self.create_generation() self.repo.add_file(gen_id, '/foo/bar') + self.repo.set_file_key( + gen_id, '/foo/bar', obnamlib.REPO_FILE_MODE, stat.S_IFREG) self.repo.commit_client('fooclient') self.repo.lock_client('fooclient') @@ -1559,6 +1565,8 @@ class RepositoryInterfaceTests(unittest.TestCase): # pragma: no cover def test_committing_remembers_file_removal(self): gen_id = self.create_generation() self.repo.add_file(gen_id, '/foo/bar') + self.repo.set_file_key( + gen_id, '/foo/bar', obnamlib.REPO_FILE_MODE, stat.S_IFREG) self.repo.commit_client('fooclient') self.repo.lock_client('fooclient') @@ -1742,6 +1750,8 @@ class RepositoryInterfaceTests(unittest.TestCase): # pragma: no cover gen_id = self.create_generation() self.repo.add_file(gen_id, '/foo/bar') self.repo.set_file_key( + gen_id, '/foo/bar', obnamlib.REPO_FILE_MODE, stat.S_IFREG) + self.repo.set_file_key( gen_id, '/foo/bar', obnamlib.REPO_FILE_TEST_KEY, 'yoyo') self.repo.commit_client('fooclient') value = self.repo.get_file_key( @@ -1752,6 +1762,8 @@ class RepositoryInterfaceTests(unittest.TestCase): # pragma: no cover gen_id = self.create_generation() self.repo.add_file(gen_id, '/foo/bar') self.repo.set_file_key( + gen_id, '/foo/bar', obnamlib.REPO_FILE_MODE, stat.S_IFREG) + self.repo.set_file_key( gen_id, '/foo/bar', obnamlib.REPO_FILE_TEST_KEY, 'first') self.repo.commit_client('fooclient') @@ -1846,6 +1858,8 @@ class RepositoryInterfaceTests(unittest.TestCase): # pragma: no cover def test_unlocking_client_forgets_modified_file_chunk_ids(self): gen_id = self.create_generation() self.repo.add_file(gen_id, '/foo/bar') + self.repo.set_file_key( + gen_id, '/foo/bar', obnamlib.REPO_FILE_MODE, stat.S_IFREG) self.repo.append_file_chunk_id(gen_id, '/foo/bar', 1) self.repo.commit_client('fooclient') @@ -1864,6 +1878,8 @@ class RepositoryInterfaceTests(unittest.TestCase): # pragma: no cover def test_committing_child_remembers_modified_file_chunk_ids(self): gen_id = self.create_generation() self.repo.add_file(gen_id, '/foo/bar') + self.repo.set_file_key( + gen_id, '/foo/bar', obnamlib.REPO_FILE_MODE, stat.S_IFREG) self.repo.append_file_chunk_id(gen_id, '/foo/bar', 1) self.repo.commit_client('fooclient') |