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

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

Issue 1151423002: Move recipe engine to third_party/recipe_engine. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/build
Patch Set: Moved field_composer_test with its buddies Created 5 years, 6 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 | « scripts/slave/recipe_config.py ('k') | scripts/slave/recipe_loader.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 import abc
6 import re
7
8 from collections import namedtuple
9
10 from infra.libs import infra_types
11
12
13 RECIPE_MODULE_PREFIX = 'RECIPE_MODULES'
14
15
16 def ResetTostringFns():
17 RecipeConfigType._TOSTRING_MAP.clear() # pylint: disable=W0212
18
19
20 def json_fixup(obj):
21 if isinstance(obj, RecipeConfigType):
22 return str(obj)
23 thawed = infra_types.thaw(obj)
24 if thawed is not obj: # i.e. it was a frozen type
25 return thawed
26 raise TypeError("%r is not JSON serializable" % obj)
27
28
29 class RecipeConfigType(object):
30 """Base class for custom Recipe config types, intended to be subclassed.
31
32 RecipeConfigTypes are meant to be PURE data. There should be no dependency on
33 any external systems (i.e. no importing sys, os, etc.).
34
35 The subclasses should override default_tostring_fn. This method should
36 produce a string representation of the object. This string representation
37 should contain all of the data members of the subclass. This representation
38 will be used during the execution of the recipe_config_tests.
39
40 External entities (usually recipe modules), can override the default
41 tostring_fn method by calling <RecipeConfigType
42 subclass>.set_tostring_fn(<new method>). This new method will recieve an
43 instance of the RecipeConfigType subclass as its single argument, and is
44 expected to return a string. There is no restriction on the data that the
45 override tostring_fn may use. For example, the Path class in this module has
46 its tostring_fn overridden by the 'path' recipe_module. This new tostring_fn
47 uses data from the current recipe run, like the host os, to return platform
48 specific strings using the data in the Path object.
49 """
50 _TOSTRING_MAP = {}
51
52 @property
53 def tostring_fn(self):
54 cls = self.__class__
55 return self._TOSTRING_MAP.get(cls.__name__, cls.default_tostring_fn)
56
57 @classmethod
58 def set_tostring_fn(cls, new_tostring_fn):
59 assert cls.__name__ not in cls._TOSTRING_MAP, (
60 'tostring_fn already installed for %s' % cls)
61 cls._TOSTRING_MAP[cls.__name__] = new_tostring_fn
62
63 def default_tostring_fn(self):
64 raise NotImplementedError
65
66 def __str__(self):
67 return self.tostring_fn(self) # pylint: disable=not-callable
68
69
70 class BasePath(object):
71 __metaclass__ = abc.ABCMeta
72
73
74 class NamedBasePath(BasePath, namedtuple('NamedBasePath', 'name')):
75 # Restrict basenames to '[ALL_CAPS]'. This will help catch
76 # errors if someone attempts to provide an actual string path '/some/example'
77 # as the 'base'.
78 BASE_RE = re.compile(r'\[([A-Z][A-Z_]*)\]')
79
80 @staticmethod
81 def parse(base):
82 base_match = NamedBasePath.BASE_RE.match(base)
83 assert base_match, 'Base should be [ALL_CAPS], got %r' % base
84 return NamedBasePath(base_match.group(1).lower())
85
86 def __repr__(self):
87 return '[%s]' % self.name.upper()
88
89
90 class ModuleBasePath(BasePath, namedtuple('ModuleBasePath', 'module')):
91 def __repr__(self):
92 prefix = '%s.' % RECIPE_MODULE_PREFIX
93 assert self.module.__name__.startswith(prefix)
94 name = self.module.__name__[len(prefix):]
95 return 'RECIPE_MODULE[%s]' % name
96
97
98 class Path(RecipeConfigType):
99 """Represents a path which is relative to a semantically-named base.
100
101 Because there's a lot of platform (separator style) and runtime-specific
102 context (working directory) which goes into assembling a final OS-specific
103 absolute path, we only store three context-free attributes in this Path
104 object.
105 """
106
107 def __init__(self, base, *pieces, **kwargs):
108 """Creates a Path
109
110 Args:
111 base (str) - The 'name' of a base path, to be filled in at recipe runtime
112 by the 'path' recipe module.
113 pieces (tuple(str)) - The components of the path relative to base. These
114 pieces must be non-relative (i.e. no '..' or '.', etc. as a piece).
115
116 Kwargs:
117 platform_ext (dict(str, str)) - A mapping from platform name (as defined
118 by the 'platform' module), to a suffix for the path.
119 """
120 super(Path, self).__init__()
121 assert all(isinstance(x, basestring) for x in pieces), pieces
122 assert not any(x in ('..', '.', '/', '\\') for x in pieces)
123 self.pieces = pieces
124
125 if isinstance(base, BasePath):
126 self.base = base
127 elif isinstance(base, basestring):
128 self.base = NamedBasePath.parse(base)
129 else:
130 raise ValueError('%s is not a valid base path' % base)
131
132 self.platform_ext = kwargs.get('platform_ext', {})
133
134 def __eq__(self, other):
135 return (self.base == other.base and
136 self.pieces == other.pieces and
137 self.platform_ext == other.platform_ext)
138
139 def __ne__(self, other):
140 return not self.base == other
141
142 def join(self, *pieces, **kwargs):
143 kwargs.setdefault('platform_ext', self.platform_ext)
144 return Path(self.base, *filter(bool, self.pieces + pieces), **kwargs)
145
146 def is_parent_of(self, child):
147 """True if |child| is in a subdirectory of this path."""
148 # Assumes base paths are not nested.
149 # TODO(vadimsh): We should not rely on this assumption.
150 if self.base != child.base:
151 return False
152 # A path is not a parent to itself.
153 if len(self.pieces) >= len(child.pieces):
154 return False
155 return child.pieces[:len(self.pieces)] == self.pieces
156
157 def default_tostring_fn(self):
158 suffix = ''
159 if self.platform_ext:
160 suffix = ', platform_ext=%r' % (self.platform_ext,)
161 pieces = ''
162 if self.pieces:
163 pieces = ', ' + (', '.join(map(repr, self.pieces)))
164 return 'Path(\'%s\'%s%s)' % (self.base, pieces, suffix)
OLDNEW
« no previous file with comments | « scripts/slave/recipe_config.py ('k') | scripts/slave/recipe_loader.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698