Mercurial > bitten > bitten-test
annotate bitten/recipe.py @ 630:042c8b49ce7f
0.6dev: Follow-up to [702] - flawed logic in argument testing.
author | osimons |
---|---|
date | Tue, 11 Aug 2009 23:20:13 +0000 |
parents | f3bb52da9e3c |
children | 075087a17f06 |
rev | line source |
---|---|
379 | 1 # -*- coding: utf-8 -*- |
21 | 2 # |
408
933105ab516b
Update file headers and other stuff pointing to the old home.
cmlenz
parents:
392
diff
changeset
|
3 # Copyright (C) 2007 Edgewall Software |
933105ab516b
Update file headers and other stuff pointing to the old home.
cmlenz
parents:
392
diff
changeset
|
4 # Copyright (C) 2005-2007 Christopher Lenz <cmlenz@gmx.de> |
163 | 5 # All rights reserved. |
21 | 6 # |
163 | 7 # This software is licensed as described in the file COPYING, which |
8 # you should have received as part of this distribution. The terms | |
408
933105ab516b
Update file headers and other stuff pointing to the old home.
cmlenz
parents:
392
diff
changeset
|
9 # are also available at http://bitten.edgewall.org/wiki/License. |
21 | 10 |
313 | 11 """Execution of build recipes. |
12 | |
13 This module provides various classes that can be used to process build recipes, | |
411
a169d2e96463
Use reStructuredText as the API documentation syntax.
cmlenz
parents:
408
diff
changeset
|
14 most importantly the `Recipe` class. |
313 | 15 """ |
16 | |
628
05686657e989
0.6dev: Implement a `subprocess` implementation of `execute()` that is now the default for all slaves where this is available - essentially all slaves with Python 2.4 and higher, or where module is installed separately. This fixes:
osimons
parents:
611
diff
changeset
|
17 import inspect |
146
affd91b4c6fb
Add a `<python:exec>` recipe command so that things like Pylint can be executed without using a Makefile.
cmlenz
parents:
144
diff
changeset
|
18 import keyword |
72
b2d371dac270
Allow individual steps of a recipe to be marked as optional, i.e. that an error in such a step should not mean that the build failed.
cmlenz
parents:
68
diff
changeset
|
19 import logging |
129
efd3df0de93a
Canonicalize path names so that comparison works. Fixes #37.
cmlenz
parents:
109
diff
changeset
|
20 import os |
628
05686657e989
0.6dev: Implement a `subprocess` implementation of `execute()` that is now the default for all slaves where this is available - essentially all slaves with Python 2.4 and higher, or where module is installed separately. This fixes:
osimons
parents:
611
diff
changeset
|
21 import time |
247
b28285d3ceec
Add validation for build configurations, and in particular for build recipes. Closes #48.
cmlenz
parents:
238
diff
changeset
|
22 try: |
b28285d3ceec
Add validation for build configurations, and in particular for build recipes. Closes #48.
cmlenz
parents:
238
diff
changeset
|
23 set |
b28285d3ceec
Add validation for build configurations, and in particular for build recipes. Closes #48.
cmlenz
parents:
238
diff
changeset
|
24 except NameError: |
b28285d3ceec
Add validation for build configurations, and in particular for build recipes. Closes #48.
cmlenz
parents:
238
diff
changeset
|
25 from sets import Set as set |
21 | 26 |
213
25f84dd9f159
* Refactoring of build recipes, the file format has changed slightly:
cmlenz
parents:
203
diff
changeset
|
27 from pkg_resources import WorkingSet |
72
b2d371dac270
Allow individual steps of a recipe to be marked as optional, i.e. that an error in such a step should not mean that the build failed.
cmlenz
parents:
68
diff
changeset
|
28 from bitten.build import BuildError |
238
832e64330c31
Add a `<c:configure>` recipe command for running configure scripts. Closes #57.
cmlenz
parents:
233
diff
changeset
|
29 from bitten.build.config import Configuration |
51
5caccd7b247e
Proper archive format negotiation; improved representation of parsed XML content in {{{bitten.util.xmlio}}}.
cmlenz
parents:
21
diff
changeset
|
30 from bitten.util import xmlio |
21 | 31 |
411
a169d2e96463
Use reStructuredText as the API documentation syntax.
cmlenz
parents:
408
diff
changeset
|
32 __all__ = ['Context', 'Recipe', 'Step', 'InvalidRecipeError'] |
a169d2e96463
Use reStructuredText as the API documentation syntax.
cmlenz
parents:
408
diff
changeset
|
33 __docformat__ = 'restructuredtext en' |
21 | 34 |
93
b289e572bc7e
Improved logging; the build master can now optionally log to a file. Closes #13.
cmlenz
parents:
80
diff
changeset
|
35 log = logging.getLogger('bitten.recipe') |
b289e572bc7e
Improved logging; the build master can now optionally log to a file. Closes #13.
cmlenz
parents:
80
diff
changeset
|
36 |
21 | 37 |
60
055a6c666fa8
* Pass a {{{Context}}} object to recipe commands as the first argument. Currently this only has the basedir, but will be extended to also provide output recording etc.
cmlenz
parents:
55
diff
changeset
|
38 class InvalidRecipeError(Exception): |
313 | 39 """Exception raised when a recipe is not valid.""" |
60
055a6c666fa8
* Pass a {{{Context}}} object to recipe commands as the first argument. Currently this only has the basedir, but will be extended to also provide output recording etc.
cmlenz
parents:
55
diff
changeset
|
40 |
055a6c666fa8
* Pass a {{{Context}}} object to recipe commands as the first argument. Currently this only has the basedir, but will be extended to also provide output recording etc.
cmlenz
parents:
55
diff
changeset
|
41 |
055a6c666fa8
* Pass a {{{Context}}} object to recipe commands as the first argument. Currently this only has the basedir, but will be extended to also provide output recording etc.
cmlenz
parents:
55
diff
changeset
|
42 class Context(object): |
313 | 43 """The context in which a build is executed.""" |
60
055a6c666fa8
* Pass a {{{Context}}} object to recipe commands as the first argument. Currently this only has the basedir, but will be extended to also provide output recording etc.
cmlenz
parents:
55
diff
changeset
|
44 |
213
25f84dd9f159
* Refactoring of build recipes, the file format has changed slightly:
cmlenz
parents:
203
diff
changeset
|
45 step = None # The current step |
25f84dd9f159
* Refactoring of build recipes, the file format has changed slightly:
cmlenz
parents:
203
diff
changeset
|
46 generator = None # The current generator (namespace#name) |
80
dc1c7fc9b915
Record the output of build steps in the database. See #12. Still need to get better granularity in transmitting the log output from slave to master before #12 can be closed.
cmlenz
parents:
72
diff
changeset
|
47 |
392 | 48 def __init__(self, basedir, config=None, vars=None): |
313 | 49 """Initialize the context. |
50 | |
466
79be3c00ae69
Applied patch to #188 for stable/configurable names of build directories. Thanks to Allen Bierbaum for the patch.
cmlenz
parents:
411
diff
changeset
|
51 :param basedir: a string containing the working directory for the build. |
79be3c00ae69
Applied patch to #188 for stable/configurable names of build directories. Thanks to Allen Bierbaum for the patch.
cmlenz
parents:
411
diff
changeset
|
52 (may be a pattern for replacement ex: 'build_${build}' |
411
a169d2e96463
Use reStructuredText as the API documentation syntax.
cmlenz
parents:
408
diff
changeset
|
53 :param config: the build slave configuration |
a169d2e96463
Use reStructuredText as the API documentation syntax.
cmlenz
parents:
408
diff
changeset
|
54 :type config: `Configuration` |
466
79be3c00ae69
Applied patch to #188 for stable/configurable names of build directories. Thanks to Allen Bierbaum for the patch.
cmlenz
parents:
411
diff
changeset
|
55 """ |
238
832e64330c31
Add a `<c:configure>` recipe command for running configure scripts. Closes #57.
cmlenz
parents:
233
diff
changeset
|
56 self.config = config or Configuration() |
392 | 57 self.vars = vars or {} |
109
5bf22bb87915
Transmit build log and generated data back to the build master in XML format. Closes #23.
cmlenz
parents:
93
diff
changeset
|
58 self.output = [] |
466
79be3c00ae69
Applied patch to #188 for stable/configurable names of build directories. Thanks to Allen Bierbaum for the patch.
cmlenz
parents:
411
diff
changeset
|
59 self.basedir = os.path.realpath(self.config.interpolate(basedir, |
79be3c00ae69
Applied patch to #188 for stable/configurable names of build directories. Thanks to Allen Bierbaum for the patch.
cmlenz
parents:
411
diff
changeset
|
60 **self.vars)) |
611
294641e84e89
0.6dev: Adding `${name}` and `${basedir}` (#325) for recipe substitution. Updated docs + new test.
osimons
parents:
466
diff
changeset
|
61 self.vars['basedir'] = self.basedir |
80
dc1c7fc9b915
Record the output of build steps in the database. See #12. Still need to get better granularity in transmitting the log output from slave to master before #12 can be closed.
cmlenz
parents:
72
diff
changeset
|
62 |
213
25f84dd9f159
* Refactoring of build recipes, the file format has changed slightly:
cmlenz
parents:
203
diff
changeset
|
63 def run(self, step, namespace, name, attr): |
313 | 64 """Run the specified recipe command. |
65 | |
411
a169d2e96463
Use reStructuredText as the API documentation syntax.
cmlenz
parents:
408
diff
changeset
|
66 :param step: the build step that the command belongs to |
a169d2e96463
Use reStructuredText as the API documentation syntax.
cmlenz
parents:
408
diff
changeset
|
67 :param namespace: the namespace URI of the command |
a169d2e96463
Use reStructuredText as the API documentation syntax.
cmlenz
parents:
408
diff
changeset
|
68 :param name: the local tag name of the command |
a169d2e96463
Use reStructuredText as the API documentation syntax.
cmlenz
parents:
408
diff
changeset
|
69 :param attr: a dictionary containing the attributes defined on the |
a169d2e96463
Use reStructuredText as the API documentation syntax.
cmlenz
parents:
408
diff
changeset
|
70 command element |
313 | 71 """ |
265
3dd311b4ad27
Add a generic `<report>` recipe command, which can be used to send any XML file to the master as a categorized report. This can be used in combination with `<sh:pipe>` or `<x:transform>` to produce reports not specifically generated by a specialized recipe command.
cmlenz
parents:
247
diff
changeset
|
72 self.step = step |
213
25f84dd9f159
* Refactoring of build recipes, the file format has changed slightly:
cmlenz
parents:
203
diff
changeset
|
73 |
265
3dd311b4ad27
Add a generic `<report>` recipe command, which can be used to send any XML file to the master as a categorized report. This can be used in combination with `<sh:pipe>` or `<x:transform>` to produce reports not specifically generated by a specialized recipe command.
cmlenz
parents:
247
diff
changeset
|
74 try: |
3dd311b4ad27
Add a generic `<report>` recipe command, which can be used to send any XML file to the master as a categorized report. This can be used in combination with `<sh:pipe>` or `<x:transform>` to produce reports not specifically generated by a specialized recipe command.
cmlenz
parents:
247
diff
changeset
|
75 function = None |
3dd311b4ad27
Add a generic `<report>` recipe command, which can be used to send any XML file to the master as a categorized report. This can be used in combination with `<sh:pipe>` or `<x:transform>` to produce reports not specifically generated by a specialized recipe command.
cmlenz
parents:
247
diff
changeset
|
76 qname = '#'.join(filter(None, [namespace, name])) |
3dd311b4ad27
Add a generic `<report>` recipe command, which can be used to send any XML file to the master as a categorized report. This can be used in combination with `<sh:pipe>` or `<x:transform>` to produce reports not specifically generated by a specialized recipe command.
cmlenz
parents:
247
diff
changeset
|
77 if namespace: |
3dd311b4ad27
Add a generic `<report>` recipe command, which can be used to send any XML file to the master as a categorized report. This can be used in combination with `<sh:pipe>` or `<x:transform>` to produce reports not specifically generated by a specialized recipe command.
cmlenz
parents:
247
diff
changeset
|
78 group = 'bitten.recipe_commands' |
3dd311b4ad27
Add a generic `<report>` recipe command, which can be used to send any XML file to the master as a categorized report. This can be used in combination with `<sh:pipe>` or `<x:transform>` to produce reports not specifically generated by a specialized recipe command.
cmlenz
parents:
247
diff
changeset
|
79 for entry_point in WorkingSet().iter_entry_points(group, qname): |
3dd311b4ad27
Add a generic `<report>` recipe command, which can be used to send any XML file to the master as a categorized report. This can be used in combination with `<sh:pipe>` or `<x:transform>` to produce reports not specifically generated by a specialized recipe command.
cmlenz
parents:
247
diff
changeset
|
80 function = entry_point.load() |
3dd311b4ad27
Add a generic `<report>` recipe command, which can be used to send any XML file to the master as a categorized report. This can be used in combination with `<sh:pipe>` or `<x:transform>` to produce reports not specifically generated by a specialized recipe command.
cmlenz
parents:
247
diff
changeset
|
81 break |
3dd311b4ad27
Add a generic `<report>` recipe command, which can be used to send any XML file to the master as a categorized report. This can be used in combination with `<sh:pipe>` or `<x:transform>` to produce reports not specifically generated by a specialized recipe command.
cmlenz
parents:
247
diff
changeset
|
82 elif name == 'report': |
3dd311b4ad27
Add a generic `<report>` recipe command, which can be used to send any XML file to the master as a categorized report. This can be used in combination with `<sh:pipe>` or `<x:transform>` to produce reports not specifically generated by a specialized recipe command.
cmlenz
parents:
247
diff
changeset
|
83 function = Context.report_file |
629
f3bb52da9e3c
0.6dev: Adding support for attachments to configurations and build - full web implementation that mirrors what is available in Ticket and Wiki. Also added a new generic `<attach/>` command that enables attaching files to be part of a recipe and uploaded by slaves as part of build.
osimons
parents:
628
diff
changeset
|
84 elif name == 'attach': |
f3bb52da9e3c
0.6dev: Adding support for attachments to configurations and build - full web implementation that mirrors what is available in Ticket and Wiki. Also added a new generic `<attach/>` command that enables attaching files to be part of a recipe and uploaded by slaves as part of build.
osimons
parents:
628
diff
changeset
|
85 function = Context.attach |
265
3dd311b4ad27
Add a generic `<report>` recipe command, which can be used to send any XML file to the master as a categorized report. This can be used in combination with `<sh:pipe>` or `<x:transform>` to produce reports not specifically generated by a specialized recipe command.
cmlenz
parents:
247
diff
changeset
|
86 if not function: |
368 | 87 raise InvalidRecipeError('Unknown recipe command %s' % qname) |
213
25f84dd9f159
* Refactoring of build recipes, the file format has changed slightly:
cmlenz
parents:
203
diff
changeset
|
88 |
265
3dd311b4ad27
Add a generic `<report>` recipe command, which can be used to send any XML file to the master as a categorized report. This can be used in combination with `<sh:pipe>` or `<x:transform>` to produce reports not specifically generated by a specialized recipe command.
cmlenz
parents:
247
diff
changeset
|
89 def escape(name): |
3dd311b4ad27
Add a generic `<report>` recipe command, which can be used to send any XML file to the master as a categorized report. This can be used in combination with `<sh:pipe>` or `<x:transform>` to produce reports not specifically generated by a specialized recipe command.
cmlenz
parents:
247
diff
changeset
|
90 name = name.replace('-', '_') |
3dd311b4ad27
Add a generic `<report>` recipe command, which can be used to send any XML file to the master as a categorized report. This can be used in combination with `<sh:pipe>` or `<x:transform>` to produce reports not specifically generated by a specialized recipe command.
cmlenz
parents:
247
diff
changeset
|
91 if keyword.iskeyword(name) or name in __builtins__: |
3dd311b4ad27
Add a generic `<report>` recipe command, which can be used to send any XML file to the master as a categorized report. This can be used in combination with `<sh:pipe>` or `<x:transform>` to produce reports not specifically generated by a specialized recipe command.
cmlenz
parents:
247
diff
changeset
|
92 name = name + '_' |
3dd311b4ad27
Add a generic `<report>` recipe command, which can be used to send any XML file to the master as a categorized report. This can be used in combination with `<sh:pipe>` or `<x:transform>` to produce reports not specifically generated by a specialized recipe command.
cmlenz
parents:
247
diff
changeset
|
93 return name |
392 | 94 args = dict([(escape(name), |
95 self.config.interpolate(attr[name], **self.vars)) | |
265
3dd311b4ad27
Add a generic `<report>` recipe command, which can be used to send any XML file to the master as a categorized report. This can be used in combination with `<sh:pipe>` or `<x:transform>` to produce reports not specifically generated by a specialized recipe command.
cmlenz
parents:
247
diff
changeset
|
96 for name in attr]) |
628
05686657e989
0.6dev: Implement a `subprocess` implementation of `execute()` that is now the default for all slaves where this is available - essentially all slaves with Python 2.4 and higher, or where module is installed separately. This fixes:
osimons
parents:
611
diff
changeset
|
97 function_args, has_kwargs = inspect.getargspec(function)[0:3:2] |
05686657e989
0.6dev: Implement a `subprocess` implementation of `execute()` that is now the default for all slaves where this is available - essentially all slaves with Python 2.4 and higher, or where module is installed separately. This fixes:
osimons
parents:
611
diff
changeset
|
98 for arg in args: |
630
042c8b49ce7f
0.6dev: Follow-up to [702] - flawed logic in argument testing.
osimons
parents:
629
diff
changeset
|
99 if not (arg in function_args or has_kwargs): |
628
05686657e989
0.6dev: Implement a `subprocess` implementation of `execute()` that is now the default for all slaves where this is available - essentially all slaves with Python 2.4 and higher, or where module is installed separately. This fixes:
osimons
parents:
611
diff
changeset
|
100 raise InvalidRecipeError( |
05686657e989
0.6dev: Implement a `subprocess` implementation of `execute()` that is now the default for all slaves where this is available - essentially all slaves with Python 2.4 and higher, or where module is installed separately. This fixes:
osimons
parents:
611
diff
changeset
|
101 "Unsupported argument '%s' for command %s" % \ |
05686657e989
0.6dev: Implement a `subprocess` implementation of `execute()` that is now the default for all slaves where this is available - essentially all slaves with Python 2.4 and higher, or where module is installed separately. This fixes:
osimons
parents:
611
diff
changeset
|
102 (arg, qname)) |
265
3dd311b4ad27
Add a generic `<report>` recipe command, which can be used to send any XML file to the master as a categorized report. This can be used in combination with `<sh:pipe>` or `<x:transform>` to produce reports not specifically generated by a specialized recipe command.
cmlenz
parents:
247
diff
changeset
|
103 |
3dd311b4ad27
Add a generic `<report>` recipe command, which can be used to send any XML file to the master as a categorized report. This can be used in combination with `<sh:pipe>` or `<x:transform>` to produce reports not specifically generated by a specialized recipe command.
cmlenz
parents:
247
diff
changeset
|
104 self.generator = qname |
3dd311b4ad27
Add a generic `<report>` recipe command, which can be used to send any XML file to the master as a categorized report. This can be used in combination with `<sh:pipe>` or `<x:transform>` to produce reports not specifically generated by a specialized recipe command.
cmlenz
parents:
247
diff
changeset
|
105 log.debug('Executing %s with arguments: %s', function, args) |
3dd311b4ad27
Add a generic `<report>` recipe command, which can be used to send any XML file to the master as a categorized report. This can be used in combination with `<sh:pipe>` or `<x:transform>` to produce reports not specifically generated by a specialized recipe command.
cmlenz
parents:
247
diff
changeset
|
106 function(self, **args) |
3dd311b4ad27
Add a generic `<report>` recipe command, which can be used to send any XML file to the master as a categorized report. This can be used in combination with `<sh:pipe>` or `<x:transform>` to produce reports not specifically generated by a specialized recipe command.
cmlenz
parents:
247
diff
changeset
|
107 |
3dd311b4ad27
Add a generic `<report>` recipe command, which can be used to send any XML file to the master as a categorized report. This can be used in combination with `<sh:pipe>` or `<x:transform>` to produce reports not specifically generated by a specialized recipe command.
cmlenz
parents:
247
diff
changeset
|
108 finally: |
3dd311b4ad27
Add a generic `<report>` recipe command, which can be used to send any XML file to the master as a categorized report. This can be used in combination with `<sh:pipe>` or `<x:transform>` to produce reports not specifically generated by a specialized recipe command.
cmlenz
parents:
247
diff
changeset
|
109 self.generator = None |
3dd311b4ad27
Add a generic `<report>` recipe command, which can be used to send any XML file to the master as a categorized report. This can be used in combination with `<sh:pipe>` or `<x:transform>` to produce reports not specifically generated by a specialized recipe command.
cmlenz
parents:
247
diff
changeset
|
110 self.step = None |
213
25f84dd9f159
* Refactoring of build recipes, the file format has changed slightly:
cmlenz
parents:
203
diff
changeset
|
111 |
131
3ed8f568f60a
Fix error handling so that reports are still generated even if a command has failed.
cmlenz
parents:
129
diff
changeset
|
112 def error(self, message): |
313 | 113 """Record an error message. |
114 | |
411
a169d2e96463
Use reStructuredText as the API documentation syntax.
cmlenz
parents:
408
diff
changeset
|
115 :param message: a string containing the error message. |
313 | 116 """ |
213
25f84dd9f159
* Refactoring of build recipes, the file format has changed slightly:
cmlenz
parents:
203
diff
changeset
|
117 self.output.append((Recipe.ERROR, None, self.generator, message)) |
131
3ed8f568f60a
Fix error handling so that reports are still generated even if a command has failed.
cmlenz
parents:
129
diff
changeset
|
118 |
313 | 119 def log(self, xml): |
120 """Record log output. | |
121 | |
411
a169d2e96463
Use reStructuredText as the API documentation syntax.
cmlenz
parents:
408
diff
changeset
|
122 :param xml: an XML fragment containing the log messages |
313 | 123 """ |
124 self.output.append((Recipe.LOG, None, self.generator, xml)) | |
109
5bf22bb87915
Transmit build log and generated data back to the build master in XML format. Closes #23.
cmlenz
parents:
93
diff
changeset
|
125 |
313 | 126 def report(self, category, xml): |
127 """Record report data. | |
128 | |
411
a169d2e96463
Use reStructuredText as the API documentation syntax.
cmlenz
parents:
408
diff
changeset
|
129 :param category: the name of category of the report |
a169d2e96463
Use reStructuredText as the API documentation syntax.
cmlenz
parents:
408
diff
changeset
|
130 :param xml: an XML fragment containing the report data |
313 | 131 """ |
132 self.output.append((Recipe.REPORT, category, self.generator, xml)) | |
60
055a6c666fa8
* Pass a {{{Context}}} object to recipe commands as the first argument. Currently this only has the basedir, but will be extended to also provide output recording etc.
cmlenz
parents:
55
diff
changeset
|
133 |
265
3dd311b4ad27
Add a generic `<report>` recipe command, which can be used to send any XML file to the master as a categorized report. This can be used in combination with `<sh:pipe>` or `<x:transform>` to produce reports not specifically generated by a specialized recipe command.
cmlenz
parents:
247
diff
changeset
|
134 def report_file(self, category=None, file_=None): |
313 | 135 """Read report data from a file and record it. |
136 | |
411
a169d2e96463
Use reStructuredText as the API documentation syntax.
cmlenz
parents:
408
diff
changeset
|
137 :param category: the name of the category of the report |
a169d2e96463
Use reStructuredText as the API documentation syntax.
cmlenz
parents:
408
diff
changeset
|
138 :param file\_: the path to the file containing the report data, relative |
a169d2e96463
Use reStructuredText as the API documentation syntax.
cmlenz
parents:
408
diff
changeset
|
139 to the base directory |
313 | 140 """ |
314
a8fd83c0317d
Fix undefined variable in recipe error reporting. Closes #78.
cmlenz
parents:
313
diff
changeset
|
141 filename = self.resolve(file_) |
265
3dd311b4ad27
Add a generic `<report>` recipe command, which can be used to send any XML file to the master as a categorized report. This can be used in combination with `<sh:pipe>` or `<x:transform>` to produce reports not specifically generated by a specialized recipe command.
cmlenz
parents:
247
diff
changeset
|
142 try: |
314
a8fd83c0317d
Fix undefined variable in recipe error reporting. Closes #78.
cmlenz
parents:
313
diff
changeset
|
143 fileobj = file(filename, 'r') |
265
3dd311b4ad27
Add a generic `<report>` recipe command, which can be used to send any XML file to the master as a categorized report. This can be used in combination with `<sh:pipe>` or `<x:transform>` to produce reports not specifically generated by a specialized recipe command.
cmlenz
parents:
247
diff
changeset
|
144 try: |
3dd311b4ad27
Add a generic `<report>` recipe command, which can be used to send any XML file to the master as a categorized report. This can be used in combination with `<sh:pipe>` or `<x:transform>` to produce reports not specifically generated by a specialized recipe command.
cmlenz
parents:
247
diff
changeset
|
145 xml_elem = xmlio.Fragment() |
3dd311b4ad27
Add a generic `<report>` recipe command, which can be used to send any XML file to the master as a categorized report. This can be used in combination with `<sh:pipe>` or `<x:transform>` to produce reports not specifically generated by a specialized recipe command.
cmlenz
parents:
247
diff
changeset
|
146 for child in xmlio.parse(fileobj).children(): |
377 | 147 child_elem = xmlio.Element(child.name, **dict([ |
148 (name, value) for name, value in child.attr.items() | |
149 if value is not None | |
150 ])) | |
370
fa5400c2879d
Fix for report imports; I would have thought that the original child.attr would work since it's a DictMixin, but at runtime, we're seeing 'argument after ** must be a dictionary'
wbell
parents:
368
diff
changeset
|
151 xml_elem.append(child_elem[ |
265
3dd311b4ad27
Add a generic `<report>` recipe command, which can be used to send any XML file to the master as a categorized report. This can be used in combination with `<sh:pipe>` or `<x:transform>` to produce reports not specifically generated by a specialized recipe command.
cmlenz
parents:
247
diff
changeset
|
152 [xmlio.Element(grandchild.name)[grandchild.gettext()] |
3dd311b4ad27
Add a generic `<report>` recipe command, which can be used to send any XML file to the master as a categorized report. This can be used in combination with `<sh:pipe>` or `<x:transform>` to produce reports not specifically generated by a specialized recipe command.
cmlenz
parents:
247
diff
changeset
|
153 for grandchild in child.children()] |
3dd311b4ad27
Add a generic `<report>` recipe command, which can be used to send any XML file to the master as a categorized report. This can be used in combination with `<sh:pipe>` or `<x:transform>` to produce reports not specifically generated by a specialized recipe command.
cmlenz
parents:
247
diff
changeset
|
154 ]) |
3dd311b4ad27
Add a generic `<report>` recipe command, which can be used to send any XML file to the master as a categorized report. This can be used in combination with `<sh:pipe>` or `<x:transform>` to produce reports not specifically generated by a specialized recipe command.
cmlenz
parents:
247
diff
changeset
|
155 self.output.append((Recipe.REPORT, category, None, xml_elem)) |
3dd311b4ad27
Add a generic `<report>` recipe command, which can be used to send any XML file to the master as a categorized report. This can be used in combination with `<sh:pipe>` or `<x:transform>` to produce reports not specifically generated by a specialized recipe command.
cmlenz
parents:
247
diff
changeset
|
156 finally: |
3dd311b4ad27
Add a generic `<report>` recipe command, which can be used to send any XML file to the master as a categorized report. This can be used in combination with `<sh:pipe>` or `<x:transform>` to produce reports not specifically generated by a specialized recipe command.
cmlenz
parents:
247
diff
changeset
|
157 fileobj.close() |
3dd311b4ad27
Add a generic `<report>` recipe command, which can be used to send any XML file to the master as a categorized report. This can be used in combination with `<sh:pipe>` or `<x:transform>` to produce reports not specifically generated by a specialized recipe command.
cmlenz
parents:
247
diff
changeset
|
158 except xmlio.ParseError, e: |
3dd311b4ad27
Add a generic `<report>` recipe command, which can be used to send any XML file to the master as a categorized report. This can be used in combination with `<sh:pipe>` or `<x:transform>` to produce reports not specifically generated by a specialized recipe command.
cmlenz
parents:
247
diff
changeset
|
159 self.error('Failed to parse %s report at %s: %s' |
3dd311b4ad27
Add a generic `<report>` recipe command, which can be used to send any XML file to the master as a categorized report. This can be used in combination with `<sh:pipe>` or `<x:transform>` to produce reports not specifically generated by a specialized recipe command.
cmlenz
parents:
247
diff
changeset
|
160 % (category, filename, e)) |
3dd311b4ad27
Add a generic `<report>` recipe command, which can be used to send any XML file to the master as a categorized report. This can be used in combination with `<sh:pipe>` or `<x:transform>` to produce reports not specifically generated by a specialized recipe command.
cmlenz
parents:
247
diff
changeset
|
161 except IOError, e: |
3dd311b4ad27
Add a generic `<report>` recipe command, which can be used to send any XML file to the master as a categorized report. This can be used in combination with `<sh:pipe>` or `<x:transform>` to produce reports not specifically generated by a specialized recipe command.
cmlenz
parents:
247
diff
changeset
|
162 self.error('Failed to read %s report at %s: %s' |
3dd311b4ad27
Add a generic `<report>` recipe command, which can be used to send any XML file to the master as a categorized report. This can be used in combination with `<sh:pipe>` or `<x:transform>` to produce reports not specifically generated by a specialized recipe command.
cmlenz
parents:
247
diff
changeset
|
163 % (category, filename, e)) |
3dd311b4ad27
Add a generic `<report>` recipe command, which can be used to send any XML file to the master as a categorized report. This can be used in combination with `<sh:pipe>` or `<x:transform>` to produce reports not specifically generated by a specialized recipe command.
cmlenz
parents:
247
diff
changeset
|
164 |
629
f3bb52da9e3c
0.6dev: Adding support for attachments to configurations and build - full web implementation that mirrors what is available in Ticket and Wiki. Also added a new generic `<attach/>` command that enables attaching files to be part of a recipe and uploaded by slaves as part of build.
osimons
parents:
628
diff
changeset
|
165 def attach(self, file_=None, description=None, resource=None): |
f3bb52da9e3c
0.6dev: Adding support for attachments to configurations and build - full web implementation that mirrors what is available in Ticket and Wiki. Also added a new generic `<attach/>` command that enables attaching files to be part of a recipe and uploaded by slaves as part of build.
osimons
parents:
628
diff
changeset
|
166 """Attach a file to the build or build configuration. |
f3bb52da9e3c
0.6dev: Adding support for attachments to configurations and build - full web implementation that mirrors what is available in Ticket and Wiki. Also added a new generic `<attach/>` command that enables attaching files to be part of a recipe and uploaded by slaves as part of build.
osimons
parents:
628
diff
changeset
|
167 |
f3bb52da9e3c
0.6dev: Adding support for attachments to configurations and build - full web implementation that mirrors what is available in Ticket and Wiki. Also added a new generic `<attach/>` command that enables attaching files to be part of a recipe and uploaded by slaves as part of build.
osimons
parents:
628
diff
changeset
|
168 :param file\_: the path to the file to attach, relative to |
f3bb52da9e3c
0.6dev: Adding support for attachments to configurations and build - full web implementation that mirrors what is available in Ticket and Wiki. Also added a new generic `<attach/>` command that enables attaching files to be part of a recipe and uploaded by slaves as part of build.
osimons
parents:
628
diff
changeset
|
169 base directory. |
f3bb52da9e3c
0.6dev: Adding support for attachments to configurations and build - full web implementation that mirrors what is available in Ticket and Wiki. Also added a new generic `<attach/>` command that enables attaching files to be part of a recipe and uploaded by slaves as part of build.
osimons
parents:
628
diff
changeset
|
170 :param description: description saved with attachment |
f3bb52da9e3c
0.6dev: Adding support for attachments to configurations and build - full web implementation that mirrors what is available in Ticket and Wiki. Also added a new generic `<attach/>` command that enables attaching files to be part of a recipe and uploaded by slaves as part of build.
osimons
parents:
628
diff
changeset
|
171 :resource: which resource to attach the file to, |
f3bb52da9e3c
0.6dev: Adding support for attachments to configurations and build - full web implementation that mirrors what is available in Ticket and Wiki. Also added a new generic `<attach/>` command that enables attaching files to be part of a recipe and uploaded by slaves as part of build.
osimons
parents:
628
diff
changeset
|
172 either 'build' (default) or 'config' |
f3bb52da9e3c
0.6dev: Adding support for attachments to configurations and build - full web implementation that mirrors what is available in Ticket and Wiki. Also added a new generic `<attach/>` command that enables attaching files to be part of a recipe and uploaded by slaves as part of build.
osimons
parents:
628
diff
changeset
|
173 :replace: non-empty to replace existing attachment with same name |
f3bb52da9e3c
0.6dev: Adding support for attachments to configurations and build - full web implementation that mirrors what is available in Ticket and Wiki. Also added a new generic `<attach/>` command that enables attaching files to be part of a recipe and uploaded by slaves as part of build.
osimons
parents:
628
diff
changeset
|
174 """ |
f3bb52da9e3c
0.6dev: Adding support for attachments to configurations and build - full web implementation that mirrors what is available in Ticket and Wiki. Also added a new generic `<attach/>` command that enables attaching files to be part of a recipe and uploaded by slaves as part of build.
osimons
parents:
628
diff
changeset
|
175 filename = self.resolve(file_) |
f3bb52da9e3c
0.6dev: Adding support for attachments to configurations and build - full web implementation that mirrors what is available in Ticket and Wiki. Also added a new generic `<attach/>` command that enables attaching files to be part of a recipe and uploaded by slaves as part of build.
osimons
parents:
628
diff
changeset
|
176 try: |
f3bb52da9e3c
0.6dev: Adding support for attachments to configurations and build - full web implementation that mirrors what is available in Ticket and Wiki. Also added a new generic `<attach/>` command that enables attaching files to be part of a recipe and uploaded by slaves as part of build.
osimons
parents:
628
diff
changeset
|
177 fileobj = file(filename, 'r') |
f3bb52da9e3c
0.6dev: Adding support for attachments to configurations and build - full web implementation that mirrors what is available in Ticket and Wiki. Also added a new generic `<attach/>` command that enables attaching files to be part of a recipe and uploaded by slaves as part of build.
osimons
parents:
628
diff
changeset
|
178 try: |
f3bb52da9e3c
0.6dev: Adding support for attachments to configurations and build - full web implementation that mirrors what is available in Ticket and Wiki. Also added a new generic `<attach/>` command that enables attaching files to be part of a recipe and uploaded by slaves as part of build.
osimons
parents:
628
diff
changeset
|
179 xml_elem = xmlio.Element('file', |
f3bb52da9e3c
0.6dev: Adding support for attachments to configurations and build - full web implementation that mirrors what is available in Ticket and Wiki. Also added a new generic `<attach/>` command that enables attaching files to be part of a recipe and uploaded by slaves as part of build.
osimons
parents:
628
diff
changeset
|
180 filename=os.path.basename(filename), |
f3bb52da9e3c
0.6dev: Adding support for attachments to configurations and build - full web implementation that mirrors what is available in Ticket and Wiki. Also added a new generic `<attach/>` command that enables attaching files to be part of a recipe and uploaded by slaves as part of build.
osimons
parents:
628
diff
changeset
|
181 description=description, |
f3bb52da9e3c
0.6dev: Adding support for attachments to configurations and build - full web implementation that mirrors what is available in Ticket and Wiki. Also added a new generic `<attach/>` command that enables attaching files to be part of a recipe and uploaded by slaves as part of build.
osimons
parents:
628
diff
changeset
|
182 resource=resource or 'build') |
f3bb52da9e3c
0.6dev: Adding support for attachments to configurations and build - full web implementation that mirrors what is available in Ticket and Wiki. Also added a new generic `<attach/>` command that enables attaching files to be part of a recipe and uploaded by slaves as part of build.
osimons
parents:
628
diff
changeset
|
183 xml_elem.append(fileobj.read().encode('base64')) |
f3bb52da9e3c
0.6dev: Adding support for attachments to configurations and build - full web implementation that mirrors what is available in Ticket and Wiki. Also added a new generic `<attach/>` command that enables attaching files to be part of a recipe and uploaded by slaves as part of build.
osimons
parents:
628
diff
changeset
|
184 self.output.append((Recipe.ATTACH, None, None, xml_elem)) |
f3bb52da9e3c
0.6dev: Adding support for attachments to configurations and build - full web implementation that mirrors what is available in Ticket and Wiki. Also added a new generic `<attach/>` command that enables attaching files to be part of a recipe and uploaded by slaves as part of build.
osimons
parents:
628
diff
changeset
|
185 |
f3bb52da9e3c
0.6dev: Adding support for attachments to configurations and build - full web implementation that mirrors what is available in Ticket and Wiki. Also added a new generic `<attach/>` command that enables attaching files to be part of a recipe and uploaded by slaves as part of build.
osimons
parents:
628
diff
changeset
|
186 finally: |
f3bb52da9e3c
0.6dev: Adding support for attachments to configurations and build - full web implementation that mirrors what is available in Ticket and Wiki. Also added a new generic `<attach/>` command that enables attaching files to be part of a recipe and uploaded by slaves as part of build.
osimons
parents:
628
diff
changeset
|
187 fileobj.close() |
f3bb52da9e3c
0.6dev: Adding support for attachments to configurations and build - full web implementation that mirrors what is available in Ticket and Wiki. Also added a new generic `<attach/>` command that enables attaching files to be part of a recipe and uploaded by slaves as part of build.
osimons
parents:
628
diff
changeset
|
188 except IOError, e: |
f3bb52da9e3c
0.6dev: Adding support for attachments to configurations and build - full web implementation that mirrors what is available in Ticket and Wiki. Also added a new generic `<attach/>` command that enables attaching files to be part of a recipe and uploaded by slaves as part of build.
osimons
parents:
628
diff
changeset
|
189 self.error('Failed to read file %s as attachment' % file_) |
f3bb52da9e3c
0.6dev: Adding support for attachments to configurations and build - full web implementation that mirrors what is available in Ticket and Wiki. Also added a new generic `<attach/>` command that enables attaching files to be part of a recipe and uploaded by slaves as part of build.
osimons
parents:
628
diff
changeset
|
190 |
60
055a6c666fa8
* Pass a {{{Context}}} object to recipe commands as the first argument. Currently this only has the basedir, but will be extended to also provide output recording etc.
cmlenz
parents:
55
diff
changeset
|
191 def resolve(self, *path): |
313 | 192 """Return the path of a file relative to the base directory. |
193 | |
194 Accepts any number of positional arguments, which are joined using the | |
195 system path separator to form the path. | |
196 """ | |
68 | 197 return os.path.normpath(os.path.join(self.basedir, *path)) |
60
055a6c666fa8
* Pass a {{{Context}}} object to recipe commands as the first argument. Currently this only has the basedir, but will be extended to also provide output recording etc.
cmlenz
parents:
55
diff
changeset
|
198 |
055a6c666fa8
* Pass a {{{Context}}} object to recipe commands as the first argument. Currently this only has the basedir, but will be extended to also provide output recording etc.
cmlenz
parents:
55
diff
changeset
|
199 |
21 | 200 class Step(object): |
201 """Represents a single step of a build recipe. | |
202 | |
203 Iterate over an object of this class to get the commands to execute, and | |
204 their keyword arguments. | |
205 """ | |
206 | |
51
5caccd7b247e
Proper archive format negotiation; improved representation of parsed XML content in {{{bitten.util.xmlio}}}.
cmlenz
parents:
21
diff
changeset
|
207 def __init__(self, elem): |
313 | 208 """Create the step. |
209 | |
411
a169d2e96463
Use reStructuredText as the API documentation syntax.
cmlenz
parents:
408
diff
changeset
|
210 :param elem: the XML element representing the step |
a169d2e96463
Use reStructuredText as the API documentation syntax.
cmlenz
parents:
408
diff
changeset
|
211 :type elem: `ParsedElement` |
313 | 212 """ |
51
5caccd7b247e
Proper archive format negotiation; improved representation of parsed XML content in {{{bitten.util.xmlio}}}.
cmlenz
parents:
21
diff
changeset
|
213 self._elem = elem |
55 | 214 self.id = elem.attr['id'] |
215 self.description = elem.attr.get('description') | |
72
b2d371dac270
Allow individual steps of a recipe to be marked as optional, i.e. that an error in such a step should not mean that the build failed.
cmlenz
parents:
68
diff
changeset
|
216 self.onerror = elem.attr.get('onerror', 'fail') |
21 | 217 |
392 | 218 def __repr__(self): |
219 return '<%s %r>' % (type(self).__name__, self.id) | |
220 | |
213
25f84dd9f159
* Refactoring of build recipes, the file format has changed slightly:
cmlenz
parents:
203
diff
changeset
|
221 def execute(self, ctxt): |
313 | 222 """Execute this step in the given context. |
223 | |
411
a169d2e96463
Use reStructuredText as the API documentation syntax.
cmlenz
parents:
408
diff
changeset
|
224 :param ctxt: the build context |
a169d2e96463
Use reStructuredText as the API documentation syntax.
cmlenz
parents:
408
diff
changeset
|
225 :type ctxt: `Context` |
313 | 226 """ |
628
05686657e989
0.6dev: Implement a `subprocess` implementation of `execute()` that is now the default for all slaves where this is available - essentially all slaves with Python 2.4 and higher, or where module is installed separately. This fixes:
osimons
parents:
611
diff
changeset
|
227 last_finish = time.time() |
51
5caccd7b247e
Proper archive format negotiation; improved representation of parsed XML content in {{{bitten.util.xmlio}}}.
cmlenz
parents:
21
diff
changeset
|
228 for child in self._elem: |
628
05686657e989
0.6dev: Implement a `subprocess` implementation of `execute()` that is now the default for all slaves where this is available - essentially all slaves with Python 2.4 and higher, or where module is installed separately. This fixes:
osimons
parents:
611
diff
changeset
|
229 try: |
05686657e989
0.6dev: Implement a `subprocess` implementation of `execute()` that is now the default for all slaves where this is available - essentially all slaves with Python 2.4 and higher, or where module is installed separately. This fixes:
osimons
parents:
611
diff
changeset
|
230 ctxt.run(self, child.namespace, child.name, child.attr) |
05686657e989
0.6dev: Implement a `subprocess` implementation of `execute()` that is now the default for all slaves where this is available - essentially all slaves with Python 2.4 and higher, or where module is installed separately. This fixes:
osimons
parents:
611
diff
changeset
|
231 except (BuildError, InvalidRecipeError), e: |
05686657e989
0.6dev: Implement a `subprocess` implementation of `execute()` that is now the default for all slaves where this is available - essentially all slaves with Python 2.4 and higher, or where module is installed separately. This fixes:
osimons
parents:
611
diff
changeset
|
232 ctxt.error(e) |
05686657e989
0.6dev: Implement a `subprocess` implementation of `execute()` that is now the default for all slaves where this is available - essentially all slaves with Python 2.4 and higher, or where module is installed separately. This fixes:
osimons
parents:
611
diff
changeset
|
233 if time.time() < last_finish + 1: |
05686657e989
0.6dev: Implement a `subprocess` implementation of `execute()` that is now the default for all slaves where this is available - essentially all slaves with Python 2.4 and higher, or where module is installed separately. This fixes:
osimons
parents:
611
diff
changeset
|
234 # Add a delay to make sure steps appear in correct order |
05686657e989
0.6dev: Implement a `subprocess` implementation of `execute()` that is now the default for all slaves where this is available - essentially all slaves with Python 2.4 and higher, or where module is installed separately. This fixes:
osimons
parents:
611
diff
changeset
|
235 time.sleep(1) |
21 | 236 |
131
3ed8f568f60a
Fix error handling so that reports are still generated even if a command has failed.
cmlenz
parents:
129
diff
changeset
|
237 errors = [] |
109
5bf22bb87915
Transmit build log and generated data back to the build master in XML format. Closes #23.
cmlenz
parents:
93
diff
changeset
|
238 while ctxt.output: |
203
e6ddca1e5712
Huge refactoring to remove dependency on BDB XML. Report data is now stored in the Trac database (SQLite/PostgreSQL).
cmlenz
parents:
163
diff
changeset
|
239 type, category, generator, output = ctxt.output.pop(0) |
e6ddca1e5712
Huge refactoring to remove dependency on BDB XML. Report data is now stored in the Trac database (SQLite/PostgreSQL).
cmlenz
parents:
163
diff
changeset
|
240 yield type, category, generator, output |
131
3ed8f568f60a
Fix error handling so that reports are still generated even if a command has failed.
cmlenz
parents:
129
diff
changeset
|
241 if type == Recipe.ERROR: |
203
e6ddca1e5712
Huge refactoring to remove dependency on BDB XML. Report data is now stored in the Trac database (SQLite/PostgreSQL).
cmlenz
parents:
163
diff
changeset
|
242 errors.append((generator, output)) |
131
3ed8f568f60a
Fix error handling so that reports are still generated even if a command has failed.
cmlenz
parents:
129
diff
changeset
|
243 if errors: |
628
05686657e989
0.6dev: Implement a `subprocess` implementation of `execute()` that is now the default for all slaves where this is available - essentially all slaves with Python 2.4 and higher, or where module is installed separately. This fixes:
osimons
parents:
611
diff
changeset
|
244 for _t, error in errors: |
05686657e989
0.6dev: Implement a `subprocess` implementation of `execute()` that is now the default for all slaves where this is available - essentially all slaves with Python 2.4 and higher, or where module is installed separately. This fixes:
osimons
parents:
611
diff
changeset
|
245 log.error(error) |
387
7cd9a26134f5
Default behavior of slaves is now to stop building when an error is raised by a step set to onerror='fail'. onerror='continue' can be used to get the old behavior, while onerror='ignore' is also still available for completely ignoring failed steps.
cmlenz
parents:
379
diff
changeset
|
246 if self.onerror != 'ignore': |
628
05686657e989
0.6dev: Implement a `subprocess` implementation of `execute()` that is now the default for all slaves where this is available - essentially all slaves with Python 2.4 and higher, or where module is installed separately. This fixes:
osimons
parents:
611
diff
changeset
|
247 raise BuildError("Build step '%s' failed" % self.id) |
05686657e989
0.6dev: Implement a `subprocess` implementation of `execute()` that is now the default for all slaves where this is available - essentially all slaves with Python 2.4 and higher, or where module is installed separately. This fixes:
osimons
parents:
611
diff
changeset
|
248 log.warning("Continuing despite errors in step '%s'", self.id) |
72
b2d371dac270
Allow individual steps of a recipe to be marked as optional, i.e. that an error in such a step should not mean that the build failed.
cmlenz
parents:
68
diff
changeset
|
249 |
21 | 250 |
251 class Recipe(object): | |
60
055a6c666fa8
* Pass a {{{Context}}} object to recipe commands as the first argument. Currently this only has the basedir, but will be extended to also provide output recording etc.
cmlenz
parents:
55
diff
changeset
|
252 """A build recipe. |
21 | 253 |
313 | 254 Iterate over this object to get the individual build steps in the order |
255 they have been defined in the recipe file. | |
131
3ed8f568f60a
Fix error handling so that reports are still generated even if a command has failed.
cmlenz
parents:
129
diff
changeset
|
256 """ |
21 | 257 |
131
3ed8f568f60a
Fix error handling so that reports are still generated even if a command has failed.
cmlenz
parents:
129
diff
changeset
|
258 ERROR = 'error' |
109
5bf22bb87915
Transmit build log and generated data back to the build master in XML format. Closes #23.
cmlenz
parents:
93
diff
changeset
|
259 LOG = 'log' |
5bf22bb87915
Transmit build log and generated data back to the build master in XML format. Closes #23.
cmlenz
parents:
93
diff
changeset
|
260 REPORT = 'report' |
629
f3bb52da9e3c
0.6dev: Adding support for attachments to configurations and build - full web implementation that mirrors what is available in Ticket and Wiki. Also added a new generic `<attach/>` command that enables attaching files to be part of a recipe and uploaded by slaves as part of build.
osimons
parents:
628
diff
changeset
|
261 ATTACH = 'attach' |
109
5bf22bb87915
Transmit build log and generated data back to the build master in XML format. Closes #23.
cmlenz
parents:
93
diff
changeset
|
262 |
233
8f816147620f
* Moved SlaveConfiguration logic into new module ([source:/trunk/bitten/build/config.py bitten.build.config]).
cmlenz
parents:
213
diff
changeset
|
263 def __init__(self, xml, basedir=os.getcwd(), config=None): |
313 | 264 """Create the recipe. |
265 | |
411
a169d2e96463
Use reStructuredText as the API documentation syntax.
cmlenz
parents:
408
diff
changeset
|
266 :param xml: the XML document representing the recipe |
a169d2e96463
Use reStructuredText as the API documentation syntax.
cmlenz
parents:
408
diff
changeset
|
267 :type xml: `ParsedElement` |
a169d2e96463
Use reStructuredText as the API documentation syntax.
cmlenz
parents:
408
diff
changeset
|
268 :param basedir: the base directory for the build |
a169d2e96463
Use reStructuredText as the API documentation syntax.
cmlenz
parents:
408
diff
changeset
|
269 :param config: the slave configuration (optional) |
a169d2e96463
Use reStructuredText as the API documentation syntax.
cmlenz
parents:
408
diff
changeset
|
270 :type config: `Configuration` |
313 | 271 """ |
148
f3f5895e373c
Fixes to problems in recipe handling introduced in [155].
cmlenz
parents:
147
diff
changeset
|
272 assert isinstance(xml, xmlio.ParsedElement) |
392 | 273 vars = dict([(name, value) for name, value in xml.attr.items() |
274 if not name.startswith('xmlns')]) | |
275 self.ctxt = Context(basedir, config, vars) | |
148
f3f5895e373c
Fixes to problems in recipe handling introduced in [155].
cmlenz
parents:
147
diff
changeset
|
276 self._root = xml |
21 | 277 |
278 def __iter__(self): | |
313 | 279 """Iterate over the individual steps of the recipe.""" |
60
055a6c666fa8
* Pass a {{{Context}}} object to recipe commands as the first argument. Currently this only has the basedir, but will be extended to also provide output recording etc.
cmlenz
parents:
55
diff
changeset
|
280 for child in self._root.children('step'): |
21 | 281 yield Step(child) |
247
b28285d3ceec
Add validation for build configurations, and in particular for build recipes. Closes #48.
cmlenz
parents:
238
diff
changeset
|
282 |
b28285d3ceec
Add validation for build configurations, and in particular for build recipes. Closes #48.
cmlenz
parents:
238
diff
changeset
|
283 def validate(self): |
313 | 284 """Validate the recipe. |
285 | |
286 This method checks a number of constraints: | |
287 - the name of the root element must be "build" | |
288 - the only permitted child elements or the root element with the name | |
289 "step" | |
290 - the recipe must contain at least one step | |
291 - step elements must have a unique "id" attribute | |
292 - a step must contain at least one nested command | |
293 - commands must not have nested content | |
294 | |
411
a169d2e96463
Use reStructuredText as the API documentation syntax.
cmlenz
parents:
408
diff
changeset
|
295 :raise InvalidRecipeError: in case any of the above contraints is |
a169d2e96463
Use reStructuredText as the API documentation syntax.
cmlenz
parents:
408
diff
changeset
|
296 violated |
313 | 297 """ |
247
b28285d3ceec
Add validation for build configurations, and in particular for build recipes. Closes #48.
cmlenz
parents:
238
diff
changeset
|
298 if self._root.name != 'build': |
368 | 299 raise InvalidRecipeError('Root element must be <build>') |
247
b28285d3ceec
Add validation for build configurations, and in particular for build recipes. Closes #48.
cmlenz
parents:
238
diff
changeset
|
300 steps = list(self._root.children()) |
b28285d3ceec
Add validation for build configurations, and in particular for build recipes. Closes #48.
cmlenz
parents:
238
diff
changeset
|
301 if not steps: |
368 | 302 raise InvalidRecipeError('Recipe defines no build steps') |
247
b28285d3ceec
Add validation for build configurations, and in particular for build recipes. Closes #48.
cmlenz
parents:
238
diff
changeset
|
303 |
b28285d3ceec
Add validation for build configurations, and in particular for build recipes. Closes #48.
cmlenz
parents:
238
diff
changeset
|
304 step_ids = set() |
b28285d3ceec
Add validation for build configurations, and in particular for build recipes. Closes #48.
cmlenz
parents:
238
diff
changeset
|
305 for step in steps: |
b28285d3ceec
Add validation for build configurations, and in particular for build recipes. Closes #48.
cmlenz
parents:
238
diff
changeset
|
306 if step.name != 'step': |
368 | 307 raise InvalidRecipeError('Only <step> elements allowed at ' |
308 'top level of recipe') | |
247
b28285d3ceec
Add validation for build configurations, and in particular for build recipes. Closes #48.
cmlenz
parents:
238
diff
changeset
|
309 if not step.attr.get('id'): |
368 | 310 raise InvalidRecipeError('Steps must have an "id" attribute') |
247
b28285d3ceec
Add validation for build configurations, and in particular for build recipes. Closes #48.
cmlenz
parents:
238
diff
changeset
|
311 |
b28285d3ceec
Add validation for build configurations, and in particular for build recipes. Closes #48.
cmlenz
parents:
238
diff
changeset
|
312 if step.attr['id'] in step_ids: |
368 | 313 raise InvalidRecipeError('Duplicate step ID "%s"' % |
314 step.attr['id']) | |
247
b28285d3ceec
Add validation for build configurations, and in particular for build recipes. Closes #48.
cmlenz
parents:
238
diff
changeset
|
315 step_ids.add(step.attr['id']) |
b28285d3ceec
Add validation for build configurations, and in particular for build recipes. Closes #48.
cmlenz
parents:
238
diff
changeset
|
316 |
b28285d3ceec
Add validation for build configurations, and in particular for build recipes. Closes #48.
cmlenz
parents:
238
diff
changeset
|
317 cmds = list(step.children()) |
b28285d3ceec
Add validation for build configurations, and in particular for build recipes. Closes #48.
cmlenz
parents:
238
diff
changeset
|
318 if not cmds: |
368 | 319 raise InvalidRecipeError('Step "%s" has no recipe commands' % |
320 step.attr['id']) | |
247
b28285d3ceec
Add validation for build configurations, and in particular for build recipes. Closes #48.
cmlenz
parents:
238
diff
changeset
|
321 for cmd in cmds: |
b28285d3ceec
Add validation for build configurations, and in particular for build recipes. Closes #48.
cmlenz
parents:
238
diff
changeset
|
322 if len(list(cmd.children())): |
368 | 323 raise InvalidRecipeError('Recipe command <%s> has nested ' |
324 'content' % cmd.name) |