download, downloadunpacked: Check shared directory is not enough. Shared...
download, downloadunpacked: Check shared directory is not enough. Shared directory may be created before completing installation. Check signature file too.
... | @@ -49,24 +49,22 @@ class Recipe: | ... | @@ -49,24 +49,22 @@ class Recipe: |
'exclusive.') | 'exclusive.') | ||
self.parts = None | self.parts = None | ||
self.destination = self.options.get('destination', None) | self.destination = self.options.get('destination', None) | ||
self.shared = shared = is_true(options.get('shared', 'false').lower()) | self.shared = shared = (is_true(options.get('shared', 'false').lower()) and | ||
buildout['buildout'].get('shared-parts', None)) | |||
if self.destination is None: | if self.destination is None: | ||
if shared and buildout['buildout'].get('shared-parts', None): | if shared: | ||
shared_part = buildout['buildout'].get('shared-parts', None) | shared_part = buildout['buildout'].get('shared-parts', None) | ||
top_location = options.get('top_location', '') | top_location = options.get('top_location', '') | ||
shared = os.path.join(shared_part.strip().rstrip('/'), top_location, name) | shared = os.path.join(shared_part.strip().rstrip('/'), top_location, name) | ||
if not os.path.exists(shared): | if not os.path.exists(shared): | ||
os.makedirs(shared) | os.makedirs(shared) | ||
self._debug_signature_text = [] | self._signature = Signature('.slapos.recipe.build.signature') | ||
m = md5() | |||
profile_base_location = options.get('_profile_base_location_', '') | profile_base_location = options.get('_profile_base_location_', '') | ||
for k, v in sorted(options.items()): | for k, v in sorted(options.items()): | ||
if profile_base_location: | if profile_base_location: | ||
v = v.replace(profile_base_location, '${:_profile_base_location_}') | v = v.replace(profile_base_location, '${:_profile_base_location_}') | ||
option_signature = ('%r: %r' % (k, v)).encode() | self._signature.update(k, v) | ||
self._debug_signature_text.append(option_signature) | shared = os.path.join(shared, self._signature.hexdigest()) | ||
m.update(option_signature) | |||
shared = os.path.join(shared, m.hexdigest()) | |||
self.parts = shared | self.parts = shared | ||
self.logger.info('shared directory %s set for %s', shared, name) | self.logger.info('shared directory %s set for %s', shared, name) | ||
else: | else: | ||
... | @@ -99,7 +97,7 @@ class Recipe: | ... | @@ -99,7 +97,7 @@ class Recipe: |
def install(self): | def install(self): | ||
if self.shared: | if self.shared: | ||
self.logger.info('Checking whether package is installed at shared path : %s', self.destination) | self.logger.info('Checking whether package is installed at shared path : %s', self.destination) | ||
if os.path.exists(self.destination): | if self._signature.test(self.destination): | ||
self.logger.info('This shared package has been installed by other package') | self.logger.info('This shared package has been installed by other package') | ||
return [] | return [] | ||
if self.parts is not None: | if self.parts is not None: | ||
... | @@ -160,8 +158,7 @@ class Recipe: | ... | @@ -160,8 +158,7 @@ class Recipe: |
self.options['url'], self.destination) | self.options['url'], self.destination) | ||
if self.shared: | if self.shared: | ||
with open(os.path.join(self.parts, ".slapos.recipe.build.signature"), 'w') as f: | self._signature.save(self.parts) | ||
f.write('\n'.join(self._debug_signature_text)) | |||
make_read_only_recursively(self.parts) | make_read_only_recursively(self.parts) | ||
return [] | return [] | ||
if self.parts is not None: | if self.parts is not None: | ||
... | @@ -236,3 +233,33 @@ def make_read_only_recursively(path): | ... | @@ -236,3 +233,33 @@ def make_read_only_recursively(path): |
make_read_only(os.path.join(root, dir)) | make_read_only(os.path.join(root, dir)) | ||
for file_ in file_list: | for file_ in file_list: | ||
make_read_only(os.path.join(root, file_)) | make_read_only(os.path.join(root, file_)) | ||
class Signature: | |||
def __init__(self, filename): | |||
self.filename = filename | |||
self.item_list = [] | |||
def update(self, key, value): | |||
self.item_list.append(('%r: %r' % (key, value)).encode()) | |||
|
|||
def hexdigest(self): | |||
m = md5() | |||
for item in self.item_list: | |||
m.update(item) | |||
return m.hexdigest() | |||
def dumps(self): | |||
return '\n'.join(self.item_list) | |||
def test(self, folder_path): | |||
digest = self.hexdigest() | |||
if os.path.basename(folder_path) == digest: | |||
target_path = os.path.join(folder_path, self.filename) | |||
if os.path.exists(target_path) and open(target_path).read() == self.dumps(): | |||
return True | |||
return False | |||
def save(self, folder_path): | |||
with open(os.path.join(folder_path, self.filename), 'w') as f: | |||
f.write(self.dumps()) |