A VCS repository archival tool
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

61 line
1.8 KiB

  1. import abc
  2. import codearchiver.core
  3. import contextlib
  4. import logging
  5. import os.path
  6. import shutil
  7. import typing
  8. _logger = logging.getLogger(__name__)
  9. class Storage(abc.ABC):
  10. @abc.abstractmethod
  11. def put(self, filename: str, index: typing.Optional[codearchiver.core.Index] = None):
  12. '''Put a local file and (if provided) its index into storage. If an error occurs, a partial copy may remain in storage. If it completes, the local input file is removed.'''
  13. def put_result(self, result: codearchiver.core.Result):
  14. '''Put a module's Result into storage. The semantics are as for `put`, and the exact behaviour regarding partial copies and leftover files on errors is undefined.'''
  15. for fn, index in result.files:
  16. self.put(fn, index)
  17. for _, subresult in result.submoduleResults:
  18. self.put_result(subresult)
  19. @abc.abstractmethod
  20. @contextlib.contextmanager
  21. def open(self, filename: str) -> typing.Iterator[typing.BinaryIO]:
  22. '''Open a file from storage.'''
  23. class DirectoryStorage(Storage):
  24. def __init__(self, directory):
  25. super().__init__()
  26. self._directory = directory
  27. def _check_directory(self):
  28. exists = os.path.exists(self._directory)
  29. if exists and not os.path.isdir(self._directory):
  30. raise NotADirectoryError(self._directory)
  31. return exists
  32. def _ensure_directory(self):
  33. if not self._check_directory():
  34. os.makedirs(self._directory)
  35. def put(self, filename, index = None):
  36. self._ensure_directory()
  37. _logger.info(f'Moving {filename} to {self._directory}')
  38. shutil.move(filename, self._directory)
  39. if not index:
  40. return
  41. indexFilename = os.path.join(self._directory, f'{filename}.codearchiver-index')
  42. _logger.info(f'Writing index for {filename} to {indexFilename}')
  43. with open(indexFilename, 'x') as fp:
  44. fp.write(index.serialise())
  45. @contextlib.contextmanager
  46. def open(self, filename):
  47. with open(filename, 'rb') as fp:
  48. yield fp