2014-09-16 04:18:57 +00:00
|
|
|
import marisa_trie
|
|
|
|
import os
|
|
|
|
import tarfile
|
2014-09-18 19:56:59 +00:00
|
|
|
from aufs import is_aufs_metadata, get_deleted_prefix
|
2014-10-15 19:51:34 +00:00
|
|
|
from util.tarlayerformat import TarLayerFormat
|
2014-09-16 04:18:57 +00:00
|
|
|
|
|
|
|
AUFS_METADATA = u'.wh..wh.'
|
|
|
|
|
|
|
|
AUFS_WHITEOUT = u'.wh.'
|
|
|
|
AUFS_WHITEOUT_PREFIX_LENGTH = len(AUFS_WHITEOUT)
|
|
|
|
|
2014-10-15 19:51:34 +00:00
|
|
|
class StreamLayerMerger(TarLayerFormat):
|
2014-09-16 04:18:57 +00:00
|
|
|
""" Class which creates a generator of the combined TAR data for a set of Docker layers. """
|
|
|
|
def __init__(self, layer_iterator):
|
2014-10-15 19:51:34 +00:00
|
|
|
super(StreamLayerMerger, self).__init__(layer_iterator)
|
2014-09-16 04:18:57 +00:00
|
|
|
|
2014-10-15 01:40:02 +00:00
|
|
|
self.path_trie = marisa_trie.Trie()
|
|
|
|
self.path_encountered = []
|
2014-09-16 04:18:57 +00:00
|
|
|
|
2014-10-15 01:40:02 +00:00
|
|
|
self.prefix_trie = marisa_trie.Trie()
|
|
|
|
self.prefix_encountered = []
|
2014-09-16 04:18:57 +00:00
|
|
|
|
2014-10-15 20:05:51 +00:00
|
|
|
def after_tar_layer(self, current_layer):
|
2014-10-15 01:40:02 +00:00
|
|
|
# Update the tries.
|
|
|
|
self.path_trie = marisa_trie.Trie(self.path_encountered)
|
|
|
|
self.prefix_trie = marisa_trie.Trie(self.prefix_encountered)
|
2014-11-24 21:07:38 +00:00
|
|
|
|
2014-09-19 16:22:54 +00:00
|
|
|
def check_tar_info(self, tar_info):
|
2014-09-16 04:18:57 +00:00
|
|
|
absolute = os.path.relpath(tar_info.name.decode('utf-8'), './')
|
|
|
|
|
2014-09-18 19:56:59 +00:00
|
|
|
# Skip metadata.
|
|
|
|
if is_aufs_metadata(absolute):
|
2014-09-19 16:22:54 +00:00
|
|
|
return False
|
2014-09-16 04:18:57 +00:00
|
|
|
|
2014-09-18 19:56:59 +00:00
|
|
|
# Add any prefix of deleted paths to the prefix list.
|
2014-11-24 21:07:38 +00:00
|
|
|
deleted_prefix = get_deleted_prefix(absolute)
|
2014-09-18 19:56:59 +00:00
|
|
|
if deleted_prefix is not None:
|
2014-10-15 01:40:02 +00:00
|
|
|
self.prefix_encountered.append(deleted_prefix)
|
2014-09-19 16:22:54 +00:00
|
|
|
return False
|
2014-09-16 04:18:57 +00:00
|
|
|
|
|
|
|
# Check if this file has already been encountered somewhere. If so,
|
|
|
|
# skip it.
|
2014-10-15 01:40:02 +00:00
|
|
|
ubsolute = unicode(absolute)
|
2014-10-15 15:57:54 +00:00
|
|
|
if ubsolute in self.path_trie:
|
2014-09-19 16:22:54 +00:00
|
|
|
return False
|
2014-09-16 04:18:57 +00:00
|
|
|
|
2014-10-15 15:57:54 +00:00
|
|
|
# Check if this file is under a deleted path.
|
|
|
|
for prefix in self.prefix_trie.iter_prefixes(ubsolute):
|
|
|
|
if not os.path.relpath(ubsolute, prefix).startswith('..'):
|
|
|
|
return False
|
|
|
|
|
2014-09-18 19:56:59 +00:00
|
|
|
# Otherwise, add the path to the encountered list and return it.
|
2014-10-15 01:40:02 +00:00
|
|
|
self.path_encountered.append(absolute)
|
2014-09-19 16:22:54 +00:00
|
|
|
return True
|