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

Side by Side Diff: third_party/recipe_engine/recipes.py

Issue 1241323004: Cross-repo recipe package system. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/build
Patch Set: Created 5 years, 4 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
OLDNEW
(Empty)
1 #!/usr/bin/env python
2
3 import argparse
4 import json
5 import logging
6 import os
7 import subprocess
8 import sys
9
10 sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
11
12
13 def get_package_pyl(args):
14 if args.package:
15 cand = os.path.realpath(os.path.join(os.getcwd(), args.package,
16 'recipe_package.pyl'))
17 if os.path.exists(cand):
18 return cand
19 else:
20 raise EnvironmentError(
21 'Specified package %s does not exist' % cand)
22
23 cwd = os.path.realpath(os.getcwd())
24 while os.path.dirname(cwd) != cwd:
25 cand = os.path.join(cwd, 'recipe_package.pyl')
26 if os.path.exists(cand):
27 return cand
28
29 if not os.path.isdir(os.path.join(cwd, '.git')):
30 cwd = os.path.dirname(cwd)
31 else:
32 raise EnvironmentError(
33 'Will not cross git repository boundary %s when looking for '
34 'recipe_package.pyl' % cwd)
35 else:
36 raise EnvironmentError(
37 'Reached root of filesystem when looking for recipe_package.pyl')
38
39 def simulation_test(package, args):
40 from recipe_engine import simulation_test
41 simulation_test.main(package, args=args.args)
42
43
44 def lint(package, args):
45 from recipe_engine import lint_test
46 lint_test.main(package)
47
48
49 def run(package, args):
50 from recipe_engine import main as recipe_main
51 from recipe_engine import loader
52 from recipe_engine import package
53 from recipe_engine.third_party import annotator
54
55 def get_properties_from_args(args):
56 properties = dict(x.split('=', 1) for x in args)
57 for key, val in properties.iteritems():
58 try:
59 properties[key] = ast.literal_eval(val)
60 except (ValueError, SyntaxError):
61 pass # If a value couldn't be evaluated, keep the string version
62 return properties
63
64 def get_properties_from_file(filename):
65 properties_file = sys.stdin if filename == '-' else open(filename)
66 properties = ast.literal_eval(properties_file.read())
67 assert isinstance(properties, dict)
68
69 arg_properties = get_properties_from_args(args.properties)
70 if args.properties_file and arg_properties:
71 raise Exception(
72 'Cannot specify both properties file and command-line properties')
73 elif args.properties_file:
74 properties = get_properties_from_file(args.properties_file)
75 else:
76 properties = arg_properties
77
78 properties['recipe'] = args.recipe
79
80 # TODO(luqui): Environment whitelist. Cf crbug.com/392992
81 os.environ['PYTHONUNBUFFERED'] = '1'
82 os.environ['PYTHONIOENCODING'] = 'UTF-8'
83
84 universe = loader.RecipeUniverse(package)
85
86 workdir = (args.workdir or
87 os.path.join(os.path.dirname(os.path.realpath(__file__)), 'workdir'))
88 logging.info('Using %s as work directory' % workdir)
89 if not os.path.exists(workdir):
90 os.makedirs(workdir)
91
92 old_cwd = os.getcwd()
93 os.chdir(workdir)
94 try:
95 ret = recipe_main.run_steps(
96 properties, annotator.StructuredAnnotationStream(), universe=universe)
97 return ret.status_code
98 finally:
99 os.chdir(old_cwd)
100
101
102 def roll(args):
103 from recipe_engine import package
104 pyl_path = get_package_pyl(args)
105 context = package.PackageContext.from_pyl_path(pyl_path)
106 package_spec = package.PackageSpec.load_pyl(pyl_path)
107 package_spec_dump = package_spec.dump()
108
109 for date, spec in package_spec.iterate_consistent_updates(context):
110 with open(pyl_path, 'w') as fh:
111 json.dump(spec.dump(), fh, indent=2, separators=(',', ': '))
112 print 'Wrote %s' % pyl_path
113
114 updated_deps = {
115 dep_id: dep['revision']
116 for dep_id, dep in spec.dump()['deps'].iteritems()
117 if dep['revision'] != package_spec_dump['deps'][dep_id]['revision']
118 }
119 print 'To commit this roll, run:'
120 print ' '.join([
121 'git commit -a --date "%s" -m "Roll dependencies"' % date.isoformat(),
122 ' '.join([ '-m "Roll %s to %s"' % (dep_id, rev)
123 for dep_id, rev in sorted(updated_deps.iteritems())]),
124 ])
125
126 break
127 else:
128 print 'No consistent rolls found'
129
130
131 def main():
132 from recipe_engine import package
133
134 parser = argparse.ArgumentParser(description='Do things with recipes.')
135
136 parser.add_argument(
137 '--package',
138 help='Package to operate on (directory containing recipe_package.pyl)')
139 parser.add_argument(
140 '--verbose', '-v', action='store_true',
141 help='Increase logging verboisty')
142 parser.add_argument(
143 '--bootstrap', action='store_true',
144 help='Use current rather than pinned version of recipe engine')
145
146 subp = parser.add_subparsers()
147
148 simulation_test_p = subp.add_parser('simulation_test',
149 help='Generate or check expectations by simulating with mock actions')
150 simulation_test_p.set_defaults(command='simulation_test')
151 simulation_test_p.add_argument('args', nargs=argparse.REMAINDER)
152
153 lint_p = subp.add_parser(
154 'lint',
155 help='Check recipes for stylistic and hygenic issues')
156 lint_p.set_defaults(command='lint')
157
158 run_p = subp.add_parser(
159 'run',
160 help='Run a recipe locally')
161 run_p.set_defaults(command='run')
162 run_p.add_argument(
163 '--properties-file',
164 help='A file containing a json blob of properties')
165 run_p.add_argument(
166 '--workdir',
167 help='The working directory of recipe execution')
168 run_p.add_argument(
169 'recipe',
170 help='The recipe to execute')
171 run_p.add_argument(
172 'properties', nargs=argparse.REMAINDER,
173 help='A list of property pairs; e.g. mastername=chromium.linux '
174 'issue=12345')
175
176 roll_p = subp.add_parser(
177 'roll',
178 help='Roll dependencies of a recipe package forward')
179 roll_p.set_defaults(command='roll')
180
181 args = parser.parse_args()
182 if args.verbose:
183 logging.getLogger().setLevel(logging.INFO)
184
185 package_deps = package.PackageDeps.create(get_package_pyl(args))
186 # We don't forward to pinned tool on rolling, because there might be new
187 # things to know about since then, who knows? Easier to look backward than
188 # forward.
189 if not args.bootstrap and args.command != 'roll':
190 tool = os.path.join(
191 package_deps.get_package('recipe_engine').root_dir, 'recipes.py')
192 cmd = [ sys.executable, '-u', tool, '--bootstrap' ] + sys.argv[1:]
193 logging.info(cmd)
194 return subprocess.call(cmd)
195
196 if args.command == 'simulation_test':
197 return simulation_test(package_deps, args)
198 elif args.command == 'lint':
199 return lint(package_deps, args)
200 elif args.command == 'run':
201 return run(package_deps, args)
202 elif args.command == 'roll':
203 return roll(args)
204 else:
205 print """Dear sir or madam,
206 It has come to my attention that a quite impossible condition has come
207 to pass in the specification you have issued a request for us to fulfill.
208 It is with a heavy heart that I inform you that, at the present juncture,
209 there is no conceivable next action to be taken upon your request, and as
210 such, we have decided to abort the request with a nonzero status code. We
211 hope that your larger goals have not been put at risk due to this
212 unfortunate circumstance, and wish you the best in deciding the next action
213 in your venture and larger life.
214
215 Warmly,
216 recipes.py
217 """
218 return 1
219
220 return 0
221
222 if __name__ == '__main__':
223 sys.exit(main())
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698