page.py revision 58537e28ecd584eab876aee8be7156509866d23a
1# Copyright (c) 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. 4import os 5import re 6import urlparse 7 8 9def _UrlPathJoin(*args): 10 """Joins each path in |args| for insertion into a URL path. 11 12 This is distinct from os.path.join in that: 13 1. Forward slashes are always used. 14 2. Paths beginning with '/' are not treated as absolute. 15 16 For example: 17 _UrlPathJoin('a', 'b') => 'a/b' 18 _UrlPathJoin('a/', 'b') => 'a/b' 19 _UrlPathJoin('a', '/b') => 'a/b' 20 _UrlPathJoin('a/', '/b') => 'a/b' 21 """ 22 if not args: 23 return '' 24 if len(args) == 1: 25 return str(args[0]) 26 else: 27 args = [str(arg).replace('\\', '/') for arg in args] 28 work = [args[0]] 29 for arg in args[1:]: 30 if not arg: 31 continue 32 if arg.startswith('/'): 33 work.append(arg[1:]) 34 else: 35 work.append(arg) 36 joined = reduce(os.path.join, work) 37 return joined.replace('\\', '/') 38 39class Page(object): 40 def __init__(self, url, page_set, attributes=None, base_dir=None): 41 parsed_url = urlparse.urlparse(url) 42 if not parsed_url.scheme: 43 abspath = os.path.abspath(os.path.join(base_dir, parsed_url.path)) 44 if os.path.exists(abspath): 45 url = 'file://%s' % os.path.abspath(os.path.join(base_dir, url)) 46 else: 47 raise Exception('URLs must be fully qualified: %s' % url) 48 self.url = url 49 self.page_set = page_set 50 self.base_dir = base_dir 51 52 # These attributes can be set dynamically by the page. 53 self.credentials = None 54 self.disabled = False 55 self.name = None 56 self.script_to_evaluate_on_commit = None 57 58 if attributes: 59 for k, v in attributes.iteritems(): 60 setattr(self, k, v) 61 62 def __getattr__(self, name): 63 if self.page_set and hasattr(self.page_set, name): 64 return getattr(self.page_set, name) 65 66 raise AttributeError() 67 68 @property 69 def is_file(self): 70 parsed_url = urlparse.urlparse(self.url) 71 return parsed_url.scheme == 'file' 72 73 @property 74 def is_local(self): 75 parsed_url = urlparse.urlparse(self.url) 76 return parsed_url.scheme == 'file' or parsed_url.scheme == 'chrome' 77 78 @property 79 def serving_dirs_and_file(self): 80 parsed_url = urlparse.urlparse(self.url) 81 path = _UrlPathJoin(self.base_dir, parsed_url.netloc, parsed_url.path) 82 83 if hasattr(self.page_set, 'serving_dirs'): 84 url_base_dir = os.path.commonprefix(self.page_set.serving_dirs) 85 base_path = _UrlPathJoin(self.base_dir, url_base_dir) 86 return ([_UrlPathJoin(self.base_dir, d) 87 for d in self.page_set.serving_dirs], 88 path.replace(base_path, '')) 89 90 return os.path.split(path) 91 92 @property 93 def file_safe_name(self): 94 """A version of display_name that's safe to use as a filename.""" 95 # Just replace all special characters in the url with underscore. 96 return re.sub('[^a-zA-Z0-9]', '_', self.display_name) 97 98 @property 99 def display_name(self): 100 if self.name: 101 return self.name 102 if not self.is_local: 103 return self.url 104 url_paths = ['/'.join(p.url.strip('/').split('/')[:-1]) 105 for p in self.page_set if p.is_file] 106 common_prefix = os.path.commonprefix(url_paths) 107 return self.url[len(common_prefix):].strip('/') 108 109 @property 110 def archive_path(self): 111 return self.page_set.WprFilePathForPage(self) 112 113 def __str__(self): 114 return self.url 115