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

Side by Side Diff: scripts/slave/recipe_config_types.py

Issue 985273002: Changed recipe_modules base paths to be abstract entities in their own right. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/build
Patch Set: Actual code change Created 5 years, 9 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | scripts/slave/recipe_loader.py » ('j') | scripts/slave/recipe_modules/path/api.py » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 import abc
5 import re 6 import re
6 7
8 from collections import namedtuple
9
7 from infra.libs import infra_types 10 from infra.libs import infra_types
8 11
9 def ResetTostringFns(): 12 def ResetTostringFns():
10 RecipeConfigType._TOSTRING_MAP.clear() # pylint: disable=W0212 13 RecipeConfigType._TOSTRING_MAP.clear() # pylint: disable=W0212
11 14
12 15
13 def json_fixup(obj): 16 def json_fixup(obj):
14 if isinstance(obj, RecipeConfigType): 17 if isinstance(obj, RecipeConfigType):
15 return str(obj) 18 return str(obj)
16 thawed = infra_types.thaw(obj) 19 thawed = infra_types.thaw(obj)
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
53 'tostring_fn already installed for %s' % cls) 56 'tostring_fn already installed for %s' % cls)
54 cls._TOSTRING_MAP[cls.__name__] = new_tostring_fn 57 cls._TOSTRING_MAP[cls.__name__] = new_tostring_fn
55 58
56 def default_tostring_fn(self): 59 def default_tostring_fn(self):
57 raise NotImplementedError 60 raise NotImplementedError
58 61
59 def __str__(self): 62 def __str__(self):
60 return self.tostring_fn(self) # pylint: disable=not-callable 63 return self.tostring_fn(self) # pylint: disable=not-callable
61 64
62 65
66 class BasePath(object):
67 __metaclass__ = abc.ABCMeta
68
69
70 class NamedBasePath(BasePath, namedtuple('NamedBasePath', 'name')):
71 # Restrict basenames to '[ALL_CAPS]'. This will help catch
72 # errors if someone attempts to provide an actual string path '/some/example'
73 # as the 'base'.
74 BASE_RE = re.compile(r'\[([A-Z][A-Z_]*)\]')
75
76 @staticmethod
77 def parse(base):
78 base_match = NamedBasePath.BASE_RE.match(base)
79 assert base_match, 'Base should be [ALL_CAPS], got %r' % base
80 return NamedBasePath(base_match.group(1).lower())
81
82 def __repr__(self):
83 return '[%s]' % self.name.upper()
84
85
86 class ModuleBasePath(BasePath, namedtuple('ModuleBasePath', ('module',))):
iannucci 2015/03/07 02:55:02 I think this r an oops. Let's stick with line 70 s
luqui 2015/03/09 18:49:28 Done.
87 def __repr__(self):
88 name = re.sub(r'^RECIPE_MODULES\.', '', self.module.__name__)
iannucci 2015/03/07 02:55:03 let's pull the regex out too, and add a comment as
luqui 2015/03/09 18:49:28 Done.
89 return 'MODULE[%s]' % name
iannucci 2015/03/07 02:55:02 let's do "RECIPE_MODULE" instead, since MODULE is
luqui 2015/03/09 18:49:28 Done.
90
91
92 class ConcreteBasePath(BasePath, namedtuple('ConcreteBasePath', 'path')):
93 def __repr__(self):
94 return self.path
95
96
63 class Path(RecipeConfigType): 97 class Path(RecipeConfigType):
64 """Represents a path which is relative to a semantically-named base. 98 """Represents a path which is relative to a semantically-named base.
65 99
66 Because there's a lot of platform (separator style) and runtime-specific 100 Because there's a lot of platform (separator style) and runtime-specific
67 context (working directory) which goes into assembling a final OS-specific 101 context (working directory) which goes into assembling a final OS-specific
68 absolute path, we only store three context-free attributes in this Path 102 absolute path, we only store three context-free attributes in this Path
69 object. 103 object.
70 """ 104 """
71 # Restrict basenames to '[ALL_CAPS]'. This will help catch
72 # errors if someone attempts to provide an actual string path '/some/example'
73 # as the 'base'.
74 BASE_RE = re.compile(r'\[([A-Z][A-Z_]*)\]')
75 105
76 def __init__(self, base, *pieces, **kwargs): 106 def __init__(self, base, *pieces, **kwargs):
77 """Creates a Path 107 """Creates a Path
78 108
79 Args: 109 Args:
80 base (str) - The 'name' of a base path, to be filled in at recipe runtime 110 base (str) - The 'name' of a base path, to be filled in at recipe runtime
81 by the 'path' recipe module. 111 by the 'path' recipe module.
82 pieces (tuple(str)) - The components of the path relative to base. These 112 pieces (tuple(str)) - The components of the path relative to base. These
83 pieces must be non-relative (i.e. no '..' or '.', etc. as a piece). 113 pieces must be non-relative (i.e. no '..' or '.', etc. as a piece).
84 114
85 Kwargs: 115 Kwargs:
86 platform_ext (dict(str, str)) - A mapping from platform name (as defined 116 platform_ext (dict(str, str)) - A mapping from platform name (as defined
87 by the 'platform' module), to a suffix for the path. 117 by the 'platform' module), to a suffix for the path.
88 _bypass (bool) - Bypass the type checking and use |base| directly. Don't
89 use this outside of the 'path' module or this class.
90 """ 118 """
91 super(Path, self).__init__() 119 super(Path, self).__init__()
92 assert all(isinstance(x, basestring) for x in pieces), pieces 120 assert all(isinstance(x, basestring) for x in pieces), pieces
93 assert not any(x in ('..', '.', '/', '\\') for x in pieces) 121 assert not any(x in ('..', '.', '/', '\\') for x in pieces)
94 self.pieces = pieces 122 self.pieces = pieces
95 123
96 if kwargs.get('_bypass'): 124 if isinstance(base, BasePath):
97 self.base = base 125 self.base = base
126 elif isinstance(base, basestring):
127 self.base = NamedBasePath.parse(base)
98 else: 128 else:
99 base_match = self.BASE_RE.match(base) 129 raise ValueError('%s is not a valid base path' % base)
100 assert base_match, 'Base should be [ALL_CAPS], got %r' % base
101 self.base = base_match.group(1).lower()
102 130
103 self.platform_ext = kwargs.get('platform_ext', {}) 131 self.platform_ext = kwargs.get('platform_ext', {})
104 132
105 def __eq__(self, other): 133 def __eq__(self, other):
106 return (self.base == other.base and 134 return (self.base == other.base and
107 self.pieces == other.pieces and 135 self.pieces == other.pieces and
108 self.platform_ext == other.platform_ext) 136 self.platform_ext == other.platform_ext)
109 137
110 def __ne__(self, other): 138 def __ne__(self, other):
111 return not self.base == other 139 return not self.base == other
112 140
113 def join(self, *pieces, **kwargs): 141 def join(self, *pieces, **kwargs):
114 kwargs.setdefault('platform_ext', self.platform_ext) 142 kwargs.setdefault('platform_ext', self.platform_ext)
115 kwargs['_bypass'] = True
116 return Path(self.base, *filter(bool, self.pieces + pieces), **kwargs) 143 return Path(self.base, *filter(bool, self.pieces + pieces), **kwargs)
117 144
118 def is_parent_of(self, child): 145 def is_parent_of(self, child):
119 """True if |child| is in a subdirectory of this path.""" 146 """True if |child| is in a subdirectory of this path."""
120 # Assumes base paths are not nested. 147 # Assumes base paths are not nested.
121 # TODO(vadimsh): We should not rely on this assumption. 148 # TODO(vadimsh): We should not rely on this assumption.
122 if self.base != child.base: 149 if self.base != child.base:
123 return False 150 return False
124 # A path is not a parent to itself. 151 # A path is not a parent to itself.
125 if len(self.pieces) >= len(child.pieces): 152 if len(self.pieces) >= len(child.pieces):
126 return False 153 return False
127 return child.pieces[:len(self.pieces)] == self.pieces 154 return child.pieces[:len(self.pieces)] == self.pieces
128 155
129 def default_tostring_fn(self): 156 def default_tostring_fn(self):
130 suffix = '' 157 suffix = ''
131 if self.platform_ext: 158 if self.platform_ext:
132 suffix = ', platform_ext=%r' % (self.platform_ext,) 159 suffix = ', platform_ext=%r' % (self.platform_ext,)
133 pieces = '' 160 pieces = ''
134 if self.pieces: 161 if self.pieces:
135 pieces = ', ' + (', '.join(map(repr, self.pieces))) 162 pieces = ', ' + (', '.join(map(repr, self.pieces)))
136 return 'Path(\'[%s]\'%s%s)' % (self.base.upper(), pieces, suffix) 163 return 'Path(\'%s\'%s%s)' % (self.base, pieces, suffix)
OLDNEW
« no previous file with comments | « no previous file | scripts/slave/recipe_loader.py » ('j') | scripts/slave/recipe_modules/path/api.py » ('J')

Powered by Google App Engine
This is Rietveld 408576698