libv8 6.3.292.48.1 → 6.7.288.46.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (195) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +10 -34
  3. data/CHANGELOG.md +16 -0
  4. data/README.md +9 -63
  5. data/Rakefile +2 -2
  6. data/ext/libv8/builder.rb +22 -87
  7. data/ext/libv8/extconf.rb +1 -1
  8. data/ext/libv8/paths.rb +5 -18
  9. data/lib/libv8/version.rb +1 -1
  10. data/spec/location_spec.rb +1 -2
  11. data/spec/spec_helper.rb +0 -1
  12. data/vendor/depot_tools/.gitattributes +1 -2
  13. data/vendor/depot_tools/OWNERS +0 -1
  14. data/vendor/depot_tools/PRESUBMIT.py +11 -6
  15. data/vendor/depot_tools/README.md +0 -1
  16. data/vendor/depot_tools/WATCHLISTS +0 -6
  17. data/vendor/depot_tools/auth.py +129 -87
  18. data/vendor/depot_tools/autoninja +11 -1
  19. data/vendor/depot_tools/autoninja.bat +7 -1
  20. data/vendor/depot_tools/autoninja.py +14 -6
  21. data/vendor/depot_tools/bootstrap/win/manifest.txt +1 -1
  22. data/vendor/depot_tools/bootstrap/win/manifest_bleeding_edge.txt +1 -1
  23. data/vendor/depot_tools/cipd +23 -2
  24. data/vendor/depot_tools/cipd.bat +2 -2
  25. data/vendor/depot_tools/cipd_client_version +1 -1
  26. data/vendor/depot_tools/cipd_manifest.txt +17 -7
  27. data/vendor/depot_tools/cit.py +7 -6
  28. data/vendor/depot_tools/cpplint.py +195 -35
  29. data/vendor/depot_tools/detect_host_arch.py +51 -0
  30. data/vendor/depot_tools/download_from_google_storage.py +85 -26
  31. data/vendor/depot_tools/fetch.py +11 -6
  32. data/vendor/depot_tools/fetch_configs/chromium.py +0 -1
  33. data/vendor/depot_tools/fetch_configs/goma_client.py +41 -0
  34. data/vendor/depot_tools/fetch_configs/infra.py +0 -1
  35. data/vendor/depot_tools/fetch_configs/infra_internal.py +0 -1
  36. data/vendor/depot_tools/gclient-new-workdir.py +4 -0
  37. data/vendor/depot_tools/gclient.py +732 -476
  38. data/vendor/depot_tools/gclient_eval.py +569 -58
  39. data/vendor/depot_tools/gclient_scm.py +258 -46
  40. data/vendor/depot_tools/gclient_utils.py +17 -1
  41. data/vendor/depot_tools/gerrit_util.py +46 -13
  42. data/vendor/depot_tools/git_cache.py +0 -2
  43. data/vendor/depot_tools/git_cl.py +176 -335
  44. data/vendor/depot_tools/git_common.py +19 -16
  45. data/vendor/depot_tools/git_footers.py +19 -5
  46. data/vendor/depot_tools/git_hyper_blame.py +9 -3
  47. data/vendor/depot_tools/git_new_branch.py +15 -3
  48. data/vendor/depot_tools/git_upstream_diff.py +7 -2
  49. data/vendor/depot_tools/gsutil.py +1 -1
  50. data/vendor/depot_tools/infra/config/cq.cfg +1 -2
  51. data/vendor/depot_tools/infra/config/recipes.cfg +1 -1
  52. data/vendor/depot_tools/luci-auth +13 -0
  53. data/vendor/depot_tools/luci-auth.bat +8 -0
  54. data/vendor/depot_tools/man/html/depot_tools.html +0 -8
  55. data/vendor/depot_tools/man/html/git-upstream-diff.html +20 -3
  56. data/vendor/depot_tools/man/man1/git-upstream-diff.1 +27 -6
  57. data/vendor/depot_tools/man/man7/depot_tools.7 +0 -5
  58. data/vendor/depot_tools/man/man7/depot_tools_tutorial.7 +2 -2
  59. data/vendor/depot_tools/man/src/git-upstream-diff.txt +21 -3
  60. data/vendor/depot_tools/man/src/make_docs.sh +6 -0
  61. data/vendor/depot_tools/my_activity.py +283 -93
  62. data/vendor/depot_tools/owners.py +9 -4
  63. data/vendor/depot_tools/owners_finder.py +7 -3
  64. data/vendor/depot_tools/post_build_ninja_summary.py +322 -0
  65. data/vendor/depot_tools/presubmit_canned_checks.py +91 -106
  66. data/vendor/depot_tools/presubmit_support.py +219 -157
  67. data/vendor/depot_tools/prpc +13 -0
  68. data/vendor/depot_tools/prpc.bat +8 -0
  69. data/vendor/depot_tools/recipes/OWNERS +3 -1
  70. data/vendor/depot_tools/recipes/README.recipes.md +70 -111
  71. data/vendor/depot_tools/recipes/recipe_modules/bot_update/__init__.py +12 -5
  72. data/vendor/depot_tools/recipes/recipe_modules/bot_update/api.py +36 -68
  73. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/deprecated_got_revision_mapping.json +0 -8
  74. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/{trychange_oauth2_json.json → no_apply_patch_on_gclient.json} +64 -10
  75. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/{no_shallow.json → shallow.json} +1 -1
  76. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob.json +0 -8
  77. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_empty_revision.json +0 -8
  78. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_fail.json +0 -6
  79. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_fail_patch.json +0 -7
  80. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_fail_patch_download.json +0 -6
  81. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_gerrit_angle_deprecated.json +44 -0
  82. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/{trychange_oauth2_buildbot.json → tryjob_gerrit_branch_heads.json} +51 -5
  83. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_v8.json +0 -8
  84. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_v8_head_by_default.json +48 -8
  85. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.py +19 -26
  86. data/vendor/depot_tools/recipes/recipe_modules/bot_update/resources/bot_update.py +193 -155
  87. data/vendor/depot_tools/recipes/recipe_modules/bot_update/test_api.py +9 -0
  88. data/vendor/depot_tools/recipes/recipe_modules/gclient/api.py +2 -7
  89. data/vendor/depot_tools/recipes/recipe_modules/gclient/config.py +31 -5
  90. data/vendor/depot_tools/recipes/recipe_modules/gclient/examples/full.expected/basic.json +37 -19
  91. data/vendor/depot_tools/recipes/recipe_modules/gclient/examples/full.expected/buildbot.json +37 -19
  92. data/vendor/depot_tools/recipes/recipe_modules/gclient/examples/full.expected/revision.json +37 -19
  93. data/vendor/depot_tools/recipes/recipe_modules/gclient/examples/full.expected/tryserver.json +37 -23
  94. data/vendor/depot_tools/recipes/recipe_modules/gclient/examples/full.py +4 -0
  95. data/vendor/depot_tools/recipes/recipe_modules/gerrit/api.py +40 -8
  96. data/vendor/depot_tools/recipes/recipe_modules/gerrit/examples/full.expected/basic.json +3 -3
  97. data/vendor/depot_tools/recipes/recipe_modules/gerrit/examples/full.py +6 -3
  98. data/vendor/depot_tools/recipes/recipe_modules/gitiles/OWNERS +0 -1
  99. data/vendor/depot_tools/recipes/recipe_modules/tryserver/__init__.py +0 -1
  100. data/vendor/depot_tools/recipes/recipe_modules/tryserver/api.py +7 -56
  101. data/vendor/depot_tools/recipes/recipe_modules/tryserver/examples/full.expected/with_wrong_patch.json +0 -1
  102. data/vendor/depot_tools/recipes/recipe_modules/tryserver/examples/full.py +15 -16
  103. data/vendor/depot_tools/recipes/recipes.py +4 -2
  104. data/vendor/depot_tools/recipes/trigger_recipe_roller.txt +12 -0
  105. data/vendor/depot_tools/roll_dep.py +35 -37
  106. data/vendor/depot_tools/support/chromite_wrapper +1 -1
  107. data/vendor/depot_tools/third_party/logilab/astroid/README.chromium +3 -3
  108. data/vendor/depot_tools/third_party/logilab/astroid/__pkginfo__.py +2 -2
  109. data/vendor/depot_tools/third_party/logilab/astroid/astpeephole.py +86 -0
  110. data/vendor/depot_tools/third_party/logilab/astroid/bases.py +53 -66
  111. data/vendor/depot_tools/third_party/logilab/astroid/brain/py2pytest.py +31 -31
  112. data/vendor/depot_tools/third_party/logilab/astroid/brain/pynose.py +39 -16
  113. data/vendor/depot_tools/third_party/logilab/astroid/brain/pysix_moves.py +225 -189
  114. data/vendor/depot_tools/third_party/logilab/astroid/inference.py +45 -41
  115. data/vendor/depot_tools/third_party/logilab/astroid/manager.py +1 -0
  116. data/vendor/depot_tools/third_party/logilab/astroid/modutils.py +2 -2
  117. data/vendor/depot_tools/third_party/logilab/astroid/node_classes.py +3 -2
  118. data/vendor/depot_tools/third_party/logilab/astroid/nodes.py +1 -0
  119. data/vendor/depot_tools/third_party/logilab/astroid/protocols.py +57 -3
  120. data/vendor/depot_tools/third_party/logilab/astroid/raw_building.py +1 -1
  121. data/vendor/depot_tools/third_party/logilab/astroid/rebuilder.py +21 -1
  122. data/vendor/depot_tools/third_party/logilab/astroid/scoped_nodes.py +58 -33
  123. data/vendor/depot_tools/third_party/pylint/README.chromium +2 -2
  124. data/vendor/depot_tools/third_party/pylint/__pkginfo__.py +3 -3
  125. data/vendor/depot_tools/third_party/pylint/checkers/base.py +6 -18
  126. data/vendor/depot_tools/third_party/pylint/checkers/classes.py +64 -63
  127. data/vendor/depot_tools/third_party/pylint/checkers/design_analysis.py +25 -57
  128. data/vendor/depot_tools/third_party/pylint/checkers/format.py +14 -10
  129. data/vendor/depot_tools/third_party/pylint/checkers/python3.py +142 -37
  130. data/vendor/depot_tools/third_party/pylint/checkers/spelling.py +10 -1
  131. data/vendor/depot_tools/third_party/pylint/checkers/stdlib.py +50 -7
  132. data/vendor/depot_tools/third_party/pylint/checkers/strings.py +1 -1
  133. data/vendor/depot_tools/third_party/pylint/epylint.py +2 -1
  134. data/vendor/depot_tools/third_party/pylint/gui.py +1 -1
  135. data/vendor/depot_tools/third_party/pylint/lint.py +88 -23
  136. data/vendor/depot_tools/third_party/pylint/reporters/html.py +37 -5
  137. data/vendor/depot_tools/third_party/pylint/testutils.py +1 -1
  138. data/vendor/depot_tools/third_party/pylint/utils.py +5 -0
  139. data/vendor/depot_tools/vpython +31 -1
  140. data/vendor/depot_tools/win_toolchain/get_toolchain_if_necessary.py +35 -2
  141. data/vendor/depot_tools/win_toolchain/package_from_installed.py +0 -15
  142. data/vendor/depot_tools/yapf +17 -0
  143. data/vendor/depot_tools/{apply_issue.bat → yapf.bat} +2 -2
  144. metadata +16 -58
  145. data/ext/libv8/compiler.rb +0 -39
  146. data/ext/libv8/compiler/apple_llvm.rb +0 -22
  147. data/ext/libv8/compiler/clang.rb +0 -22
  148. data/ext/libv8/compiler/gcc.rb +0 -22
  149. data/ext/libv8/compiler/generic_compiler.rb +0 -66
  150. data/ext/libv8/make.rb +0 -13
  151. data/ext/libv8/patcher.rb +0 -21
  152. data/patches/0001-Build-a-standalone-static-library.patch +0 -26
  153. data/patches/0002-Don-t-compile-unnecessary-stuff.patch +0 -85
  154. data/patches/0003-Use-the-fPIC-flag-for-the-static-library.patch +0 -25
  155. data/patches/0004-Do-not-embed-debug-symbols-in-macOS-libraries.patch +0 -25
  156. data/patches/0005-Remove-TryInstallOptimizedCode.patch +0 -321
  157. data/patches/mingw-generate-makefiles.sh +0 -97
  158. data/spec/compiler/apple_llvm_spec.rb +0 -37
  159. data/spec/compiler/clang_spec.rb +0 -37
  160. data/spec/compiler/gcc_spec.rb +0 -37
  161. data/spec/compiler/generic_compiler_spec.rb +0 -50
  162. data/spec/compiler_spec.rb +0 -45
  163. data/spec/support/compiler_helpers.rb +0 -47
  164. data/vendor/depot_tools/apply_issue +0 -8
  165. data/vendor/depot_tools/apply_issue.py +0 -315
  166. data/vendor/depot_tools/man/html/git-cherry-pick-upload.html +0 -815
  167. data/vendor/depot_tools/man/man1/git-cherry-pick-upload.1 +0 -80
  168. data/vendor/depot_tools/man/src/_git-cherry-pick-upload_desc.helper.txt +0 -1
  169. data/vendor/depot_tools/man/src/git-cherry-pick-upload.demo.1.sh +0 -17
  170. data/vendor/depot_tools/man/src/git-cherry-pick-upload.txt +0 -35
  171. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/trychange_oauth2.json +0 -8
  172. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/trychange_oauth2_json_win.json +0 -196
  173. data/vendor/depot_tools/recipes/recipe_modules/rietveld/__init__.py +0 -6
  174. data/vendor/depot_tools/recipes/recipe_modules/rietveld/api.py +0 -97
  175. data/vendor/depot_tools/recipes/recipe_modules/rietveld/examples/full.expected/basic.json +0 -8
  176. data/vendor/depot_tools/recipes/recipe_modules/rietveld/examples/full.expected/buildbot.json +0 -30
  177. data/vendor/depot_tools/recipes/recipe_modules/rietveld/examples/full.expected/no_auth.json +0 -27
  178. data/vendor/depot_tools/recipes/recipe_modules/rietveld/examples/full.py +0 -38
  179. data/vendor/depot_tools/recipes/recipe_modules/tryserver/examples/full.expected/with_rietveld_patch.json +0 -69
  180. data/vendor/depot_tools/recipes/recipe_modules/tryserver/examples/full.expected/with_rietveld_patch_new.json +0 -69
  181. data/vendor/depot_tools/third_party/cq_client/OWNERS +0 -2
  182. data/vendor/depot_tools/third_party/cq_client/README.depot_tools.md +0 -2
  183. data/vendor/depot_tools/third_party/cq_client/README.md +0 -59
  184. data/vendor/depot_tools/third_party/cq_client/__init__.py +0 -3
  185. data/vendor/depot_tools/third_party/cq_client/v1/__init__.py +0 -3
  186. data/vendor/depot_tools/third_party/cq_client/v1/cq.pb.go +0 -810
  187. data/vendor/depot_tools/third_party/cq_client/v1/cq.proto +0 -281
  188. data/vendor/depot_tools/third_party/cq_client/v1/cq_pb2.py +0 -794
  189. data/vendor/depot_tools/third_party/cq_client/v1/testdata/cq_both.cfg +0 -71
  190. data/vendor/depot_tools/third_party/cq_client/v1/testdata/cq_gerrit.cfg +0 -58
  191. data/vendor/depot_tools/third_party/cq_client/v1/testdata/cq_rietveld.cfg +0 -60
  192. data/vendor/depot_tools/third_party/cq_client/v2/__init__.py +0 -3
  193. data/vendor/depot_tools/third_party/cq_client/v2/cq.pb.go +0 -792
  194. data/vendor/depot_tools/third_party/cq_client/v2/cq.proto +0 -270
  195. data/vendor/depot_tools/third_party/cq_client/v2/cq_pb2.py +0 -841
@@ -3,29 +3,104 @@
3
3
  # found in the LICENSE file.
4
4
 
5
5
  import ast
6
+ import cStringIO
6
7
  import collections
8
+ import logging
9
+ import tokenize
10
+
11
+ import gclient_utils
7
12
 
8
13
  from third_party import schema
9
14
 
10
15
 
16
+ class _NodeDict(collections.MutableMapping):
17
+ """Dict-like type that also stores information on AST nodes and tokens."""
18
+ def __init__(self, data, tokens=None):
19
+ self.data = collections.OrderedDict(data)
20
+ self.tokens = tokens
21
+
22
+ def __str__(self):
23
+ return str({k: v[0] for k, v in self.data.iteritems()})
24
+
25
+ def __getitem__(self, key):
26
+ return self.data[key][0]
27
+
28
+ def __setitem__(self, key, value):
29
+ self.data[key] = (value, None)
30
+
31
+ def __delitem__(self, key):
32
+ del self.data[key]
33
+
34
+ def __iter__(self):
35
+ return iter(self.data)
36
+
37
+ def __len__(self):
38
+ return len(self.data)
39
+
40
+ def MoveTokens(self, origin, delta):
41
+ if self.tokens:
42
+ new_tokens = {}
43
+ for pos, token in self.tokens.iteritems():
44
+ if pos[0] >= origin:
45
+ pos = (pos[0] + delta, pos[1])
46
+ token = token[:2] + (pos,) + token[3:]
47
+ new_tokens[pos] = token
48
+
49
+ for value, node in self.data.values():
50
+ if node.lineno >= origin:
51
+ node.lineno += delta
52
+ if isinstance(value, _NodeDict):
53
+ value.MoveTokens(origin, delta)
54
+
55
+ def GetNode(self, key):
56
+ return self.data[key][1]
57
+
58
+ def SetNode(self, key, value, node):
59
+ self.data[key] = (value, node)
60
+
61
+
62
+ def _NodeDictSchema(dict_schema):
63
+ """Validate dict_schema after converting _NodeDict to a regular dict."""
64
+ def validate(d):
65
+ schema.Schema(dict_schema).validate(dict(d))
66
+ return True
67
+ return validate
68
+
69
+
11
70
  # See https://github.com/keleshev/schema for docs how to configure schema.
12
- _GCLIENT_DEPS_SCHEMA = {
71
+ _GCLIENT_DEPS_SCHEMA = _NodeDictSchema({
13
72
  schema.Optional(basestring): schema.Or(
14
73
  None,
15
74
  basestring,
16
- {
75
+ _NodeDictSchema({
17
76
  # Repo and revision to check out under the path
18
77
  # (same as if no dict was used).
19
- 'url': basestring,
78
+ 'url': schema.Or(None, basestring),
20
79
 
21
80
  # Optional condition string. The dep will only be processed
22
81
  # if the condition evaluates to True.
23
82
  schema.Optional('condition'): basestring,
24
- },
83
+
84
+ schema.Optional('dep_type', default='git'): basestring,
85
+ }),
86
+ # CIPD package.
87
+ _NodeDictSchema({
88
+ 'packages': [
89
+ _NodeDictSchema({
90
+ 'package': basestring,
91
+
92
+ 'version': basestring,
93
+ })
94
+ ],
95
+
96
+ schema.Optional('condition'): basestring,
97
+
98
+ schema.Optional('dep_type', default='cipd'): basestring,
99
+ }),
25
100
  ),
26
- }
101
+ })
27
102
 
28
- _GCLIENT_HOOKS_SCHEMA = [{
103
+ _GCLIENT_HOOKS_SCHEMA = [_NodeDictSchema({
29
104
  # Hook action: list of command-line arguments to invoke.
30
105
  'action': [basestring],
31
106
 
@@ -43,9 +118,9 @@ _GCLIENT_HOOKS_SCHEMA = [{
43
118
  # Optional condition string. The hook will only be run
44
119
  # if the condition evaluates to True.
45
120
  schema.Optional('condition'): basestring,
46
- }]
121
+ })]
47
122
 
48
- _GCLIENT_SCHEMA = schema.Schema({
123
+ _GCLIENT_SCHEMA = schema.Schema(_NodeDictSchema({
49
124
  # List of host names from which dependencies are allowed (whitelist).
50
125
  # NOTE: when not present, all hosts are allowed.
51
126
  # NOTE: scoped to current DEPS file, not recursive.
@@ -63,9 +138,14 @@ _GCLIENT_SCHEMA = schema.Schema({
63
138
 
64
139
  # Similar to 'deps' (see above) - also keyed by OS (e.g. 'linux').
65
140
  # Also see 'target_os'.
66
- schema.Optional('deps_os'): {
141
+ schema.Optional('deps_os'): _NodeDictSchema({
67
142
  schema.Optional(basestring): _GCLIENT_DEPS_SCHEMA,
68
- },
143
+ }),
144
+
145
+ # Dependency to get gclient_gn_args* settings from. This allows these values
146
+ # to be set in a recursedeps file, rather than requiring that they exist in
147
+ # the top-level solution.
148
+ schema.Optional('gclient_gn_args_from'): basestring,
69
149
 
70
150
  # Path to GN args file to write selected variables.
71
151
  schema.Optional('gclient_gn_args_file'): basestring,
@@ -79,9 +159,9 @@ _GCLIENT_SCHEMA = schema.Schema({
79
159
  schema.Optional('hooks'): _GCLIENT_HOOKS_SCHEMA,
80
160
 
81
161
  # Similar to 'hooks', also keyed by OS.
82
- schema.Optional('hooks_os'): {
162
+ schema.Optional('hooks_os'): _NodeDictSchema({
83
163
  schema.Optional(basestring): _GCLIENT_HOOKS_SCHEMA
84
- },
164
+ }),
85
165
 
86
166
  # Rules which #includes are allowed in the directory.
87
167
  # Also see 'skip_child_includes' and 'specific_include_rules'.
@@ -107,9 +187,9 @@ _GCLIENT_SCHEMA = schema.Schema({
107
187
 
108
188
  # Mapping from paths to include rules specific for that path.
109
189
  # See 'include_rules' for more details.
110
- schema.Optional('specific_include_rules'): {
190
+ schema.Optional('specific_include_rules'): _NodeDictSchema({
111
191
  schema.Optional(basestring): [basestring]
112
- },
192
+ }),
113
193
 
114
194
  # List of additional OS names to consider when selecting dependencies
115
195
  # from deps_os.
@@ -120,13 +200,13 @@ _GCLIENT_SCHEMA = schema.Schema({
120
200
  schema.Optional('use_relative_paths'): bool,
121
201
 
122
202
  # Variables that can be referenced using Var() - see 'deps'.
123
- schema.Optional('vars'): {
203
+ schema.Optional('vars'): _NodeDictSchema({
124
204
  schema.Optional(basestring): schema.Or(basestring, bool),
125
- },
126
- })
205
+ }),
206
+ }))
127
207
 
128
208
 
129
- def _gclient_eval(node_or_string, global_scope, filename='<unknown>'):
209
+ def _gclient_eval(node_or_string, filename='<unknown>', vars_dict=None):
130
210
  """Safely evaluates a single expression. Returns the result."""
131
211
  _allowed_names = {'None': None, 'True': True, 'False': False}
132
212
  if isinstance(node_or_string, basestring):
@@ -135,7 +215,15 @@ def _gclient_eval(node_or_string, global_scope, filename='<unknown>'):
135
215
  node_or_string = node_or_string.body
136
216
  def _convert(node):
137
217
  if isinstance(node, ast.Str):
138
- return node.s
218
+ if vars_dict is None:
219
+ return node.s
220
+ try:
221
+ return node.s.format(**vars_dict)
222
+ except KeyError as e:
223
+ raise KeyError(
224
+ '%s was used as a variable, but was not declared in the vars dict '
225
+ '(file %r, line %s)' % (
226
+ e.message, filename, getattr(node, 'lineno', '<unknown>')))
139
227
  elif isinstance(node, ast.Num):
140
228
  return node.n
141
229
  elif isinstance(node, ast.Tuple):
@@ -143,8 +231,7 @@ def _gclient_eval(node_or_string, global_scope, filename='<unknown>'):
143
231
  elif isinstance(node, ast.List):
144
232
  return list(map(_convert, node.elts))
145
233
  elif isinstance(node, ast.Dict):
146
- return collections.OrderedDict(
147
- (_convert(k), _convert(v))
234
+ return _NodeDict((_convert(k), (_convert(v), v))
148
235
  for k, v in zip(node.keys, node.values))
149
236
  elif isinstance(node, ast.Name):
150
237
  if node.id not in _allowed_names:
@@ -153,16 +240,27 @@ def _gclient_eval(node_or_string, global_scope, filename='<unknown>'):
153
240
  node.id, filename, getattr(node, 'lineno', '<unknown>')))
154
241
  return _allowed_names[node.id]
155
242
  elif isinstance(node, ast.Call):
156
- if not isinstance(node.func, ast.Name):
243
+ if not isinstance(node.func, ast.Name) or node.func.id != 'Var':
157
244
  raise ValueError(
158
- 'invalid call: func should be a name (file %r, line %s)' % (
245
+ 'Var is the only allowed function (file %r, line %s)' % (
159
246
  filename, getattr(node, 'lineno', '<unknown>')))
160
- if node.keywords or node.starargs or node.kwargs:
247
+ if node.keywords or node.starargs or node.kwargs or len(node.args) != 1:
161
248
  raise ValueError(
162
- 'invalid call: use only regular args (file %r, line %s)' % (
249
+ 'Var takes exactly one argument (file %r, line %s)' % (
163
250
  filename, getattr(node, 'lineno', '<unknown>')))
164
- args = map(_convert, node.args)
165
- return global_scope[node.func.id](*args)
251
+ arg = _convert(node.args[0])
252
+ if not isinstance(arg, basestring):
253
+ raise ValueError(
254
+ 'Var\'s argument must be a variable name (file %r, line %s)' % (
255
+ filename, getattr(node, 'lineno', '<unknown>')))
256
+ if vars_dict is None:
257
+ return '{' + arg + '}'
258
+ if arg not in vars_dict:
259
+ raise KeyError(
260
+ '%s was used as a variable, but was not declared in the vars dict '
261
+ '(file %r, line %s)' % (
262
+ arg, filename, getattr(node, 'lineno', '<unknown>')))
263
+ return vars_dict[arg]
166
264
  elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.Add):
167
265
  return _convert(node.left) + _convert(node.right)
168
266
  elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.Mod):
@@ -175,41 +273,35 @@ def _gclient_eval(node_or_string, global_scope, filename='<unknown>'):
175
273
  return _convert(node_or_string)
176
274
 
177
275
 
178
- def Exec(content, global_scope, local_scope, filename='<unknown>'):
179
- """Safely execs a set of assignments. Mutates |local_scope|."""
180
- node_or_string = ast.parse(content, filename=filename, mode='exec')
181
- if isinstance(node_or_string, ast.Expression):
182
- node_or_string = node_or_string.body
183
-
184
- def _visit_in_module(node):
185
- if isinstance(node, ast.Assign):
186
- if len(node.targets) != 1:
187
- raise ValueError(
188
- 'invalid assignment: use exactly one target (file %r, line %s)' % (
189
- filename, getattr(node, 'lineno', '<unknown>')))
190
- target = node.targets[0]
191
- if not isinstance(target, ast.Name):
192
- raise ValueError(
193
- 'invalid assignment: target should be a name (file %r, line %s)' % (
194
- filename, getattr(node, 'lineno', '<unknown>')))
195
- value = _gclient_eval(node.value, global_scope, filename=filename)
196
-
197
- if target.id in local_scope:
198
- raise ValueError(
199
- 'invalid assignment: overrides var %r (file %r, line %s)' % (
200
- target.id, filename, getattr(node, 'lineno', '<unknown>')))
201
-
202
- local_scope[target.id] = value
203
- else:
276
+ def Exec(content, filename='<unknown>', vars_override=None):
277
+ """Safely execs a set of assignments."""
278
+ def _validate_statement(node, local_scope):
279
+ if not isinstance(node, ast.Assign):
204
280
  raise ValueError(
205
281
  'unexpected AST node: %s %s (file %r, line %s)' % (
206
282
  node, ast.dump(node), filename,
207
283
  getattr(node, 'lineno', '<unknown>')))
208
284
 
209
- if isinstance(node_or_string, ast.Module):
210
- for stmt in node_or_string.body:
211
- _visit_in_module(stmt)
212
- else:
285
+ if len(node.targets) != 1:
286
+ raise ValueError(
287
+ 'invalid assignment: use exactly one target (file %r, line %s)' % (
288
+ filename, getattr(node, 'lineno', '<unknown>')))
289
+
290
+ target = node.targets[0]
291
+ if not isinstance(target, ast.Name):
292
+ raise ValueError(
293
+ 'invalid assignment: target should be a name (file %r, line %s)' % (
294
+ filename, getattr(node, 'lineno', '<unknown>')))
295
+ if target.id in local_scope:
296
+ raise ValueError(
297
+ 'invalid assignment: overrides var %r (file %r, line %s)' % (
298
+ target.id, filename, getattr(node, 'lineno', '<unknown>')))
299
+
300
+ node_or_string = ast.parse(content, filename=filename, mode='exec')
301
+ if isinstance(node_or_string, ast.Expression):
302
+ node_or_string = node_or_string.body
303
+
304
+ if not isinstance(node_or_string, ast.Module):
213
305
  raise ValueError(
214
306
  'unexpected AST node: %s %s (file %r, line %s)' % (
215
307
  node_or_string,
@@ -217,7 +309,191 @@ def Exec(content, global_scope, local_scope, filename='<unknown>'):
217
309
  filename,
218
310
  getattr(node_or_string, 'lineno', '<unknown>')))
219
311
 
220
- _GCLIENT_SCHEMA.validate(local_scope)
312
+ statements = {}
313
+ for statement in node_or_string.body:
314
+ _validate_statement(statement, statements)
315
+ statements[statement.targets[0].id] = statement.value
316
+
317
+ tokens = {
318
+ token[2]: list(token)
319
+ for token in tokenize.generate_tokens(
320
+ cStringIO.StringIO(content).readline)
321
+ }
322
+ local_scope = _NodeDict({}, tokens)
323
+
324
+ # Process vars first, so we can expand variables in the rest of the DEPS file.
325
+ vars_dict = {}
326
+ if 'vars' in statements:
327
+ vars_statement = statements['vars']
328
+ value = _gclient_eval(vars_statement, filename)
329
+ local_scope.SetNode('vars', value, vars_statement)
330
+ # Update the parsed vars with the overrides, but only if they are already
331
+ # present (overrides do not introduce new variables).
332
+ vars_dict.update(value)
333
+ if vars_override:
334
+ vars_dict.update({
335
+ k: v
336
+ for k, v in vars_override.iteritems()
337
+ if k in vars_dict})
338
+
339
+ for name, node in statements.iteritems():
340
+ value = _gclient_eval(node, filename, vars_dict)
341
+ local_scope.SetNode(name, value, node)
342
+
343
+ return _GCLIENT_SCHEMA.validate(local_scope)
344
+
345
+
346
+ def ExecLegacy(content, filename='<unknown>', vars_override=None):
347
+ """Executes a DEPS file |content| using exec."""
348
+ local_scope = {}
349
+ global_scope = {'Var': lambda var_name: '{%s}' % var_name}
350
+
351
+ # If we use 'exec' directly, it complains that 'Parse' contains a nested
352
+ # function with free variables.
353
+ # This is because on versions of Python < 2.7.9, "exec(a, b, c)" not the same
354
+ # as "exec a in b, c" (See https://bugs.python.org/issue21591).
355
+ eval(compile(content, filename, 'exec'), global_scope, local_scope)
356
+
357
+ if 'vars' not in local_scope:
358
+ return local_scope
359
+
360
+ vars_dict = {}
361
+ vars_dict.update(local_scope['vars'])
362
+ if vars_override:
363
+ vars_dict.update({
364
+ k: v
365
+ for k, v in vars_override.iteritems()
366
+ if k in vars_dict
367
+ })
368
+
369
+ def _DeepFormat(node):
370
+ if isinstance(node, basestring):
371
+ return node.format(**vars_dict)
372
+ elif isinstance(node, dict):
373
+ return {
374
+ k.format(**vars_dict): _DeepFormat(v)
375
+ for k, v in node.iteritems()
376
+ }
377
+ elif isinstance(node, list):
378
+ return [_DeepFormat(elem) for elem in node]
379
+ elif isinstance(node, tuple):
380
+ return tuple(_DeepFormat(elem) for elem in node)
381
+ else:
382
+ return node
383
+
384
+ return _DeepFormat(local_scope)
385
+
386
+
387
+ def _StandardizeDeps(deps_dict, vars_dict):
388
+ """"Standardizes the deps_dict.
389
+
390
+ For each dependency:
391
+ - Expands the variable in the dependency name.
392
+ - Ensures the dependency is a dictionary.
393
+ - Set's the 'dep_type' to be 'git' by default.
394
+ """
395
+ new_deps_dict = {}
396
+ for dep_name, dep_info in deps_dict.items():
397
+ dep_name = dep_name.format(**vars_dict)
398
+ if not isinstance(dep_info, collections.Mapping):
399
+ dep_info = {'url': dep_info}
400
+ dep_info.setdefault('dep_type', 'git')
401
+ new_deps_dict[dep_name] = dep_info
402
+ return new_deps_dict
403
+
404
+
405
+ def _MergeDepsOs(deps_dict, os_deps_dict, os_name):
406
+ """Merges the deps in os_deps_dict into conditional dependencies in deps_dict.
407
+
408
+ The dependencies in os_deps_dict are transformed into conditional dependencies
409
+ using |'checkout_' + os_name|.
410
+ If the dependency is already present, the URL and revision must coincide.
411
+ """
412
+ for dep_name, dep_info in os_deps_dict.items():
413
+ # Make this condition very visible, so it's not a silent failure.
414
+ # It's unclear how to support None override in deps_os.
415
+ if dep_info['url'] is None:
416
+ logging.error('Ignoring %r:%r in %r deps_os', dep_name, dep_info, os_name)
417
+ continue
418
+
419
+ os_condition = 'checkout_' + (os_name if os_name != 'unix' else 'linux')
420
+ UpdateCondition(dep_info, 'and', os_condition)
421
+
422
+ if dep_name in deps_dict:
423
+ if deps_dict[dep_name]['url'] != dep_info['url']:
424
+ raise gclient_utils.Error(
425
+ 'Value from deps_os (%r; %r: %r) conflicts with existing deps '
426
+ 'entry (%r).' % (
427
+ os_name, dep_name, dep_info, deps_dict[dep_name]))
428
+
429
+ UpdateCondition(dep_info, 'or', deps_dict[dep_name].get('condition'))
430
+
431
+ deps_dict[dep_name] = dep_info
432
+
433
+
434
+ def UpdateCondition(info_dict, op, new_condition):
435
+ """Updates info_dict's condition with |new_condition|.
436
+
437
+ An absent value is treated as implicitly True.
438
+ """
439
+ curr_condition = info_dict.get('condition')
440
+ # Easy case: Both are present.
441
+ if curr_condition and new_condition:
442
+ info_dict['condition'] = '(%s) %s (%s)' % (
443
+ curr_condition, op, new_condition)
444
+ # If |op| == 'and', and at least one condition is present, then use it.
445
+ elif op == 'and' and (curr_condition or new_condition):
446
+ info_dict['condition'] = curr_condition or new_condition
447
+ # Otherwise, no condition should be set
448
+ elif curr_condition:
449
+ del info_dict['condition']
450
+
451
+
452
+ def Parse(content, validate_syntax, filename, vars_override=None):
453
+ """Parses DEPS strings.
454
+
455
+ Executes the Python-like string stored in content, resulting in a Python
456
+ dictionary specifyied by the schema above. Supports syntax validation and
457
+ variable expansion.
458
+
459
+ Args:
460
+ content: str. DEPS file stored as a string.
461
+ validate_syntax: bool. Whether syntax should be validated using the schema
462
+ defined above.
463
+ filename: str. The name of the DEPS file, or a string describing the source
464
+ of the content, e.g. '<string>', '<unknown>'.
465
+ vars_override: dict, optional. A dictionary with overrides for the variables
466
+ defined by the DEPS file.
467
+
468
+ Returns:
469
+ A Python dict with the parsed contents of the DEPS file, as specified by the
470
+ schema above.
471
+ """
472
+ if validate_syntax:
473
+ result = Exec(content, filename, vars_override)
474
+ else:
475
+ result = ExecLegacy(content, filename, vars_override)
476
+
477
+ vars_dict = result.get('vars', {})
478
+ if 'deps' in result:
479
+ result['deps'] = _StandardizeDeps(result['deps'], vars_dict)
480
+
481
+ if 'deps_os' in result:
482
+ deps = result.setdefault('deps', {})
483
+ for os_name, os_deps in result['deps_os'].iteritems():
484
+ os_deps = _StandardizeDeps(os_deps, vars_dict)
485
+ _MergeDepsOs(deps, os_deps, os_name)
486
+ del result['deps_os']
487
+
488
+ if 'hooks_os' in result:
489
+ hooks = result.setdefault('hooks', [])
490
+ for os_name, os_hooks in result['hooks_os'].iteritems():
491
+ for hook in os_hooks:
492
+ UpdateCondition(hook, 'and', 'checkout_' + os_name)
493
+ hooks.extend(os_hooks)
494
+ del result['hooks_os']
495
+
496
+ return result
221
497
 
222
498
 
223
499
  def EvaluateCondition(condition, variables, referenced_variables=None):
@@ -317,3 +593,238 @@ def EvaluateCondition(condition, variables, referenced_variables=None):
317
593
  'unexpected AST node: %s %s (inside %r)' % (
318
594
  node, ast.dump(node), condition))
319
595
  return _convert(main_node)
596
+
597
+
598
+ def RenderDEPSFile(gclient_dict):
599
+ contents = sorted(gclient_dict.tokens.values(), key=lambda token: token[2])
600
+ return tokenize.untokenize(contents)
601
+
602
+
603
+ def _UpdateAstString(tokens, node, value):
604
+ position = node.lineno, node.col_offset
605
+ quote_char = tokens[position][1][0]
606
+ tokens[position][1] = quote_char + value + quote_char
607
+ node.s = value
608
+
609
+
610
+ def _ShiftLinesInTokens(tokens, delta, start):
611
+ new_tokens = {}
612
+ for token in tokens.values():
613
+ if token[2][0] >= start:
614
+ token[2] = token[2][0] + delta, token[2][1]
615
+ token[3] = token[3][0] + delta, token[3][1]
616
+ new_tokens[token[2]] = token
617
+ return new_tokens
618
+
619
+
620
+ def AddVar(gclient_dict, var_name, value):
621
+ if not isinstance(gclient_dict, _NodeDict) or gclient_dict.tokens is None:
622
+ raise ValueError(
623
+ "Can't use SetVar for the given gclient dict. It contains no "
624
+ "formatting information.")
625
+
626
+ if 'vars' not in gclient_dict:
627
+ raise KeyError("vars dict is not defined.")
628
+
629
+ if var_name in gclient_dict['vars']:
630
+ raise ValueError(
631
+ "%s has already been declared in the vars dict. Consider using SetVar "
632
+ "instead." % var_name)
633
+
634
+ if not gclient_dict['vars']:
635
+ raise ValueError('vars dict is empty. This is not yet supported.')
636
+
637
+ # We will attempt to add the var right after 'vars = {'.
638
+ node = gclient_dict.GetNode('vars')
639
+ if node is None:
640
+ raise ValueError(
641
+ "The vars dict has no formatting information." % var_name)
642
+ line = node.lineno + 1
643
+
644
+ # We will try to match the new var's indentation to the next variable.
645
+ col = node.keys[0].col_offset
646
+
647
+ # We use a minimal Python dictionary, so that ast can parse it.
648
+ var_content = '{\n%s"%s": "%s",\n}' % (' ' * col, var_name, value)
649
+ var_ast = ast.parse(var_content).body[0].value
650
+
651
+ # Set the ast nodes for the key and value.
652
+ vars_node = gclient_dict.GetNode('vars')
653
+
654
+ var_name_node = var_ast.keys[0]
655
+ var_name_node.lineno += line - 2
656
+ vars_node.keys.insert(0, var_name_node)
657
+
658
+ value_node = var_ast.values[0]
659
+ value_node.lineno += line - 2
660
+ vars_node.values.insert(0, value_node)
661
+
662
+ # Update the tokens.
663
+ var_tokens = list(tokenize.generate_tokens(
664
+ cStringIO.StringIO(var_content).readline))
665
+ var_tokens = {
666
+ token[2]: list(token)
667
+ # Ignore the tokens corresponding to braces and new lines.
668
+ for token in var_tokens[2:-2]
669
+ }
670
+
671
+ gclient_dict.tokens = _ShiftLinesInTokens(gclient_dict.tokens, 1, line)
672
+ gclient_dict.tokens.update(_ShiftLinesInTokens(var_tokens, line - 2, 0))
673
+
674
+
675
+ def SetVar(gclient_dict, var_name, value):
676
+ if not isinstance(gclient_dict, _NodeDict) or gclient_dict.tokens is None:
677
+ raise ValueError(
678
+ "Can't use SetVar for the given gclient dict. It contains no "
679
+ "formatting information.")
680
+ tokens = gclient_dict.tokens
681
+
682
+ if 'vars' not in gclient_dict:
683
+ raise KeyError("vars dict is not defined.")
684
+
685
+ if var_name not in gclient_dict['vars']:
686
+ raise ValueError(
687
+ "%s has not been declared in the vars dict. Consider using AddVar "
688
+ "instead." % var_name)
689
+
690
+ node = gclient_dict['vars'].GetNode(var_name)
691
+ if node is None:
692
+ raise ValueError(
693
+ "The vars entry for %s has no formatting information." % var_name)
694
+
695
+ _UpdateAstString(tokens, node, value)
696
+ gclient_dict['vars'].SetNode(var_name, value, node)
697
+
698
+
699
+ def SetCIPD(gclient_dict, dep_name, package_name, new_version):
700
+ if not isinstance(gclient_dict, _NodeDict) or gclient_dict.tokens is None:
701
+ raise ValueError(
702
+ "Can't use SetCIPD for the given gclient dict. It contains no "
703
+ "formatting information.")
704
+ tokens = gclient_dict.tokens
705
+
706
+ if 'deps' not in gclient_dict or dep_name not in gclient_dict['deps']:
707
+ raise KeyError(
708
+ "Could not find any dependency called %s." % dep_name)
709
+
710
+ # Find the package with the given name
711
+ packages = [
712
+ package
713
+ for package in gclient_dict['deps'][dep_name]['packages']
714
+ if package['package'] == package_name
715
+ ]
716
+ if len(packages) != 1:
717
+ raise ValueError(
718
+ "There must be exactly one package with the given name (%s), "
719
+ "%s were found." % (package_name, len(packages)))
720
+
721
+ # TODO(ehmaldonado): Support Var in package's version.
722
+ node = packages[0].GetNode('version')
723
+ if node is None:
724
+ raise ValueError(
725
+ "The deps entry for %s:%s has no formatting information." %
726
+ (dep_name, package_name))
727
+
728
+ new_version = 'version:' + new_version
729
+ _UpdateAstString(tokens, node, new_version)
730
+ packages[0].SetNode('version', new_version, node)
731
+
732
+
733
+ def SetRevision(gclient_dict, dep_name, new_revision):
734
+ def _GetVarName(node):
735
+ if isinstance(node, ast.Call):
736
+ return node.args[0].s
737
+ elif node.s.endswith('}'):
738
+ last_brace = node.s.rfind('{')
739
+ return node.s[last_brace+1:-1]
740
+ return None
741
+
742
+ def _UpdateRevision(dep_dict, dep_key, new_revision):
743
+ dep_node = dep_dict.GetNode(dep_key)
744
+ if dep_node is None:
745
+ raise ValueError(
746
+ "The deps entry for %s has no formatting information." % dep_name)
747
+
748
+ node = dep_node
749
+ if isinstance(node, ast.BinOp):
750
+ node = node.right
751
+
752
+ if not isinstance(node, ast.Call) and not isinstance(node, ast.Str):
753
+ raise ValueError(
754
+ "Unsupported dependency revision format. Please file a bug.")
755
+
756
+ var_name = _GetVarName(node)
757
+ if var_name is not None:
758
+ SetVar(gclient_dict, var_name, new_revision)
759
+ else:
760
+ if '@' in node.s:
761
+ # '@' is part of the last string, which we want to modify. Discard
762
+ # whatever was after the '@' and put the new revision in its place.
763
+ new_revision = node.s.split('@')[0] + '@' + new_revision
764
+ elif '@' not in dep_dict[dep_key]:
765
+ # '@' is not part of the URL at all. This mean the dependency is
766
+ # unpinned and we should pin it.
767
+ new_revision = node.s + '@' + new_revision
768
+ _UpdateAstString(tokens, node, new_revision)
769
+ dep_dict.SetNode(dep_key, new_revision, node)
770
+
771
+ if not isinstance(gclient_dict, _NodeDict) or gclient_dict.tokens is None:
772
+ raise ValueError(
773
+ "Can't use SetRevision for the given gclient dict. It contains no "
774
+ "formatting information.")
775
+ tokens = gclient_dict.tokens
776
+
777
+ if 'deps' not in gclient_dict or dep_name not in gclient_dict['deps']:
778
+ raise KeyError(
779
+ "Could not find any dependency called %s." % dep_name)
780
+
781
+ if isinstance(gclient_dict['deps'][dep_name], _NodeDict):
782
+ _UpdateRevision(gclient_dict['deps'][dep_name], 'url', new_revision)
783
+ else:
784
+ _UpdateRevision(gclient_dict['deps'], dep_name, new_revision)
785
+
786
+
787
+ def GetVar(gclient_dict, var_name):
788
+ if 'vars' not in gclient_dict or var_name not in gclient_dict['vars']:
789
+ raise KeyError(
790
+ "Could not find any variable called %s." % var_name)
791
+
792
+ return gclient_dict['vars'][var_name]
793
+
794
+
795
+ def GetCIPD(gclient_dict, dep_name, package_name):
796
+ if 'deps' not in gclient_dict or dep_name not in gclient_dict['deps']:
797
+ raise KeyError(
798
+ "Could not find any dependency called %s." % dep_name)
799
+
800
+ # Find the package with the given name
801
+ packages = [
802
+ package
803
+ for package in gclient_dict['deps'][dep_name]['packages']
804
+ if package['package'] == package_name
805
+ ]
806
+ if len(packages) != 1:
807
+ raise ValueError(
808
+ "There must be exactly one package with the given name (%s), "
809
+ "%s were found." % (package_name, len(packages)))
810
+
811
+ return packages[0]['version'][len('version:'):]
812
+
813
+
814
+ def GetRevision(gclient_dict, dep_name):
815
+ if 'deps' not in gclient_dict or dep_name not in gclient_dict['deps']:
816
+ raise KeyError(
817
+ "Could not find any dependency called %s." % dep_name)
818
+
819
+ dep = gclient_dict['deps'][dep_name]
820
+ if dep is None:
821
+ return None
822
+ elif isinstance(dep, basestring):
823
+ _, _, revision = dep.partition('@')
824
+ return revision or None
825
+ elif isinstance(dep, collections.Mapping) and 'url' in dep:
826
+ _, _, revision = dep['url'].partition('@')
827
+ return revision or None
828
+ else:
829
+ raise ValueError(
830
+ '%s is not a valid git dependency.' % dep_name)