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

Side by Side Diff: tools/android/loading/run_sandwich.py

Issue 1690233002: sandwich: Save browser cache as zip archive preserving all timestamps (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@d02
Patch Set: Created 4 years, 10 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
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #! /usr/bin/env python 1 #! /usr/bin/env python
2 # Copyright 2016 The Chromium Authors. All rights reserved. 2 # Copyright 2016 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """Instructs Chrome to load series of web pages and reports results. 6 """Instructs Chrome to load series of web pages and reports results.
7 7
8 When running Chrome is sandwiched between preprocessed disk caches and 8 When running Chrome is sandwiched between preprocessed disk caches and
9 WepPageReplay serving all connections. 9 WepPageReplay serving all connections.
10 10
11 TODO(pasko): implement cache preparation and WPR. 11 TODO(pasko): implement cache preparation and WPR.
12 """ 12 """
13 13
14 import argparse 14 import argparse
15 import json
15 import logging 16 import logging
16 import os 17 import os
18 import shutil
17 import sys 19 import sys
20 import tempfile
18 import time 21 import time
22 import zipfile
19 23
20 _SRC_DIR = os.path.abspath(os.path.join( 24 _SRC_DIR = os.path.abspath(os.path.join(
21 os.path.dirname(__file__), '..', '..', '..')) 25 os.path.dirname(__file__), '..', '..', '..'))
22 26
23 sys.path.append(os.path.join(_SRC_DIR, 'third_party', 'catapult', 'devil')) 27 sys.path.append(os.path.join(_SRC_DIR, 'third_party', 'catapult', 'devil'))
24 from devil.android import device_utils 28 from devil.android import device_utils
25 29
26 sys.path.append(os.path.join(_SRC_DIR, 'build', 'android')) 30 sys.path.append(os.path.join(_SRC_DIR, 'build', 'android'))
27 from pylib import constants 31 from pylib import constants
28 import devil_chromium 32 import devil_chromium
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
93 json.dump({'traceEvents': events['events'], 'metadata': {}}, f, indent=2) 97 json.dump({'traceEvents': events['events'], 'metadata': {}}, f, indent=2)
94 except IOError: 98 except IOError:
95 logging.warning('Could not save a trace: %s' % filename) 99 logging.warning('Could not save a trace: %s' % filename)
96 # Swallow the exception. 100 # Swallow the exception.
97 101
98 102
99 def _UpdateTimestampFromAdbStat(filename, stat): 103 def _UpdateTimestampFromAdbStat(filename, stat):
100 os.utime(filename, (stat.st_time, stat.st_time)) 104 os.utime(filename, (stat.st_time, stat.st_time))
101 105
102 106
103 def _SaveBrowserCache(device, output_directory): 107 def _PullBrowserCache(device):
104 """Pulls the browser cache from the device and saves it locally. 108 """Pulls the browser cache from the device and saves it locally.
105 109
106 Cache is saved with the same file structure as on the device. Timestamps are 110 Cache is saved with the same file structure as on the device. Timestamps are
107 important to preserve because indexing and eviction depends on them. 111 important to preserve because indexing and eviction depends on them.
108 112
109 Args: 113 Returns:
110 output_directory: name of the directory for saving cache. 114 Oemporary directory containing all the browser cache.
mattcary 2016/02/12 10:46:45 Temporary
Benoit L 2016/02/15 12:49:19 s/Oemporary/Temporary/
gabadie 2016/02/15 13:16:44 Done.
111 """ 115 """
112 save_target = os.path.join(output_directory, _CACHE_DIRECTORY_NAME) 116 save_target = tempfile.mkdtemp(suffix='.cache')
113 try:
114 os.makedirs(save_target)
115 except IOError:
116 logging.warning('Could not create directory: %s' % save_target)
117 raise
118
119 cache_directory = '/data/data/' + _CHROME_PACKAGE + '/cache/Cache' 117 cache_directory = '/data/data/' + _CHROME_PACKAGE + '/cache/Cache'
120 for filename, stat in device.adb.Ls(cache_directory): 118 for filename, stat in device.adb.Ls(cache_directory):
121 if filename == '..': 119 if filename == '..':
122 continue 120 continue
123 if filename == '.': 121 if filename == '.':
124 cache_directory_stat = stat 122 cache_directory_stat = stat
125 continue 123 continue
126 original_file = os.path.join(cache_directory, filename) 124 original_file = os.path.join(cache_directory, filename)
127 saved_file = os.path.join(save_target, filename) 125 saved_file = os.path.join(save_target, filename)
128 device.adb.Pull(original_file, saved_file) 126 device.adb.Pull(original_file, saved_file)
129 _UpdateTimestampFromAdbStat(saved_file, stat) 127 _UpdateTimestampFromAdbStat(saved_file, stat)
130 if filename == _INDEX_DIRECTORY_NAME: 128 if filename == _INDEX_DIRECTORY_NAME:
131 # The directory containing the index was pulled recursively, update the 129 # The directory containing the index was pulled recursively, update the
132 # timestamps for known files. They are ignored by cache backend, but may 130 # timestamps for known files. They are ignored by cache backend, but may
133 # be useful for debugging. 131 # be useful for debugging.
134 index_dir_stat = stat 132 index_dir_stat = stat
135 saved_index_dir = os.path.join(save_target, _INDEX_DIRECTORY_NAME) 133 saved_index_dir = os.path.join(save_target, _INDEX_DIRECTORY_NAME)
136 saved_index_file = os.path.join(saved_index_dir, _REAL_INDEX_FILE_NAME) 134 saved_index_file = os.path.join(saved_index_dir, _REAL_INDEX_FILE_NAME)
137 for sub_file, sub_stat in device.adb.Ls(original_file): 135 for sub_file, sub_stat in device.adb.Ls(original_file):
138 if sub_file == _REAL_INDEX_FILE_NAME: 136 if sub_file == _REAL_INDEX_FILE_NAME:
139 _UpdateTimestampFromAdbStat(saved_index_file, sub_stat) 137 _UpdateTimestampFromAdbStat(saved_index_file, sub_stat)
140 break 138 break
141 _UpdateTimestampFromAdbStat(saved_index_dir, index_dir_stat) 139 _UpdateTimestampFromAdbStat(saved_index_dir, index_dir_stat)
142 140
143 # Store the cache directory modification time. It is important to update it 141 # Store the cache directory modification time. It is important to update it
144 # after all files in it have been written. The timestamp is compared with 142 # after all files in it have been written. The timestamp is compared with
145 # the contents of the index file when freshness is determined. 143 # the contents of the index file when freshness is determined.
146 _UpdateTimestampFromAdbStat(save_target, cache_directory_stat) 144 _UpdateTimestampFromAdbStat(save_target, cache_directory_stat)
145 return save_target
147 146
147 def _ZipDirectoryContent(root_directory_path, archive_dest_path):
Benoit L 2016/02/15 12:49:19 nit: 2 blank lines.
gabadie 2016/02/15 13:16:44 Done.
148 """Zip a directory's content recursively with all the directories's
Benoit L 2016/02/15 12:49:19 s/'s/'/
gabadie 2016/02/15 13:16:44 Done.
149 timestamp preserved.
150
151 Args:
152 root_directory_path: The directory's path to archive.
153 archive_dest_path: Archive destination's path.
154 """
155 with zipfile.ZipFile(archive_dest_path, 'w') as zip_output:
156 timestamps = {}
157 for directory_path, dirnames, filenames in os.walk(root_directory_path):
158 for dirname in dirnames:
159 subdirectory_path = os.path.join(directory_path, dirname)
160 subdirectory_relative_path = os.path.relpath(subdirectory_path,
161 root_directory_path)
162 subdirectory_stats = os.stat(subdirectory_path)
163 timestamps[subdirectory_relative_path] = {
164 'atime': subdirectory_stats.st_atime,
165 'mtime': subdirectory_stats.st_mtime}
166 for filename in filenames:
167 file_path = os.path.join(directory_path, filename)
168 file_archive_name = os.path.join('content',
169 os.path.relpath(file_path, root_directory_path))
170 file_stats = os.stat(file_path)
171 timestamps[file_archive_name[8:]] = {
172 'atime': file_stats.st_atime,
173 'mtime': file_stats.st_mtime}
174 zip_output.write(file_path, arcname=file_archive_name)
175 zip_output.writestr('timestamps.json',
176 json.dumps(timestamps, indent=2))
177
178 def _UnzipDirectoryContent(archive_path, directory_dest_path):
179 """Unzip a directory's content recursively with all the directories's
Benoit L 2016/02/15 12:49:19 s/'s/'/
gabadie 2016/02/15 13:16:44 Done.
180 timestamp preserved.
Benoit L 2016/02/15 12:49:19 timestamps.
gabadie 2016/02/15 13:16:44 Done.
181
182 Args:
183 archive_path: Archive's path to unzip.
184 directory_dest_path: Directory destination path.
185 """
186 if not os.path.exists(directory_dest_path):
187 os.makedirs(directory_dest_path)
188
189 with zipfile.ZipFile(archive_path) as zip_input:
190 timestamps = None
191 for file_archive_name in zip_input.namelist():
192 if file_archive_name == 'timestamps.json':
193 timestamps = json.loads(zip_input.read(file_archive_name))
194
Benoit L 2016/02/15 12:49:19 nit: blank line here is weird.
gabadie 2016/02/15 13:16:44 Done.
195 elif file_archive_name.startswith('content/'):
196 file_relative_path = file_archive_name[8:]
197 file_output_path = os.path.join(directory_dest_path, file_relative_path)
198 file_parent_directory_path = os.path.dirname(file_output_path)
199 if not os.path.exists(file_parent_directory_path):
200 os.makedirs(file_parent_directory_path)
201 with open(file_output_path, 'w') as f:
202 f.write(zip_input.read(file_archive_name))
203
204 assert timestamps
205 for relative_path, stats in timestamps.iteritems():
206 output_path = os.path.join(directory_dest_path, relative_path)
207 if not os.path.exists(output_path):
208 os.makedirs(output_path)
209 os.utime(output_path, (stats['atime'], stats['mtime']))
148 210
149 def main(): 211 def main():
150 logging.basicConfig(level=logging.INFO) 212 logging.basicConfig(level=logging.INFO)
151 devil_chromium.Initialize() 213 devil_chromium.Initialize()
152 214
153 parser = argparse.ArgumentParser() 215 parser = argparse.ArgumentParser()
154 parser.add_argument('--job', required=True, 216 parser.add_argument('--job', required=True,
155 help='JSON file with job description.') 217 help='JSON file with job description.')
156 parser.add_argument('--output', required=True, 218 parser.add_argument('--output', required=True,
157 help='Name of output directory to create.') 219 help='Name of output directory to create.')
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
196 pages_loaded += 1 258 pages_loaded += 1
197 _SaveChromeTrace(tracing_track.ToJsonDict(), args.output, 259 _SaveChromeTrace(tracing_track.ToJsonDict(), args.output,
198 str(pages_loaded)) 260 str(pages_loaded))
199 261
200 if args.save_cache: 262 if args.save_cache:
201 # Move Chrome to background to allow it to flush the index. 263 # Move Chrome to background to allow it to flush the index.
202 device.adb.Shell('am start com.google.android.launcher') 264 device.adb.Shell('am start com.google.android.launcher')
203 time.sleep(_TIME_TO_DEVICE_IDLE_SECONDS) 265 time.sleep(_TIME_TO_DEVICE_IDLE_SECONDS)
204 device.KillAll(_CHROME_PACKAGE, quiet=True) 266 device.KillAll(_CHROME_PACKAGE, quiet=True)
205 time.sleep(_TIME_TO_DEVICE_IDLE_SECONDS) 267 time.sleep(_TIME_TO_DEVICE_IDLE_SECONDS)
206 _SaveBrowserCache(device, args.output) 268
269 cache_directory_path = _PullBrowserCache(device)
270 _ZipDirectoryContent(cache_directory_path,
271 os.path.join(args.output, 'cache.zip'))
272 shutil.rmtree(cache_directory_path)
207 273
208 274
209 if __name__ == '__main__': 275 if __name__ == '__main__':
210 sys.exit(main()) 276 sys.exit(main())
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698