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

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

Issue 24737002: Add Paths as first-class types in configs. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/build
Patch Set: Address comments. I like this one. Created 7 years, 2 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_api.py ('k') | scripts/slave/recipe_modules/android/api.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 import re
2
3 def ResetTostringFns():
4 RecipeConfigType._TOSTRING_MAP.clear() # pylint: disable=W0212
5
6
7 def json_fixup(obj):
8 if isinstance(obj, RecipeConfigType):
9 return str(obj)
10 raise TypeError("%r is not JSON serializable" % obj)
11
12
13 class RecipeConfigType(object):
14 """Base class for custom Recipe config types, intended to be subclassed.
15
16 RecipeConfigTypes are meant to be PURE data. There should be no dependency on
17 any external systems (i.e. no importing sys, os, etc.).
18
19 The subclasses should override default_tostring_fn. This method should
20 produce a string representation of the object. This string representation
21 should contain all of the data members of the subclass. This representation
22 will be used during the execution of the recipe_config_tests.
23
24 External entities (usually recipe modules), can override the default
25 tostring_fn method by calling <RecipeConfigType
26 subclass>.set_tostring_fn(<new method>). This new method will recieve an
27 instance of the RecipeConfigType subclass as its single argument, and is
28 expected to return a string. There is no restriction on the data that the
29 override tostring_fn may use (for example, the Path class in this module has
30 its tostring_fn overridden by the 'path' recipe_module. This new tostring_fn
31 uses data from the current recipe run, like the host os, to return platform
32 specific strings using the data in the Path object).
agable 2013/09/27 20:19:33 I more meant that the parentheses start partway th
iannucci 2013/09/27 23:21:47 Oh. Durp.
33 """
34 _TOSTRING_MAP = {}
35
36 @property
37 def tostring_fn(self):
38 cls = self.__class__
39 return self._TOSTRING_MAP.get(cls.__name__, cls.default_tostring_fn)
40
41 @classmethod
42 def set_tostring_fn(cls, new_tostring_fn):
43 assert cls.__name__ not in cls._TOSTRING_MAP, (
44 'tostring_fn already installed for %s' % cls)
45 cls._TOSTRING_MAP[cls.__name__] = new_tostring_fn
46
47 def default_tostring_fn(self):
48 raise NotImplementedError
49
50 def __str__(self):
51 return self.tostring_fn(self)
52
53
54 class Path(RecipeConfigType):
55 """Represents a path which is relative to a semantically-named base.
56
57 Because there's a lot of platform (separator style) and runtime-specific
58 context (working directory) which goes into assembling a final OS-specific
59 absolute path, we only store three context-free attributes in this Path
60 object.
61 """
62 # Restrict basenames to '[ALL_CAPS]'. This will help catch
63 # errors if someone attempts to provide an actual string path '/some/example'
64 # as the 'base'.
65 BASE_RE = re.compile('\[([A-Z][A-Z_]*)\]')
66
67 def __init__(self, base, *pieces, **kwargs):
68 """Creates a Path
69
70 Args:
71 base (str) - The 'name' of a base path, to be filled in at recipe runtime
72 by the 'path' recipe module.
73 pieces (tuple(str)) - The components of the path relative to base. These
74 pieces must be non-relative (i.e. no '..' or '.', etc. as a piece).
75
76 Kwargs:
77 platform_ext (dict(str, str)) - A mapping from platform name (as defined
78 by the 'platform' module), to a suffix for the path.
79 bypass (bool) - Bypass the type checking and use |base| directly.
agable 2013/09/27 20:19:33 Maybe call it _bypass so no one outside of the pat
iannucci 2013/09/27 23:21:47 Done.
80 """
81 super(Path, self).__init__()
82 assert all(isinstance(x, basestring) for x in pieces), pieces
83 assert not any(x in ('..', '.', '/', '\\') for x in pieces)
84 self.pieces = pieces
85
86 if kwargs.get('bypass'):
87 self.base = base
88 else:
89 base_match = self.BASE_RE.match(base)
90 assert base_match, 'Base should be [ALL_CAPS], got %r' % base
91 self.base = base_match.group(1).lower()
92
93 self.platform_ext = kwargs.get('platform_ext', {})
94
95 def __call__(self, *pieces, **kwargs):
96 kwargs.setdefault('platform_ext', self.platform_ext)
97 kwargs['bypass'] = True
98 return Path(self.base, *filter(bool, self.pieces + pieces), **kwargs)
99
100 def default_tostring_fn(self):
101 suffix = ''
102 if self.platform_ext:
103 suffix = ', platform_ext=%r' % (self.platform_ext,)
104 pieces = ''
105 if self.pieces:
106 pieces = ', ' + (', '.join(map(repr, self.pieces)))
107 return 'Path(\'[%s]\'%s%s)' % (self.base.upper(), pieces, suffix)
OLDNEW
« no previous file with comments | « scripts/slave/recipe_api.py ('k') | scripts/slave/recipe_modules/android/api.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698