| OLD | NEW |
| 1 # Copyright 2013 The Chromium Authors. All rights reserved. | 1 # Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 from copy import deepcopy | 5 from copy import deepcopy |
| 6 | 6 |
| 7 from file_system import FileSystem, StatInfo, FileNotFoundError | 7 from file_system import FileSystem, StatInfo, FileNotFoundError |
| 8 from future import Future | 8 from future import Future |
| 9 | 9 |
| 10 class _AsyncFetchFuture(object): | 10 class _AsyncFetchFuture(object): |
| (...skipping 20 matching lines...) Expand all Loading... |
| 31 self._patched_file_system._GetDirectoryListingFromPatch(path)) | 31 self._patched_file_system._GetDirectoryListingFromPatch(path)) |
| 32 if original_listing is None: | 32 if original_listing is None: |
| 33 if len(added) == 0: | 33 if len(added) == 0: |
| 34 raise FileNotFoundError('Directory %s not found in the patch.' % path) | 34 raise FileNotFoundError('Directory %s not found in the patch.' % path) |
| 35 return added | 35 return added |
| 36 return list((set(original_listing) | set(added)) - set(deleted)) | 36 return list((set(original_listing) | set(added)) - set(deleted)) |
| 37 | 37 |
| 38 class PatchedFileSystem(FileSystem): | 38 class PatchedFileSystem(FileSystem): |
| 39 ''' Class to fetch resources with a patch applied. | 39 ''' Class to fetch resources with a patch applied. |
| 40 ''' | 40 ''' |
| 41 def __init__(self, host_file_system, patcher): | 41 def __init__(self, base_file_system, patcher): |
| 42 self._host_file_system = host_file_system | 42 self._base_file_system = base_file_system |
| 43 self._patcher = patcher | 43 self._patcher = patcher |
| 44 | 44 |
| 45 def Read(self, paths, binary=False): | 45 def Read(self, paths, binary=False): |
| 46 patched_files = set() | 46 patched_files = set() |
| 47 added, deleted, modified = self._patcher.GetPatchedFiles() | 47 added, deleted, modified = self._patcher.GetPatchedFiles() |
| 48 if set(paths) & set(deleted): | 48 if set(paths) & set(deleted): |
| 49 raise FileNotFoundError('Files are removed from the patch.') | 49 raise FileNotFoundError('Files are removed from the patch.') |
| 50 patched_files |= (set(added) | set(modified)) | 50 patched_files |= (set(added) | set(modified)) |
| 51 dir_paths = set(path for path in paths if path.endswith('/')) | 51 dir_paths = set(path for path in paths if path.endswith('/')) |
| 52 file_paths = set(paths) - dir_paths | 52 file_paths = set(paths) - dir_paths |
| 53 patched_paths = file_paths & patched_files | 53 patched_paths = file_paths & patched_files |
| 54 unpatched_paths = file_paths - patched_files | 54 unpatched_paths = file_paths - patched_files |
| 55 return Future(delegate=_AsyncFetchFuture( | 55 return Future(delegate=_AsyncFetchFuture( |
| 56 self._host_file_system.Read(unpatched_paths, binary), | 56 self._base_file_system.Read(unpatched_paths, binary), |
| 57 self._patcher.Apply(patched_paths, self._host_file_system, binary), | 57 self._patcher.Apply(patched_paths, self._base_file_system, binary), |
| 58 self._TryReadDirectory(dir_paths, binary), | 58 self._TryReadDirectory(dir_paths, binary), |
| 59 self)) | 59 self)) |
| 60 | 60 |
| 61 ''' Given the list of patched files, it's not possible to determine whether | 61 ''' Given the list of patched files, it's not possible to determine whether |
| 62 a directory to read exists in self._host_file_system. So try reading each one | 62 a directory to read exists in self._base_file_system. So try reading each one |
| 63 and handle FileNotFoundError. | 63 and handle FileNotFoundError. |
| 64 ''' | 64 ''' |
| 65 def _TryReadDirectory(self, paths, binary): | 65 def _TryReadDirectory(self, paths, binary): |
| 66 value = {} | 66 value = {} |
| 67 for path in paths: | 67 for path in paths: |
| 68 assert path.endswith('/') | 68 assert path.endswith('/') |
| 69 try: | 69 try: |
| 70 value[path] = self._host_file_system.ReadSingle(path, binary) | 70 value[path] = self._base_file_system.ReadSingle(path, binary) |
| 71 except FileNotFoundError: | 71 except FileNotFoundError: |
| 72 value[path] = None | 72 value[path] = None |
| 73 return value | 73 return value |
| 74 | 74 |
| 75 def _GetDirectoryListingFromPatch(self, path): | 75 def _GetDirectoryListingFromPatch(self, path): |
| 76 assert path.endswith('/') | 76 assert path.endswith('/') |
| 77 def _FindChildrenInPath(files, path): | 77 def _FindChildrenInPath(files, path): |
| 78 result = [] | 78 result = [] |
| 79 for f in files: | 79 for f in files: |
| 80 if f.startswith(path): | 80 if f.startswith(path): |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 119 version = self._patcher.GetVersion() | 119 version = self._patcher.GetVersion() |
| 120 assert version is not None | 120 assert version is not None |
| 121 version = 'patched_%s' % version | 121 version = 'patched_%s' % version |
| 122 | 122 |
| 123 directory, filename = path.rsplit('/', 1) | 123 directory, filename = path.rsplit('/', 1) |
| 124 added, deleted, modified = self._GetDirectoryListingFromPatch( | 124 added, deleted, modified = self._GetDirectoryListingFromPatch( |
| 125 directory + '/') | 125 directory + '/') |
| 126 | 126 |
| 127 if len(added) > 0: | 127 if len(added) > 0: |
| 128 # There are new files added. It's possible (if |directory| is new) that | 128 # There are new files added. It's possible (if |directory| is new) that |
| 129 # self._host_file_system.Stat will throw an exception. | 129 # self._base_file_system.Stat will throw an exception. |
| 130 try: | 130 try: |
| 131 stat_info = self._PatchStat( | 131 stat_info = self._PatchStat( |
| 132 self._host_file_system.Stat(directory + '/'), | 132 self._base_file_system.Stat(directory + '/'), |
| 133 version, | 133 version, |
| 134 added, | 134 added, |
| 135 deleted, | 135 deleted, |
| 136 modified) | 136 modified) |
| 137 except FileNotFoundError: | 137 except FileNotFoundError: |
| 138 stat_info = StatInfo( | 138 stat_info = StatInfo( |
| 139 version, | 139 version, |
| 140 dict((child, version) for child in added + modified)) | 140 dict((child, version) for child in added + modified)) |
| 141 elif len(deleted) + len(modified) > 0: | 141 elif len(deleted) + len(modified) > 0: |
| 142 # No files were added. | 142 # No files were added. |
| 143 stat_info = self._PatchStat(self._host_file_system.Stat(directory + '/'), | 143 stat_info = self._PatchStat(self._base_file_system.Stat(directory + '/'), |
| 144 version, | 144 version, |
| 145 added, | 145 added, |
| 146 deleted, | 146 deleted, |
| 147 modified) | 147 modified) |
| 148 else: | 148 else: |
| 149 # No changes are made in this directory. | 149 # No changes are made in this directory. |
| 150 return self._host_file_system.Stat(path) | 150 return self._base_file_system.Stat(path) |
| 151 | 151 |
| 152 if stat_info.child_versions is not None: | 152 if stat_info.child_versions is not None: |
| 153 if filename: | 153 if filename: |
| 154 if filename in stat_info.child_versions: | 154 if filename in stat_info.child_versions: |
| 155 stat_info = StatInfo(stat_info.child_versions[filename]) | 155 stat_info = StatInfo(stat_info.child_versions[filename]) |
| 156 else: | 156 else: |
| 157 raise FileNotFoundError('%s was not in child versions' % filename) | 157 raise FileNotFoundError('%s was not in child versions' % filename) |
| 158 return stat_info | 158 return stat_info |
| 159 | 159 |
| 160 def GetIdentity(self): | 160 def GetIdentity(self): |
| 161 return '%s(%s,%s)' % (self.__class__.__name__, | 161 return '%s(%s,%s)' % (self.__class__.__name__, |
| 162 self._host_file_system.GetIdentity(), | 162 self._base_file_system.GetIdentity(), |
| 163 self._patcher.GetIdentity()) | 163 self._patcher.GetIdentity()) |
| OLD | NEW |