manifest.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. import datetime
  2. import logging
  3. import os
  4. from .utils import *
  5. from .fstree import *
  6. MANIFEST_VERSION = 0
  7. class ManifestRecord:
  8. tag = None
  9. @staticmethod
  10. def fromLine(line):
  11. raise NotImplementedError
  12. def toLine(self):
  13. raise NotImplementedError
  14. def _unpack(self, manifest, key, type):
  15. key, value = manifest.readline().split(":", 1)
  16. assert key == key
  17. return type(value)
  18. MANIFEST_TAGS_RECORDS = {}
  19. def addManifestRecord(record: ManifestRecord):
  20. assert record.tag
  21. MANIFEST_TAGS_RECORDS[record.tag] = record
  22. class ManifestRecordVersion(ManifestRecord):
  23. tag = "V"
  24. def __init__(self, version):
  25. self.version = version
  26. @staticmethod
  27. def fromLine(line):
  28. return ManifestRecordVersion(int(line))
  29. def toLine(self):
  30. return f"{self.tag}:{self.version}\n"
  31. addManifestRecord(ManifestRecordVersion)
  32. class ManifestRecordTimestamp(ManifestRecord):
  33. tag = "T"
  34. def __init__(self, timestamp: int):
  35. self.timestamp = int(timestamp)
  36. @staticmethod
  37. def fromLine(line):
  38. return ManifestRecordTimestamp(int(line))
  39. def toLine(self):
  40. return f"{self.tag}:{self.timestamp}\n"
  41. addManifestRecord(ManifestRecordTimestamp)
  42. class ManifestRecordDirectory(ManifestRecord):
  43. tag = "D"
  44. def __init__(self, path: str):
  45. self.path = path
  46. @staticmethod
  47. def fromLine(line):
  48. return ManifestRecordDirectory(line)
  49. def toLine(self):
  50. return f"{self.tag}:{self.path}\n"
  51. addManifestRecord(ManifestRecordDirectory)
  52. class ManifestRecordFile(ManifestRecord):
  53. tag = "F"
  54. def __init__(self, path: str, md5: str, size: int):
  55. self.path = path
  56. self.md5 = md5
  57. self.size = size
  58. @staticmethod
  59. def fromLine(line):
  60. data = line.split(":", 3)
  61. return ManifestRecordFile(data[2], data[0], data[1])
  62. def toLine(self):
  63. return f"{self.tag}:{self.md5}:{self.size}:{self.path}\n"
  64. addManifestRecord(ManifestRecordFile)
  65. class Manifest:
  66. def __init__(self):
  67. self.version = None
  68. self.records = []
  69. self.records.append(ManifestRecordVersion(MANIFEST_VERSION))
  70. self.records.append(ManifestRecordTimestamp(timestamp()))
  71. self.logger = logging.getLogger(self.__class__.__name__)
  72. def load(self, filename):
  73. manifest = open(filename, "r")
  74. for line in manifest.readlines():
  75. line = line.strip()
  76. if len(line) == 0:
  77. continue
  78. tag, line = line.split(":", 1)
  79. record = MANIFEST_TAGS_RECORDS[tag].fromLine(line)
  80. self.records.append(record)
  81. def save(self, filename):
  82. manifest = open(filename, "w+")
  83. for record in self.records:
  84. manifest.write(record.toLine())
  85. manifest.close()
  86. def addDirectory(self, path):
  87. self.records.append(ManifestRecordDirectory(path))
  88. def addFile(self, path, md5, size):
  89. self.records.append(ManifestRecordFile(path, md5, size))
  90. def create(self, directory_path):
  91. for root, dirs, files in os.walk(directory_path):
  92. relative_root = root.replace(directory_path, "", 1)
  93. if relative_root.startswith("/"):
  94. relative_root = relative_root[1:]
  95. # process directories
  96. for dir in dirs:
  97. relative_dir_path = os.path.join(relative_root, dir)
  98. self.logger.info(f'Adding directory: "{relative_dir_path}"')
  99. self.addDirectory(relative_dir_path)
  100. # Process files
  101. for file in files:
  102. relative_file_path = os.path.join(relative_root, file)
  103. full_file_path = os.path.join(root, file)
  104. self.logger.info(f'Adding file: "{relative_file_path}"')
  105. self.addFile(
  106. relative_file_path,
  107. file_md5(full_file_path),
  108. os.path.getsize(full_file_path),
  109. )
  110. def toFsTree(self):
  111. root = FsNode("", FsNode.Type.Directory)
  112. for record in self.records:
  113. if isinstance(record, ManifestRecordDirectory):
  114. root.addDirectory(record.path)
  115. elif isinstance(record, ManifestRecordFile):
  116. root.addFile(record.path, record.md5, record.size)
  117. return root
  118. @staticmethod
  119. def compare(left: "Manifest", right: "Manifest"):
  120. return compare_fs_trees(left.toFsTree(), right.toFsTree())