Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(121)

Side by Side Diff: chrome/common/extensions/docs/server2/patched_file_system.py

Issue 14125010: Docserver: Add support for viewing docs with a codereview patch applied (Closed) Base URL: https://src.chromium.org/svn/trunk/src/
Patch Set: rebase Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
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
3 # found in the LICENSE file.
4
5 from copy import deepcopy
6
7 from file_system import FileSystem, StatInfo, FileNotFoundError
8 from future import Future
9
10 class _AsyncFetchFuture(object):
11 def __init__(self,
12 unpatched_files_future,
13 patched_files_future,
14 dirs_value,
15 patched_file_system):
16 self._unpatched_files_future = unpatched_files_future
17 self._patched_files_future = patched_files_future
18 self._dirs_value = dirs_value
19 self._patched_file_system = patched_file_system
20
21 def Get(self):
22 files = self._unpatched_files_future.Get()
23 files.update(self._patched_files_future.Get())
24 files.update({path: self._PatchDirectoryListing(path,
25 self._dirs_value[path])
26 for path in self._dirs_value})
27 return files
28
29 def _PatchDirectoryListing(self, path, original_listing):
30 added, deleted, modified = (
31 self._patched_file_system._GetDirectoryListingFromPatch(path))
32 if original_listing is None:
33 if len(added) == 0:
34 raise FileNotFoundError('Directory %s not found in the patch.' % path)
35 return added
36 return list((set(original_listing) | set(added)) - set(deleted))
37
38 class PatchedFileSystem(FileSystem):
39 ''' Class to fetch resources with a patch applied.
40 '''
41 def __init__(self, host_file_system, patcher):
42 self._host_file_system = host_file_system
43 self._patcher = patcher
44
45 def Read(self, paths, binary=False):
46 patched_files = set()
47 added, deleted, modified = self._patcher.GetPatchedFiles()
48 if set(paths) & set(deleted):
49 raise FileNotFoundError('Files are removed from the patch.')
50 patched_files |= (set(added) | set(modified))
51 dir_paths = {path for path in paths if path.endswith('/')}
52 file_paths = set(paths) - dir_paths
53 patched_paths = file_paths & patched_files
54 unpatched_paths = file_paths - patched_files
55 return Future(delegate=_AsyncFetchFuture(
56 self._host_file_system.Read(unpatched_paths, binary),
57 self._patcher.Apply(patched_paths, self._host_file_system, binary),
58 self._TryReadDirectory(dir_paths, binary),
59 self))
60
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
63 and handle FileNotFoundError.
64 '''
65 def _TryReadDirectory(self, paths, binary):
66 value = {}
67 for path in paths:
68 assert path.endswith('/')
69 try:
70 value[path] = self._host_file_system.ReadSingle(path, binary)
71 except FileNotFoundError:
72 value[path] = None
73 return value
74
75 def _GetDirectoryListingFromPatch(self, path):
76 assert path.endswith('/')
77 def _FindChildrenInPath(files, path):
78 result = []
79 for f in files:
80 if f.startswith(path):
81 child_path = f[len(path):]
82 if '/' in child_path:
83 child_name = child_path[0:child_path.find('/') + 1]
84 else:
85 child_name = child_path
86 result.append(child_name)
87 return result
88
89 added, deleted, modified = (tuple(
90 _FindChildrenInPath(files, path)
91 for files in self._patcher.GetPatchedFiles()))
92
93 # A patch applies to files only. It cannot delete directories.
94 deleted_files = [child for child in deleted if not child.endswith('/')]
95 # However, these directories are actually modified because their children
96 # are patched.
97 modified += [child for child in deleted if child.endswith('/')]
98
99 return (added, deleted_files, modified)
100
101 def _PatchStat(self, stat_info, version, added, deleted, modified):
102 assert len(added) + len(deleted) + len(modified) > 0
103 assert stat_info.child_versions is not None
104
105 # Deep copy before patching to make sure it doesn't interfere with values
106 # cached in memory.
107 stat_info = deepcopy(stat_info)
108
109 stat_info.version = version
110 for child in added + modified:
111 stat_info.child_versions[child] = version
112 for child in deleted:
113 if stat_info.child_versions.get(child):
114 del stat_info.child_versions[child]
115
116 return stat_info
117
118 def Stat(self, path):
119 version = self._patcher.GetVersion()
120 if version is None:
121 return self._host_file_system.Stat(path)
not at google - send to devlin 2013/05/11 20:39:53 I think my comments in CacheChainCompiledSystem wi
122 version = 'patched_%s' % version
123
124 directory, filename = path.rsplit('/', 1)
125 added, deleted, modified = self._GetDirectoryListingFromPatch(
126 directory + '/')
127
128 if len(added) > 0:
129 # There are new files added. It's possible (if |directory| is new) that
130 # self._host_file_system.Stat will throw an exception.
131 try:
132 stat_info = self._PatchStat(
133 self._host_file_system.Stat(directory + '/'),
134 version,
135 added,
136 deleted,
137 modified)
138 except FileNotFoundError:
139 stat_info = StatInfo(version, {child: version
140 for child in added + modified})
141 elif len(deleted) + len(modified) > 0:
142 # No files were added.
143 stat_info = self._PatchStat(self._host_file_system.Stat(directory + '/'),
144 version,
145 added,
146 deleted,
147 modified)
148 else:
149 # No changes are made in this directory.
150 return self._host_file_system.Stat(path)
151
152 if stat_info.child_versions is not None:
153 if filename:
154 if filename in stat_info.child_versions:
155 stat_info = StatInfo(stat_info.child_versions[filename])
156 else:
157 raise FileNotFoundError('%s was not in child versions' % filename)
158 return stat_info
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698