1# Copyright 2012 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 5import inspect 6import os 7import re 8import urlparse 9 10 11class Page(object): 12 def __init__(self, url, page_set=None, base_dir=None, name=''): 13 self._url = url 14 self._page_set = page_set 15 # Default value of base_dir is the directory of the file that defines the 16 # class of this page instace. 17 if base_dir is None: 18 base_dir = os.path.dirname(inspect.getfile(self.__class__)) 19 self._base_dir = base_dir 20 self._name = name 21 22 # These attributes can be set dynamically by the page. 23 self.synthetic_delays = dict() 24 self.startup_url = page_set.startup_url if page_set else '' 25 self.credentials = None 26 self.disabled = False 27 self.script_to_evaluate_on_commit = None 28 self._SchemeErrorCheck() 29 30 def _SchemeErrorCheck(self): 31 if not self._scheme: 32 raise ValueError('Must prepend the URL with scheme (e.g. file://)') 33 34 if self.startup_url: 35 startup_url_scheme = urlparse.urlparse(self.startup_url).scheme 36 if not startup_url_scheme: 37 raise ValueError('Must prepend the URL with scheme (e.g. http://)') 38 if startup_url_scheme == 'file': 39 raise ValueError('startup_url with local file scheme is not supported') 40 41 def RunNavigateSteps(self, action_runner): 42 action_runner.NavigateToPage(self) 43 44 def CanRunOnBrowser(self, browser_info): 45 """Override this to returns whether this page can be run on specific 46 browser. 47 48 Args: 49 browser_info: an instance of telemetry.core.browser_info.BrowserInfo 50 """ 51 assert browser_info 52 return True 53 54 @property 55 def page_set(self): 56 return self._page_set 57 58 @property 59 def name(self): 60 return self._name 61 62 @property 63 def url(self): 64 return self._url 65 66 def GetSyntheticDelayCategories(self): 67 result = [] 68 for delay, options in self.synthetic_delays.items(): 69 options = '%f;%s' % (options.get('target_duration', 0), 70 options.get('mode', 'static')) 71 result.append('DELAY(%s;%s)' % (delay, options)) 72 return result 73 74 def __lt__(self, other): 75 return self.url < other.url 76 77 def __cmp__(self, other): 78 x = cmp(self.name, other.name) 79 if x != 0: 80 return x 81 return cmp(self.url, other.url) 82 83 def __str__(self): 84 return self.url 85 86 def AddCustomizeBrowserOptions(self, options): 87 """ Inherit page overrides this to add customized browser options.""" 88 pass 89 90 @property 91 def _scheme(self): 92 return urlparse.urlparse(self.url).scheme 93 94 @property 95 def is_file(self): 96 """Returns True iff this URL points to a file.""" 97 return self._scheme == 'file' 98 99 @property 100 def is_local(self): 101 """Returns True iff this URL is local. This includes chrome:// URLs.""" 102 return self._scheme in ['file', 'chrome', 'about'] 103 104 @property 105 def file_path(self): 106 """Returns the path of the file, stripping the scheme and query string.""" 107 assert self.is_file 108 # Because ? is a valid character in a filename, 109 # we have to treat the url as a non-file by removing the scheme. 110 parsed_url = urlparse.urlparse(self.url[7:]) 111 return os.path.normpath(os.path.join( 112 self._base_dir, parsed_url.netloc + parsed_url.path)) 113 114 @property 115 def file_path_url(self): 116 """Returns the file path, including the params, query, and fragment.""" 117 assert self.is_file 118 file_path_url = os.path.normpath(os.path.join(self._base_dir, self.url[7:])) 119 # Preserve trailing slash or backslash. 120 # It doesn't matter in a file path, but it does matter in a URL. 121 if self.url.endswith('/'): 122 file_path_url += os.sep 123 return file_path_url 124 125 @property 126 def serving_dir(self): 127 file_path = os.path.realpath(self.file_path) 128 if os.path.isdir(file_path): 129 return file_path 130 else: 131 return os.path.dirname(file_path) 132 133 @property 134 def file_safe_name(self): 135 """A version of display_name that's safe to use as a filename.""" 136 # Just replace all special characters in the url with underscore. 137 return re.sub('[^a-zA-Z0-9]', '_', self.display_name) 138 139 @property 140 def display_name(self): 141 if self.name: 142 return self.name 143 if not self.is_file: 144 return self.url 145 all_urls = [p.url.rstrip('/') for p in self.page_set if p.is_file] 146 common_prefix = os.path.dirname(os.path.commonprefix(all_urls)) 147 return self.url[len(common_prefix):].strip('/') 148 149 @property 150 def archive_path(self): 151 return self.page_set.WprFilePathForPage(self) 152