xref: /freebsd/contrib/kyua/model/metadata.cpp (revision 257e70f1d5ee61037c8c59b116538d3b6b1427a2)
1b0d29bc4SBrooks Davis // Copyright 2012 The Kyua Authors.
2b0d29bc4SBrooks Davis // All rights reserved.
3b0d29bc4SBrooks Davis //
4b0d29bc4SBrooks Davis // Redistribution and use in source and binary forms, with or without
5b0d29bc4SBrooks Davis // modification, are permitted provided that the following conditions are
6b0d29bc4SBrooks Davis // met:
7b0d29bc4SBrooks Davis //
8b0d29bc4SBrooks Davis // * Redistributions of source code must retain the above copyright
9b0d29bc4SBrooks Davis //   notice, this list of conditions and the following disclaimer.
10b0d29bc4SBrooks Davis // * Redistributions in binary form must reproduce the above copyright
11b0d29bc4SBrooks Davis //   notice, this list of conditions and the following disclaimer in the
12b0d29bc4SBrooks Davis //   documentation and/or other materials provided with the distribution.
13b0d29bc4SBrooks Davis // * Neither the name of Google Inc. nor the names of its contributors
14b0d29bc4SBrooks Davis //   may be used to endorse or promote products derived from this software
15b0d29bc4SBrooks Davis //   without specific prior written permission.
16b0d29bc4SBrooks Davis //
17b0d29bc4SBrooks Davis // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18b0d29bc4SBrooks Davis // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19b0d29bc4SBrooks Davis // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20b0d29bc4SBrooks Davis // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21b0d29bc4SBrooks Davis // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22b0d29bc4SBrooks Davis // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23b0d29bc4SBrooks Davis // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24b0d29bc4SBrooks Davis // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25b0d29bc4SBrooks Davis // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26b0d29bc4SBrooks Davis // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27b0d29bc4SBrooks Davis // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28b0d29bc4SBrooks Davis 
29b0d29bc4SBrooks Davis #include "model/metadata.hpp"
30b0d29bc4SBrooks Davis 
31b0d29bc4SBrooks Davis #include <memory>
32b0d29bc4SBrooks Davis 
33*257e70f1SIgor Ostapenko #include "engine/execenv/execenv.hpp"
34b0d29bc4SBrooks Davis #include "model/exceptions.hpp"
35b0d29bc4SBrooks Davis #include "model/types.hpp"
36b0d29bc4SBrooks Davis #include "utils/config/exceptions.hpp"
37b0d29bc4SBrooks Davis #include "utils/config/nodes.ipp"
38b0d29bc4SBrooks Davis #include "utils/config/tree.ipp"
39b0d29bc4SBrooks Davis #include "utils/datetime.hpp"
40b0d29bc4SBrooks Davis #include "utils/defs.hpp"
41b0d29bc4SBrooks Davis #include "utils/format/macros.hpp"
42b0d29bc4SBrooks Davis #include "utils/fs/exceptions.hpp"
43b0d29bc4SBrooks Davis #include "utils/fs/path.hpp"
44b0d29bc4SBrooks Davis #include "utils/noncopyable.hpp"
45b0d29bc4SBrooks Davis #include "utils/optional.ipp"
46b0d29bc4SBrooks Davis #include "utils/sanity.hpp"
47b0d29bc4SBrooks Davis #include "utils/text/exceptions.hpp"
48b0d29bc4SBrooks Davis #include "utils/text/operations.hpp"
49b0d29bc4SBrooks Davis #include "utils/units.hpp"
50b0d29bc4SBrooks Davis 
51b0d29bc4SBrooks Davis namespace config = utils::config;
52b0d29bc4SBrooks Davis namespace datetime = utils::datetime;
53b0d29bc4SBrooks Davis namespace fs = utils::fs;
54b0d29bc4SBrooks Davis namespace text = utils::text;
55b0d29bc4SBrooks Davis namespace units = utils::units;
56b0d29bc4SBrooks Davis 
57b0d29bc4SBrooks Davis using utils::optional;
58b0d29bc4SBrooks Davis 
59b0d29bc4SBrooks Davis 
60b0d29bc4SBrooks Davis namespace {
61b0d29bc4SBrooks Davis 
62b0d29bc4SBrooks Davis 
63b0d29bc4SBrooks Davis /// Global instance of defaults.
64b0d29bc4SBrooks Davis ///
65b0d29bc4SBrooks Davis /// This exists so that the getters in metadata can return references instead
66b0d29bc4SBrooks Davis /// of object copies.  Use get_defaults() to query.
67b0d29bc4SBrooks Davis static optional< config::tree > defaults;
68b0d29bc4SBrooks Davis 
69b0d29bc4SBrooks Davis 
70b0d29bc4SBrooks Davis /// A leaf node that holds a bytes quantity.
71b0d29bc4SBrooks Davis class bytes_node : public config::native_leaf_node< units::bytes > {
72b0d29bc4SBrooks Davis public:
73b0d29bc4SBrooks Davis     /// Copies the node.
74b0d29bc4SBrooks Davis     ///
75b0d29bc4SBrooks Davis     /// \return A dynamically-allocated node.
76b0d29bc4SBrooks Davis     virtual base_node*
deep_copy(void) const77b0d29bc4SBrooks Davis     deep_copy(void) const
78b0d29bc4SBrooks Davis     {
79b0d29bc4SBrooks Davis         std::auto_ptr< bytes_node > new_node(new bytes_node());
80b0d29bc4SBrooks Davis         new_node->_value = _value;
81b0d29bc4SBrooks Davis         return new_node.release();
82b0d29bc4SBrooks Davis     }
83b0d29bc4SBrooks Davis 
84b0d29bc4SBrooks Davis     /// Pushes the node's value onto the Lua stack.
85b0d29bc4SBrooks Davis     void
push_lua(lutok::state &) const86b0d29bc4SBrooks Davis     push_lua(lutok::state& /* state */) const
87b0d29bc4SBrooks Davis     {
88b0d29bc4SBrooks Davis         UNREACHABLE;
89b0d29bc4SBrooks Davis     }
90b0d29bc4SBrooks Davis 
91b0d29bc4SBrooks Davis     /// Sets the value of the node from an entry in the Lua stack.
92b0d29bc4SBrooks Davis     void
set_lua(lutok::state &,const int)93b0d29bc4SBrooks Davis     set_lua(lutok::state& /* state */, const int /* index */)
94b0d29bc4SBrooks Davis     {
95b0d29bc4SBrooks Davis         UNREACHABLE;
96b0d29bc4SBrooks Davis     }
97b0d29bc4SBrooks Davis };
98b0d29bc4SBrooks Davis 
99b0d29bc4SBrooks Davis 
100b0d29bc4SBrooks Davis /// A leaf node that holds a time delta.
101b0d29bc4SBrooks Davis class delta_node : public config::typed_leaf_node< datetime::delta > {
102b0d29bc4SBrooks Davis public:
103b0d29bc4SBrooks Davis     /// Copies the node.
104b0d29bc4SBrooks Davis     ///
105b0d29bc4SBrooks Davis     /// \return A dynamically-allocated node.
106b0d29bc4SBrooks Davis     virtual base_node*
deep_copy(void) const107b0d29bc4SBrooks Davis     deep_copy(void) const
108b0d29bc4SBrooks Davis     {
109b0d29bc4SBrooks Davis         std::auto_ptr< delta_node > new_node(new delta_node());
110b0d29bc4SBrooks Davis         new_node->_value = _value;
111b0d29bc4SBrooks Davis         return new_node.release();
112b0d29bc4SBrooks Davis     }
113b0d29bc4SBrooks Davis 
114b0d29bc4SBrooks Davis     /// Sets the value of the node from a raw string representation.
115b0d29bc4SBrooks Davis     ///
116b0d29bc4SBrooks Davis     /// \param raw_value The value to set the node to.
117b0d29bc4SBrooks Davis     ///
118b0d29bc4SBrooks Davis     /// \throw value_error If the value is invalid.
119b0d29bc4SBrooks Davis     void
set_string(const std::string & raw_value)120b0d29bc4SBrooks Davis     set_string(const std::string& raw_value)
121b0d29bc4SBrooks Davis     {
122b0d29bc4SBrooks Davis         unsigned int seconds;
123b0d29bc4SBrooks Davis         try {
124b0d29bc4SBrooks Davis             seconds = text::to_type< unsigned int >(raw_value);
125b0d29bc4SBrooks Davis         } catch (const text::error& e) {
126b0d29bc4SBrooks Davis             throw config::value_error(F("Invalid time delta %s") % raw_value);
127b0d29bc4SBrooks Davis         }
128b0d29bc4SBrooks Davis         set(datetime::delta(seconds, 0));
129b0d29bc4SBrooks Davis     }
130b0d29bc4SBrooks Davis 
131b0d29bc4SBrooks Davis     /// Converts the contents of the node to a string.
132b0d29bc4SBrooks Davis     ///
133b0d29bc4SBrooks Davis     /// \pre The node must have a value.
134b0d29bc4SBrooks Davis     ///
135b0d29bc4SBrooks Davis     /// \return A string representation of the value held by the node.
136b0d29bc4SBrooks Davis     std::string
to_string(void) const137b0d29bc4SBrooks Davis     to_string(void) const
138b0d29bc4SBrooks Davis     {
139b0d29bc4SBrooks Davis         return F("%s") % value().seconds;
140b0d29bc4SBrooks Davis     }
141b0d29bc4SBrooks Davis 
142b0d29bc4SBrooks Davis     /// Pushes the node's value onto the Lua stack.
143b0d29bc4SBrooks Davis     void
push_lua(lutok::state &) const144b0d29bc4SBrooks Davis     push_lua(lutok::state& /* state */) const
145b0d29bc4SBrooks Davis     {
146b0d29bc4SBrooks Davis         UNREACHABLE;
147b0d29bc4SBrooks Davis     }
148b0d29bc4SBrooks Davis 
149b0d29bc4SBrooks Davis     /// Sets the value of the node from an entry in the Lua stack.
150b0d29bc4SBrooks Davis     void
set_lua(lutok::state &,const int)151b0d29bc4SBrooks Davis     set_lua(lutok::state& /* state */, const int /* index */)
152b0d29bc4SBrooks Davis     {
153b0d29bc4SBrooks Davis         UNREACHABLE;
154b0d29bc4SBrooks Davis     }
155b0d29bc4SBrooks Davis };
156b0d29bc4SBrooks Davis 
157b0d29bc4SBrooks Davis 
158b0d29bc4SBrooks Davis /// A leaf node that holds a "required user" property.
159b0d29bc4SBrooks Davis ///
160b0d29bc4SBrooks Davis /// This node is just a string, but it provides validation of the only allowed
161b0d29bc4SBrooks Davis /// values.
162b0d29bc4SBrooks Davis class user_node : public config::string_node {
163b0d29bc4SBrooks Davis     /// Copies the node.
164b0d29bc4SBrooks Davis     ///
165b0d29bc4SBrooks Davis     /// \return A dynamically-allocated node.
166b0d29bc4SBrooks Davis     virtual base_node*
deep_copy(void) const167b0d29bc4SBrooks Davis     deep_copy(void) const
168b0d29bc4SBrooks Davis     {
169b0d29bc4SBrooks Davis         std::auto_ptr< user_node > new_node(new user_node());
170b0d29bc4SBrooks Davis         new_node->_value = _value;
171b0d29bc4SBrooks Davis         return new_node.release();
172b0d29bc4SBrooks Davis     }
173b0d29bc4SBrooks Davis 
174b0d29bc4SBrooks Davis     /// Checks a given user textual representation for validity.
175b0d29bc4SBrooks Davis     ///
176b0d29bc4SBrooks Davis     /// \param user The value to validate.
177b0d29bc4SBrooks Davis     ///
178b0d29bc4SBrooks Davis     /// \throw config::value_error If the value is not valid.
179b0d29bc4SBrooks Davis     void
validate(const value_type & user) const180b0d29bc4SBrooks Davis     validate(const value_type& user) const
181b0d29bc4SBrooks Davis     {
182b0d29bc4SBrooks Davis         if (!user.empty() && user != "root" && user != "unprivileged")
183b0d29bc4SBrooks Davis             throw config::value_error("Invalid required user value");
184b0d29bc4SBrooks Davis     }
185b0d29bc4SBrooks Davis };
186b0d29bc4SBrooks Davis 
187b0d29bc4SBrooks Davis 
188b0d29bc4SBrooks Davis /// A leaf node that holds a set of paths.
189b0d29bc4SBrooks Davis ///
190b0d29bc4SBrooks Davis /// This node type is used to represent the value of the required files and
191b0d29bc4SBrooks Davis /// required programs, for example, and these do not allow relative paths.  We
192b0d29bc4SBrooks Davis /// check this here.
193b0d29bc4SBrooks Davis class paths_set_node : public config::base_set_node< fs::path > {
194b0d29bc4SBrooks Davis     /// Copies the node.
195b0d29bc4SBrooks Davis     ///
196b0d29bc4SBrooks Davis     /// \return A dynamically-allocated node.
197b0d29bc4SBrooks Davis     virtual base_node*
deep_copy(void) const198b0d29bc4SBrooks Davis     deep_copy(void) const
199b0d29bc4SBrooks Davis     {
200b0d29bc4SBrooks Davis         std::auto_ptr< paths_set_node > new_node(new paths_set_node());
201b0d29bc4SBrooks Davis         new_node->_value = _value;
202b0d29bc4SBrooks Davis         return new_node.release();
203b0d29bc4SBrooks Davis     }
204b0d29bc4SBrooks Davis 
205b0d29bc4SBrooks Davis     /// Converts a single path to the native type.
206b0d29bc4SBrooks Davis     ///
207b0d29bc4SBrooks Davis     /// \param raw_value The value to parse.
208b0d29bc4SBrooks Davis     ///
209b0d29bc4SBrooks Davis     /// \return The parsed value.
210b0d29bc4SBrooks Davis     ///
211b0d29bc4SBrooks Davis     /// \throw config::value_error If the value is invalid.
212b0d29bc4SBrooks Davis     fs::path
parse_one(const std::string & raw_value) const213b0d29bc4SBrooks Davis     parse_one(const std::string& raw_value) const
214b0d29bc4SBrooks Davis     {
215b0d29bc4SBrooks Davis         try {
216b0d29bc4SBrooks Davis             return fs::path(raw_value);
217b0d29bc4SBrooks Davis         } catch (const fs::error& e) {
218b0d29bc4SBrooks Davis             throw config::value_error(e.what());
219b0d29bc4SBrooks Davis         }
220b0d29bc4SBrooks Davis     }
221b0d29bc4SBrooks Davis 
222b0d29bc4SBrooks Davis     /// Checks a collection of paths for validity.
223b0d29bc4SBrooks Davis     ///
224b0d29bc4SBrooks Davis     /// \param paths The value to validate.
225b0d29bc4SBrooks Davis     ///
226b0d29bc4SBrooks Davis     /// \throw config::value_error If the value is not valid.
227b0d29bc4SBrooks Davis     void
validate(const value_type & paths) const228b0d29bc4SBrooks Davis     validate(const value_type& paths) const
229b0d29bc4SBrooks Davis     {
230b0d29bc4SBrooks Davis         for (value_type::const_iterator iter = paths.begin();
231b0d29bc4SBrooks Davis              iter != paths.end(); ++iter) {
232b0d29bc4SBrooks Davis             const fs::path& path = *iter;
233b0d29bc4SBrooks Davis             if (!path.is_absolute() && path.ncomponents() > 1)
234b0d29bc4SBrooks Davis                 throw config::value_error(F("Relative path '%s' not allowed") %
235b0d29bc4SBrooks Davis                                           *iter);
236b0d29bc4SBrooks Davis         }
237b0d29bc4SBrooks Davis     }
238b0d29bc4SBrooks Davis };
239b0d29bc4SBrooks Davis 
240b0d29bc4SBrooks Davis 
241b0d29bc4SBrooks Davis /// Initializes a tree to hold test case requirements.
242b0d29bc4SBrooks Davis ///
243b0d29bc4SBrooks Davis /// \param [in,out] tree The tree to initialize.
244b0d29bc4SBrooks Davis static void
init_tree(config::tree & tree)245b0d29bc4SBrooks Davis init_tree(config::tree& tree)
246b0d29bc4SBrooks Davis {
247b0d29bc4SBrooks Davis     tree.define< config::strings_set_node >("allowed_architectures");
248b0d29bc4SBrooks Davis     tree.define< config::strings_set_node >("allowed_platforms");
249b0d29bc4SBrooks Davis     tree.define_dynamic("custom");
250b0d29bc4SBrooks Davis     tree.define< config::string_node >("description");
251*257e70f1SIgor Ostapenko     tree.define< config::string_node >("execenv");
252*257e70f1SIgor Ostapenko     tree.define< config::string_node >("execenv_jail_params");
253b0d29bc4SBrooks Davis     tree.define< config::bool_node >("has_cleanup");
254b0d29bc4SBrooks Davis     tree.define< config::bool_node >("is_exclusive");
255b0d29bc4SBrooks Davis     tree.define< config::strings_set_node >("required_configs");
256b0d29bc4SBrooks Davis     tree.define< bytes_node >("required_disk_space");
257b0d29bc4SBrooks Davis     tree.define< paths_set_node >("required_files");
258b0d29bc4SBrooks Davis     tree.define< bytes_node >("required_memory");
259b0d29bc4SBrooks Davis     tree.define< paths_set_node >("required_programs");
260b0d29bc4SBrooks Davis     tree.define< user_node >("required_user");
261b0d29bc4SBrooks Davis     tree.define< delta_node >("timeout");
262b0d29bc4SBrooks Davis }
263b0d29bc4SBrooks Davis 
264b0d29bc4SBrooks Davis 
265b0d29bc4SBrooks Davis /// Sets default values on a tree object.
266b0d29bc4SBrooks Davis ///
267b0d29bc4SBrooks Davis /// \param [in,out] tree The tree to configure.
268b0d29bc4SBrooks Davis static void
set_defaults(config::tree & tree)269b0d29bc4SBrooks Davis set_defaults(config::tree& tree)
270b0d29bc4SBrooks Davis {
271b0d29bc4SBrooks Davis     tree.set< config::strings_set_node >("allowed_architectures",
272b0d29bc4SBrooks Davis                                          model::strings_set());
273b0d29bc4SBrooks Davis     tree.set< config::strings_set_node >("allowed_platforms",
274b0d29bc4SBrooks Davis                                          model::strings_set());
275b0d29bc4SBrooks Davis     tree.set< config::string_node >("description", "");
276*257e70f1SIgor Ostapenko     tree.set< config::string_node >("execenv", "");
277*257e70f1SIgor Ostapenko     tree.set< config::string_node >("execenv_jail_params", "");
278b0d29bc4SBrooks Davis     tree.set< config::bool_node >("has_cleanup", false);
279b0d29bc4SBrooks Davis     tree.set< config::bool_node >("is_exclusive", false);
280b0d29bc4SBrooks Davis     tree.set< config::strings_set_node >("required_configs",
281b0d29bc4SBrooks Davis                                          model::strings_set());
282b0d29bc4SBrooks Davis     tree.set< bytes_node >("required_disk_space", units::bytes(0));
283b0d29bc4SBrooks Davis     tree.set< paths_set_node >("required_files", model::paths_set());
284b0d29bc4SBrooks Davis     tree.set< bytes_node >("required_memory", units::bytes(0));
285b0d29bc4SBrooks Davis     tree.set< paths_set_node >("required_programs", model::paths_set());
286b0d29bc4SBrooks Davis     tree.set< user_node >("required_user", "");
287b0d29bc4SBrooks Davis     // TODO(jmmv): We shouldn't be setting a default timeout like this.  See
288b0d29bc4SBrooks Davis     // Issue 5 for details.
289b0d29bc4SBrooks Davis     tree.set< delta_node >("timeout", datetime::delta(300, 0));
290b0d29bc4SBrooks Davis }
291b0d29bc4SBrooks Davis 
292b0d29bc4SBrooks Davis 
293b0d29bc4SBrooks Davis /// Queries the global defaults tree object with lazy initialization.
294b0d29bc4SBrooks Davis ///
295b0d29bc4SBrooks Davis /// \return A metadata tree.  This object is statically allocated so it is
296b0d29bc4SBrooks Davis /// acceptable to obtain references to it and its members.
297b0d29bc4SBrooks Davis const config::tree&
get_defaults(void)298b0d29bc4SBrooks Davis get_defaults(void)
299b0d29bc4SBrooks Davis {
300b0d29bc4SBrooks Davis     if (!defaults) {
301b0d29bc4SBrooks Davis         config::tree props;
302b0d29bc4SBrooks Davis         init_tree(props);
303b0d29bc4SBrooks Davis         set_defaults(props);
304b0d29bc4SBrooks Davis         defaults = props;
305b0d29bc4SBrooks Davis     }
306b0d29bc4SBrooks Davis     return defaults.get();
307b0d29bc4SBrooks Davis }
308b0d29bc4SBrooks Davis 
309b0d29bc4SBrooks Davis 
310b0d29bc4SBrooks Davis /// Looks up a value in a tree with error rewriting.
311b0d29bc4SBrooks Davis ///
312b0d29bc4SBrooks Davis /// \tparam NodeType The type of the node.
313b0d29bc4SBrooks Davis /// \param tree The tree in which to insert the value.
314b0d29bc4SBrooks Davis /// \param key The key to set.
315b0d29bc4SBrooks Davis ///
316b0d29bc4SBrooks Davis /// \return A read-write reference to the value in the node.
317b0d29bc4SBrooks Davis ///
318b0d29bc4SBrooks Davis /// \throw model::error If the key is not known or if the value is not valid.
319b0d29bc4SBrooks Davis template< class NodeType >
320b0d29bc4SBrooks Davis typename NodeType::value_type&
lookup_rw(config::tree & tree,const std::string & key)321b0d29bc4SBrooks Davis lookup_rw(config::tree& tree, const std::string& key)
322b0d29bc4SBrooks Davis {
323b0d29bc4SBrooks Davis     try {
324b0d29bc4SBrooks Davis         return tree.lookup_rw< NodeType >(key);
325b0d29bc4SBrooks Davis     } catch (const config::unknown_key_error& e) {
326b0d29bc4SBrooks Davis         throw model::error(F("Unknown metadata property %s") % key);
327b0d29bc4SBrooks Davis     } catch (const config::value_error& e) {
328b0d29bc4SBrooks Davis         throw model::error(F("Invalid value for metadata property %s: %s") %
329b0d29bc4SBrooks Davis                             key % e.what());
330b0d29bc4SBrooks Davis     }
331b0d29bc4SBrooks Davis }
332b0d29bc4SBrooks Davis 
333b0d29bc4SBrooks Davis 
334b0d29bc4SBrooks Davis /// Sets a value in a tree with error rewriting.
335b0d29bc4SBrooks Davis ///
336b0d29bc4SBrooks Davis /// \tparam NodeType The type of the node.
337b0d29bc4SBrooks Davis /// \param tree The tree in which to insert the value.
338b0d29bc4SBrooks Davis /// \param key The key to set.
339b0d29bc4SBrooks Davis /// \param value The value to set the node to.
340b0d29bc4SBrooks Davis ///
341b0d29bc4SBrooks Davis /// \throw model::error If the key is not known or if the value is not valid.
342b0d29bc4SBrooks Davis template< class NodeType >
343b0d29bc4SBrooks Davis void
set(config::tree & tree,const std::string & key,const typename NodeType::value_type & value)344b0d29bc4SBrooks Davis set(config::tree& tree, const std::string& key,
345b0d29bc4SBrooks Davis     const typename NodeType::value_type& value)
346b0d29bc4SBrooks Davis {
347b0d29bc4SBrooks Davis     try {
348b0d29bc4SBrooks Davis         tree.set< NodeType >(key, value);
349b0d29bc4SBrooks Davis     } catch (const config::unknown_key_error& e) {
350b0d29bc4SBrooks Davis         throw model::error(F("Unknown metadata property %s") % key);
351b0d29bc4SBrooks Davis     } catch (const config::value_error& e) {
352b0d29bc4SBrooks Davis         throw model::error(F("Invalid value for metadata property %s: %s") %
353b0d29bc4SBrooks Davis                             key % e.what());
354b0d29bc4SBrooks Davis     }
355b0d29bc4SBrooks Davis }
356b0d29bc4SBrooks Davis 
357b0d29bc4SBrooks Davis 
358b0d29bc4SBrooks Davis }  // anonymous namespace
359b0d29bc4SBrooks Davis 
360b0d29bc4SBrooks Davis 
361b0d29bc4SBrooks Davis /// Internal implementation of the metadata class.
362b0d29bc4SBrooks Davis struct model::metadata::impl : utils::noncopyable {
363b0d29bc4SBrooks Davis     /// Metadata properties.
364b0d29bc4SBrooks Davis     config::tree props;
365b0d29bc4SBrooks Davis 
366b0d29bc4SBrooks Davis     /// Constructor.
367b0d29bc4SBrooks Davis     ///
368b0d29bc4SBrooks Davis     /// \param props_ Metadata properties of the test.
implmodel::metadata::impl369b0d29bc4SBrooks Davis     impl(const utils::config::tree& props_) :
370b0d29bc4SBrooks Davis         props(props_)
371b0d29bc4SBrooks Davis     {
372b0d29bc4SBrooks Davis     }
373b0d29bc4SBrooks Davis 
374b0d29bc4SBrooks Davis     /// Equality comparator.
375b0d29bc4SBrooks Davis     ///
376b0d29bc4SBrooks Davis     /// \param other The other object to compare this one to.
377b0d29bc4SBrooks Davis     ///
378b0d29bc4SBrooks Davis     /// \return True if this object and other are equal; false otherwise.
379b0d29bc4SBrooks Davis     bool
operator ==model::metadata::impl380b0d29bc4SBrooks Davis     operator==(const impl& other) const
381b0d29bc4SBrooks Davis     {
382b0d29bc4SBrooks Davis         return (get_defaults().combine(props) ==
383b0d29bc4SBrooks Davis                 get_defaults().combine(other.props));
384b0d29bc4SBrooks Davis     }
385b0d29bc4SBrooks Davis };
386b0d29bc4SBrooks Davis 
387b0d29bc4SBrooks Davis 
388b0d29bc4SBrooks Davis /// Constructor.
389b0d29bc4SBrooks Davis ///
390b0d29bc4SBrooks Davis /// \param props Metadata properties of the test.
metadata(const utils::config::tree & props)391b0d29bc4SBrooks Davis model::metadata::metadata(const utils::config::tree& props) :
392b0d29bc4SBrooks Davis     _pimpl(new impl(props))
393b0d29bc4SBrooks Davis {
394b0d29bc4SBrooks Davis }
395b0d29bc4SBrooks Davis 
396b0d29bc4SBrooks Davis 
397b0d29bc4SBrooks Davis /// Destructor.
~metadata(void)398b0d29bc4SBrooks Davis model::metadata::~metadata(void)
399b0d29bc4SBrooks Davis {
400b0d29bc4SBrooks Davis }
401b0d29bc4SBrooks Davis 
402b0d29bc4SBrooks Davis 
403b0d29bc4SBrooks Davis /// Applies a set of overrides to this metadata object.
404b0d29bc4SBrooks Davis ///
405b0d29bc4SBrooks Davis /// \param overrides The overrides to apply.  Any values explicitly set in this
406b0d29bc4SBrooks Davis ///     other object will override any possible values set in this object.
407b0d29bc4SBrooks Davis ///
408b0d29bc4SBrooks Davis /// \return A new metadata object with the combination.
409b0d29bc4SBrooks Davis model::metadata
apply_overrides(const metadata & overrides) const410b0d29bc4SBrooks Davis model::metadata::apply_overrides(const metadata& overrides) const
411b0d29bc4SBrooks Davis {
412b0d29bc4SBrooks Davis     return metadata(_pimpl->props.combine(overrides._pimpl->props));
413b0d29bc4SBrooks Davis }
414b0d29bc4SBrooks Davis 
415b0d29bc4SBrooks Davis 
416b0d29bc4SBrooks Davis /// Returns the architectures allowed by the test.
417b0d29bc4SBrooks Davis ///
418b0d29bc4SBrooks Davis /// \return Set of architectures, or empty if this does not apply.
419b0d29bc4SBrooks Davis const model::strings_set&
allowed_architectures(void) const420b0d29bc4SBrooks Davis model::metadata::allowed_architectures(void) const
421b0d29bc4SBrooks Davis {
422b0d29bc4SBrooks Davis     if (_pimpl->props.is_set("allowed_architectures")) {
423b0d29bc4SBrooks Davis         return _pimpl->props.lookup< config::strings_set_node >(
424b0d29bc4SBrooks Davis             "allowed_architectures");
425b0d29bc4SBrooks Davis     } else {
426b0d29bc4SBrooks Davis         return get_defaults().lookup< config::strings_set_node >(
427b0d29bc4SBrooks Davis             "allowed_architectures");
428b0d29bc4SBrooks Davis     }
429b0d29bc4SBrooks Davis }
430b0d29bc4SBrooks Davis 
431b0d29bc4SBrooks Davis 
432b0d29bc4SBrooks Davis /// Returns the platforms allowed by the test.
433b0d29bc4SBrooks Davis ///
434b0d29bc4SBrooks Davis /// \return Set of platforms, or empty if this does not apply.
435b0d29bc4SBrooks Davis const model::strings_set&
allowed_platforms(void) const436b0d29bc4SBrooks Davis model::metadata::allowed_platforms(void) const
437b0d29bc4SBrooks Davis {
438b0d29bc4SBrooks Davis     if (_pimpl->props.is_set("allowed_platforms")) {
439b0d29bc4SBrooks Davis         return _pimpl->props.lookup< config::strings_set_node >(
440b0d29bc4SBrooks Davis             "allowed_platforms");
441b0d29bc4SBrooks Davis     } else {
442b0d29bc4SBrooks Davis         return get_defaults().lookup< config::strings_set_node >(
443b0d29bc4SBrooks Davis             "allowed_platforms");
444b0d29bc4SBrooks Davis     }
445b0d29bc4SBrooks Davis }
446b0d29bc4SBrooks Davis 
447b0d29bc4SBrooks Davis 
448b0d29bc4SBrooks Davis /// Returns all the user-defined metadata properties.
449b0d29bc4SBrooks Davis ///
450b0d29bc4SBrooks Davis /// \return A key/value map of properties.
451b0d29bc4SBrooks Davis model::properties_map
custom(void) const452b0d29bc4SBrooks Davis model::metadata::custom(void) const
453b0d29bc4SBrooks Davis {
454b0d29bc4SBrooks Davis     return _pimpl->props.all_properties("custom", true);
455b0d29bc4SBrooks Davis }
456b0d29bc4SBrooks Davis 
457b0d29bc4SBrooks Davis 
458b0d29bc4SBrooks Davis /// Returns the description of the test.
459b0d29bc4SBrooks Davis ///
460b0d29bc4SBrooks Davis /// \return Textual description; may be empty.
461b0d29bc4SBrooks Davis const std::string&
description(void) const462b0d29bc4SBrooks Davis model::metadata::description(void) const
463b0d29bc4SBrooks Davis {
464b0d29bc4SBrooks Davis     if (_pimpl->props.is_set("description")) {
465b0d29bc4SBrooks Davis         return _pimpl->props.lookup< config::string_node >("description");
466b0d29bc4SBrooks Davis     } else {
467b0d29bc4SBrooks Davis         return get_defaults().lookup< config::string_node >("description");
468b0d29bc4SBrooks Davis     }
469b0d29bc4SBrooks Davis }
470b0d29bc4SBrooks Davis 
471b0d29bc4SBrooks Davis 
472*257e70f1SIgor Ostapenko /// Returns execution environment name.
473*257e70f1SIgor Ostapenko ///
474*257e70f1SIgor Ostapenko /// \return Name of configured execution environment.
475*257e70f1SIgor Ostapenko const std::string&
execenv(void) const476*257e70f1SIgor Ostapenko model::metadata::execenv(void) const
477*257e70f1SIgor Ostapenko {
478*257e70f1SIgor Ostapenko     if (_pimpl->props.is_set("execenv")) {
479*257e70f1SIgor Ostapenko         return _pimpl->props.lookup< config::string_node >("execenv");
480*257e70f1SIgor Ostapenko     } else {
481*257e70f1SIgor Ostapenko         return get_defaults().lookup< config::string_node >("execenv");
482*257e70f1SIgor Ostapenko     }
483*257e70f1SIgor Ostapenko }
484*257e70f1SIgor Ostapenko 
485*257e70f1SIgor Ostapenko 
486*257e70f1SIgor Ostapenko /// Returns execenv jail(8) parameters string to run a test with.
487*257e70f1SIgor Ostapenko ///
488*257e70f1SIgor Ostapenko /// \return String of jail parameters.
489*257e70f1SIgor Ostapenko const std::string&
execenv_jail_params(void) const490*257e70f1SIgor Ostapenko model::metadata::execenv_jail_params(void) const
491*257e70f1SIgor Ostapenko {
492*257e70f1SIgor Ostapenko     if (_pimpl->props.is_set("execenv_jail_params")) {
493*257e70f1SIgor Ostapenko         return _pimpl->props.lookup< config::string_node >(
494*257e70f1SIgor Ostapenko             "execenv_jail_params");
495*257e70f1SIgor Ostapenko     } else {
496*257e70f1SIgor Ostapenko         return get_defaults().lookup< config::string_node >(
497*257e70f1SIgor Ostapenko             "execenv_jail_params");
498*257e70f1SIgor Ostapenko     }
499*257e70f1SIgor Ostapenko }
500*257e70f1SIgor Ostapenko 
501*257e70f1SIgor Ostapenko 
502b0d29bc4SBrooks Davis /// Returns whether the test has a cleanup part or not.
503b0d29bc4SBrooks Davis ///
504b0d29bc4SBrooks Davis /// \return True if there is a cleanup part; false otherwise.
505b0d29bc4SBrooks Davis bool
has_cleanup(void) const506b0d29bc4SBrooks Davis model::metadata::has_cleanup(void) const
507b0d29bc4SBrooks Davis {
508b0d29bc4SBrooks Davis     if (_pimpl->props.is_set("has_cleanup")) {
509b0d29bc4SBrooks Davis         return _pimpl->props.lookup< config::bool_node >("has_cleanup");
510b0d29bc4SBrooks Davis     } else {
511b0d29bc4SBrooks Davis         return get_defaults().lookup< config::bool_node >("has_cleanup");
512b0d29bc4SBrooks Davis     }
513b0d29bc4SBrooks Davis }
514b0d29bc4SBrooks Davis 
515b0d29bc4SBrooks Davis 
516*257e70f1SIgor Ostapenko /// Returns whether the test has a specific execenv apart from default one.
517*257e70f1SIgor Ostapenko ///
518*257e70f1SIgor Ostapenko /// \return True if there is a non-host execenv configured; false otherwise.
519*257e70f1SIgor Ostapenko bool
has_execenv(void) const520*257e70f1SIgor Ostapenko model::metadata::has_execenv(void) const
521*257e70f1SIgor Ostapenko {
522*257e70f1SIgor Ostapenko     const std::string& name = execenv();
523*257e70f1SIgor Ostapenko     return !name.empty() && name != engine::execenv::default_execenv_name;
524*257e70f1SIgor Ostapenko }
525*257e70f1SIgor Ostapenko 
526*257e70f1SIgor Ostapenko 
527b0d29bc4SBrooks Davis /// Returns whether the test is exclusive or not.
528b0d29bc4SBrooks Davis ///
529b0d29bc4SBrooks Davis /// \return True if the test has to be run on its own, not concurrently with any
530b0d29bc4SBrooks Davis /// other tests; false otherwise.
531b0d29bc4SBrooks Davis bool
is_exclusive(void) const532b0d29bc4SBrooks Davis model::metadata::is_exclusive(void) const
533b0d29bc4SBrooks Davis {
534b0d29bc4SBrooks Davis     if (_pimpl->props.is_set("is_exclusive")) {
535b0d29bc4SBrooks Davis         return _pimpl->props.lookup< config::bool_node >("is_exclusive");
536b0d29bc4SBrooks Davis     } else {
537b0d29bc4SBrooks Davis         return get_defaults().lookup< config::bool_node >("is_exclusive");
538b0d29bc4SBrooks Davis     }
539b0d29bc4SBrooks Davis }
540b0d29bc4SBrooks Davis 
541b0d29bc4SBrooks Davis 
542b0d29bc4SBrooks Davis /// Returns the list of configuration variables needed by the test.
543b0d29bc4SBrooks Davis ///
544b0d29bc4SBrooks Davis /// \return Set of configuration variables.
545b0d29bc4SBrooks Davis const model::strings_set&
required_configs(void) const546b0d29bc4SBrooks Davis model::metadata::required_configs(void) const
547b0d29bc4SBrooks Davis {
548b0d29bc4SBrooks Davis     if (_pimpl->props.is_set("required_configs")) {
549b0d29bc4SBrooks Davis         return _pimpl->props.lookup< config::strings_set_node >(
550b0d29bc4SBrooks Davis             "required_configs");
551b0d29bc4SBrooks Davis     } else {
552b0d29bc4SBrooks Davis         return get_defaults().lookup< config::strings_set_node >(
553b0d29bc4SBrooks Davis             "required_configs");
554b0d29bc4SBrooks Davis     }
555b0d29bc4SBrooks Davis }
556b0d29bc4SBrooks Davis 
557b0d29bc4SBrooks Davis 
558b0d29bc4SBrooks Davis /// Returns the amount of free disk space required by the test.
559b0d29bc4SBrooks Davis ///
560b0d29bc4SBrooks Davis /// \return Number of bytes, or 0 if this does not apply.
561b0d29bc4SBrooks Davis const units::bytes&
required_disk_space(void) const562b0d29bc4SBrooks Davis model::metadata::required_disk_space(void) const
563b0d29bc4SBrooks Davis {
564b0d29bc4SBrooks Davis     if (_pimpl->props.is_set("required_disk_space")) {
565b0d29bc4SBrooks Davis         return _pimpl->props.lookup< bytes_node >("required_disk_space");
566b0d29bc4SBrooks Davis     } else {
567b0d29bc4SBrooks Davis         return get_defaults().lookup< bytes_node >("required_disk_space");
568b0d29bc4SBrooks Davis     }
569b0d29bc4SBrooks Davis }
570b0d29bc4SBrooks Davis 
571b0d29bc4SBrooks Davis 
572b0d29bc4SBrooks Davis /// Returns the list of files needed by the test.
573b0d29bc4SBrooks Davis ///
574b0d29bc4SBrooks Davis /// \return Set of paths.
575b0d29bc4SBrooks Davis const model::paths_set&
required_files(void) const576b0d29bc4SBrooks Davis model::metadata::required_files(void) const
577b0d29bc4SBrooks Davis {
578b0d29bc4SBrooks Davis     if (_pimpl->props.is_set("required_files")) {
579b0d29bc4SBrooks Davis         return _pimpl->props.lookup< paths_set_node >("required_files");
580b0d29bc4SBrooks Davis     } else {
581b0d29bc4SBrooks Davis         return get_defaults().lookup< paths_set_node >("required_files");
582b0d29bc4SBrooks Davis     }
583b0d29bc4SBrooks Davis }
584b0d29bc4SBrooks Davis 
585b0d29bc4SBrooks Davis 
586b0d29bc4SBrooks Davis /// Returns the amount of memory required by the test.
587b0d29bc4SBrooks Davis ///
588b0d29bc4SBrooks Davis /// \return Number of bytes, or 0 if this does not apply.
589b0d29bc4SBrooks Davis const units::bytes&
required_memory(void) const590b0d29bc4SBrooks Davis model::metadata::required_memory(void) const
591b0d29bc4SBrooks Davis {
592b0d29bc4SBrooks Davis     if (_pimpl->props.is_set("required_memory")) {
593b0d29bc4SBrooks Davis         return _pimpl->props.lookup< bytes_node >("required_memory");
594b0d29bc4SBrooks Davis     } else {
595b0d29bc4SBrooks Davis         return get_defaults().lookup< bytes_node >("required_memory");
596b0d29bc4SBrooks Davis     }
597b0d29bc4SBrooks Davis }
598b0d29bc4SBrooks Davis 
599b0d29bc4SBrooks Davis 
600b0d29bc4SBrooks Davis /// Returns the list of programs needed by the test.
601b0d29bc4SBrooks Davis ///
602b0d29bc4SBrooks Davis /// \return Set of paths.
603b0d29bc4SBrooks Davis const model::paths_set&
required_programs(void) const604b0d29bc4SBrooks Davis model::metadata::required_programs(void) const
605b0d29bc4SBrooks Davis {
606b0d29bc4SBrooks Davis     if (_pimpl->props.is_set("required_programs")) {
607b0d29bc4SBrooks Davis         return _pimpl->props.lookup< paths_set_node >("required_programs");
608b0d29bc4SBrooks Davis     } else {
609b0d29bc4SBrooks Davis         return get_defaults().lookup< paths_set_node >("required_programs");
610b0d29bc4SBrooks Davis     }
611b0d29bc4SBrooks Davis }
612b0d29bc4SBrooks Davis 
613b0d29bc4SBrooks Davis 
614b0d29bc4SBrooks Davis /// Returns the user required by the test.
615b0d29bc4SBrooks Davis ///
616b0d29bc4SBrooks Davis /// \return One of unprivileged, root or empty.
617b0d29bc4SBrooks Davis const std::string&
required_user(void) const618b0d29bc4SBrooks Davis model::metadata::required_user(void) const
619b0d29bc4SBrooks Davis {
620b0d29bc4SBrooks Davis     if (_pimpl->props.is_set("required_user")) {
621b0d29bc4SBrooks Davis         return _pimpl->props.lookup< user_node >("required_user");
622b0d29bc4SBrooks Davis     } else {
623b0d29bc4SBrooks Davis         return get_defaults().lookup< user_node >("required_user");
624b0d29bc4SBrooks Davis     }
625b0d29bc4SBrooks Davis }
626b0d29bc4SBrooks Davis 
627b0d29bc4SBrooks Davis 
628b0d29bc4SBrooks Davis /// Returns the timeout of the test.
629b0d29bc4SBrooks Davis ///
630b0d29bc4SBrooks Davis /// \return A time delta; should be compared to default_timeout to see if it has
631b0d29bc4SBrooks Davis /// been overriden.
632b0d29bc4SBrooks Davis const datetime::delta&
timeout(void) const633b0d29bc4SBrooks Davis model::metadata::timeout(void) const
634b0d29bc4SBrooks Davis {
635b0d29bc4SBrooks Davis     if (_pimpl->props.is_set("timeout")) {
636b0d29bc4SBrooks Davis         return _pimpl->props.lookup< delta_node >("timeout");
637b0d29bc4SBrooks Davis     } else {
638b0d29bc4SBrooks Davis         return get_defaults().lookup< delta_node >("timeout");
639b0d29bc4SBrooks Davis     }
640b0d29bc4SBrooks Davis }
641b0d29bc4SBrooks Davis 
642b0d29bc4SBrooks Davis 
643b0d29bc4SBrooks Davis /// Externalizes the metadata to a set of key/value textual pairs.
644b0d29bc4SBrooks Davis ///
645b0d29bc4SBrooks Davis /// \return A key/value representation of the metadata.
646b0d29bc4SBrooks Davis model::properties_map
to_properties(void) const647b0d29bc4SBrooks Davis model::metadata::to_properties(void) const
648b0d29bc4SBrooks Davis {
649b0d29bc4SBrooks Davis     const config::tree fully_specified = get_defaults().combine(_pimpl->props);
650b0d29bc4SBrooks Davis     return fully_specified.all_properties();
651b0d29bc4SBrooks Davis }
652b0d29bc4SBrooks Davis 
653b0d29bc4SBrooks Davis 
654b0d29bc4SBrooks Davis /// Equality comparator.
655b0d29bc4SBrooks Davis ///
656b0d29bc4SBrooks Davis /// \param other The other object to compare this one to.
657b0d29bc4SBrooks Davis ///
658b0d29bc4SBrooks Davis /// \return True if this object and other are equal; false otherwise.
659b0d29bc4SBrooks Davis bool
operator ==(const metadata & other) const660b0d29bc4SBrooks Davis model::metadata::operator==(const metadata& other) const
661b0d29bc4SBrooks Davis {
662b0d29bc4SBrooks Davis     return _pimpl == other._pimpl || *_pimpl == *other._pimpl;
663b0d29bc4SBrooks Davis }
664b0d29bc4SBrooks Davis 
665b0d29bc4SBrooks Davis 
666b0d29bc4SBrooks Davis /// Inequality comparator.
667b0d29bc4SBrooks Davis ///
668b0d29bc4SBrooks Davis /// \param other The other object to compare this one to.
669b0d29bc4SBrooks Davis ///
670b0d29bc4SBrooks Davis /// \return True if this object and other are different; false otherwise.
671b0d29bc4SBrooks Davis bool
operator !=(const metadata & other) const672b0d29bc4SBrooks Davis model::metadata::operator!=(const metadata& other) const
673b0d29bc4SBrooks Davis {
674b0d29bc4SBrooks Davis     return !(*this == other);
675b0d29bc4SBrooks Davis }
676b0d29bc4SBrooks Davis 
677b0d29bc4SBrooks Davis 
678b0d29bc4SBrooks Davis /// Injects the object into a stream.
679b0d29bc4SBrooks Davis ///
680b0d29bc4SBrooks Davis /// \param output The stream into which to inject the object.
681b0d29bc4SBrooks Davis /// \param object The object to format.
682b0d29bc4SBrooks Davis ///
683b0d29bc4SBrooks Davis /// \return The output stream.
684b0d29bc4SBrooks Davis std::ostream&
operator <<(std::ostream & output,const metadata & object)685b0d29bc4SBrooks Davis model::operator<<(std::ostream& output, const metadata& object)
686b0d29bc4SBrooks Davis {
687b0d29bc4SBrooks Davis     output << "metadata{";
688b0d29bc4SBrooks Davis 
689b0d29bc4SBrooks Davis     bool first = true;
690b0d29bc4SBrooks Davis     const model::properties_map props = object.to_properties();
691b0d29bc4SBrooks Davis     for (model::properties_map::const_iterator iter = props.begin();
692b0d29bc4SBrooks Davis          iter != props.end(); ++iter) {
693b0d29bc4SBrooks Davis         if (!first)
694b0d29bc4SBrooks Davis             output << ", ";
695b0d29bc4SBrooks Davis         output << F("%s=%s") % (*iter).first %
696b0d29bc4SBrooks Davis             text::quote((*iter).second, '\'');
697b0d29bc4SBrooks Davis         first = false;
698b0d29bc4SBrooks Davis     }
699b0d29bc4SBrooks Davis 
700b0d29bc4SBrooks Davis     output << "}";
701b0d29bc4SBrooks Davis     return output;
702b0d29bc4SBrooks Davis }
703b0d29bc4SBrooks Davis 
704b0d29bc4SBrooks Davis 
705b0d29bc4SBrooks Davis /// Internal implementation of the metadata_builder class.
706b0d29bc4SBrooks Davis struct model::metadata_builder::impl : utils::noncopyable {
707b0d29bc4SBrooks Davis     /// Collection of requirements.
708b0d29bc4SBrooks Davis     config::tree props;
709b0d29bc4SBrooks Davis 
710b0d29bc4SBrooks Davis     /// Whether we have created a metadata object or not.
711b0d29bc4SBrooks Davis     bool built;
712b0d29bc4SBrooks Davis 
713b0d29bc4SBrooks Davis     /// Constructor.
implmodel::metadata_builder::impl714b0d29bc4SBrooks Davis     impl(void) :
715b0d29bc4SBrooks Davis         built(false)
716b0d29bc4SBrooks Davis     {
717b0d29bc4SBrooks Davis         init_tree(props);
718b0d29bc4SBrooks Davis     }
719b0d29bc4SBrooks Davis 
720b0d29bc4SBrooks Davis     /// Constructor.
721b0d29bc4SBrooks Davis     ///
722b0d29bc4SBrooks Davis     /// \param base The base model to construct a copy from.
implmodel::metadata_builder::impl723b0d29bc4SBrooks Davis     impl(const model::metadata& base) :
724b0d29bc4SBrooks Davis         props(base._pimpl->props.deep_copy()),
725b0d29bc4SBrooks Davis         built(false)
726b0d29bc4SBrooks Davis     {
727b0d29bc4SBrooks Davis     }
728b0d29bc4SBrooks Davis };
729b0d29bc4SBrooks Davis 
730b0d29bc4SBrooks Davis 
731b0d29bc4SBrooks Davis /// Constructor.
metadata_builder(void)732b0d29bc4SBrooks Davis model::metadata_builder::metadata_builder(void) :
733b0d29bc4SBrooks Davis     _pimpl(new impl())
734b0d29bc4SBrooks Davis {
735b0d29bc4SBrooks Davis }
736b0d29bc4SBrooks Davis 
737b0d29bc4SBrooks Davis 
738b0d29bc4SBrooks Davis /// Constructor.
metadata_builder(const model::metadata & base)739b0d29bc4SBrooks Davis model::metadata_builder::metadata_builder(const model::metadata& base) :
740b0d29bc4SBrooks Davis     _pimpl(new impl(base))
741b0d29bc4SBrooks Davis {
742b0d29bc4SBrooks Davis }
743b0d29bc4SBrooks Davis 
744b0d29bc4SBrooks Davis 
745b0d29bc4SBrooks Davis /// Destructor.
~metadata_builder(void)746b0d29bc4SBrooks Davis model::metadata_builder::~metadata_builder(void)
747b0d29bc4SBrooks Davis {
748b0d29bc4SBrooks Davis }
749b0d29bc4SBrooks Davis 
750b0d29bc4SBrooks Davis 
751b0d29bc4SBrooks Davis /// Accumulates an additional allowed architecture.
752b0d29bc4SBrooks Davis ///
753b0d29bc4SBrooks Davis /// \param arch The architecture.
754b0d29bc4SBrooks Davis ///
755b0d29bc4SBrooks Davis /// \return A reference to this builder.
756b0d29bc4SBrooks Davis ///
757b0d29bc4SBrooks Davis /// \throw model::error If the value is invalid.
758b0d29bc4SBrooks Davis model::metadata_builder&
add_allowed_architecture(const std::string & arch)759b0d29bc4SBrooks Davis model::metadata_builder::add_allowed_architecture(const std::string& arch)
760b0d29bc4SBrooks Davis {
761b0d29bc4SBrooks Davis     if (!_pimpl->props.is_set("allowed_architectures")) {
762b0d29bc4SBrooks Davis         _pimpl->props.set< config::strings_set_node >(
763b0d29bc4SBrooks Davis             "allowed_architectures",
764b0d29bc4SBrooks Davis             get_defaults().lookup< config::strings_set_node >(
765b0d29bc4SBrooks Davis                 "allowed_architectures"));
766b0d29bc4SBrooks Davis     }
767b0d29bc4SBrooks Davis     lookup_rw< config::strings_set_node >(
768b0d29bc4SBrooks Davis         _pimpl->props, "allowed_architectures").insert(arch);
769b0d29bc4SBrooks Davis     return *this;
770b0d29bc4SBrooks Davis }
771b0d29bc4SBrooks Davis 
772b0d29bc4SBrooks Davis 
773b0d29bc4SBrooks Davis /// Accumulates an additional allowed platform.
774b0d29bc4SBrooks Davis ///
775b0d29bc4SBrooks Davis /// \param platform The platform.
776b0d29bc4SBrooks Davis ///
777b0d29bc4SBrooks Davis /// \return A reference to this builder.
778b0d29bc4SBrooks Davis ///
779b0d29bc4SBrooks Davis /// \throw model::error If the value is invalid.
780b0d29bc4SBrooks Davis model::metadata_builder&
add_allowed_platform(const std::string & platform)781b0d29bc4SBrooks Davis model::metadata_builder::add_allowed_platform(const std::string& platform)
782b0d29bc4SBrooks Davis {
783b0d29bc4SBrooks Davis     if (!_pimpl->props.is_set("allowed_platforms")) {
784b0d29bc4SBrooks Davis         _pimpl->props.set< config::strings_set_node >(
785b0d29bc4SBrooks Davis             "allowed_platforms",
786b0d29bc4SBrooks Davis             get_defaults().lookup< config::strings_set_node >(
787b0d29bc4SBrooks Davis                 "allowed_platforms"));
788b0d29bc4SBrooks Davis     }
789b0d29bc4SBrooks Davis     lookup_rw< config::strings_set_node >(
790b0d29bc4SBrooks Davis         _pimpl->props, "allowed_platforms").insert(platform);
791b0d29bc4SBrooks Davis     return *this;
792b0d29bc4SBrooks Davis }
793b0d29bc4SBrooks Davis 
794b0d29bc4SBrooks Davis 
795b0d29bc4SBrooks Davis /// Accumulates a single user-defined property.
796b0d29bc4SBrooks Davis ///
797b0d29bc4SBrooks Davis /// \param key Name of the property to define.
798b0d29bc4SBrooks Davis /// \param value Value of the property.
799b0d29bc4SBrooks Davis ///
800b0d29bc4SBrooks Davis /// \return A reference to this builder.
801b0d29bc4SBrooks Davis ///
802b0d29bc4SBrooks Davis /// \throw model::error If the value is invalid.
803b0d29bc4SBrooks Davis model::metadata_builder&
add_custom(const std::string & key,const std::string & value)804b0d29bc4SBrooks Davis model::metadata_builder::add_custom(const std::string& key,
805b0d29bc4SBrooks Davis                                      const std::string& value)
806b0d29bc4SBrooks Davis {
807b0d29bc4SBrooks Davis     _pimpl->props.set_string(F("custom.%s") % key, value);
808b0d29bc4SBrooks Davis     return *this;
809b0d29bc4SBrooks Davis }
810b0d29bc4SBrooks Davis 
811b0d29bc4SBrooks Davis 
812b0d29bc4SBrooks Davis /// Accumulates an additional required configuration variable.
813b0d29bc4SBrooks Davis ///
814b0d29bc4SBrooks Davis /// \param var The name of the configuration variable.
815b0d29bc4SBrooks Davis ///
816b0d29bc4SBrooks Davis /// \return A reference to this builder.
817b0d29bc4SBrooks Davis ///
818b0d29bc4SBrooks Davis /// \throw model::error If the value is invalid.
819b0d29bc4SBrooks Davis model::metadata_builder&
add_required_config(const std::string & var)820b0d29bc4SBrooks Davis model::metadata_builder::add_required_config(const std::string& var)
821b0d29bc4SBrooks Davis {
822b0d29bc4SBrooks Davis     if (!_pimpl->props.is_set("required_configs")) {
823b0d29bc4SBrooks Davis         _pimpl->props.set< config::strings_set_node >(
824b0d29bc4SBrooks Davis             "required_configs",
825b0d29bc4SBrooks Davis             get_defaults().lookup< config::strings_set_node >(
826b0d29bc4SBrooks Davis                 "required_configs"));
827b0d29bc4SBrooks Davis     }
828b0d29bc4SBrooks Davis     lookup_rw< config::strings_set_node >(
829b0d29bc4SBrooks Davis         _pimpl->props, "required_configs").insert(var);
830b0d29bc4SBrooks Davis     return *this;
831b0d29bc4SBrooks Davis }
832b0d29bc4SBrooks Davis 
833b0d29bc4SBrooks Davis 
834b0d29bc4SBrooks Davis /// Accumulates an additional required file.
835b0d29bc4SBrooks Davis ///
836b0d29bc4SBrooks Davis /// \param path The path to the file.
837b0d29bc4SBrooks Davis ///
838b0d29bc4SBrooks Davis /// \return A reference to this builder.
839b0d29bc4SBrooks Davis ///
840b0d29bc4SBrooks Davis /// \throw model::error If the value is invalid.
841b0d29bc4SBrooks Davis model::metadata_builder&
add_required_file(const fs::path & path)842b0d29bc4SBrooks Davis model::metadata_builder::add_required_file(const fs::path& path)
843b0d29bc4SBrooks Davis {
844b0d29bc4SBrooks Davis     if (!_pimpl->props.is_set("required_files")) {
845b0d29bc4SBrooks Davis         _pimpl->props.set< paths_set_node >(
846b0d29bc4SBrooks Davis             "required_files",
847b0d29bc4SBrooks Davis             get_defaults().lookup< paths_set_node >("required_files"));
848b0d29bc4SBrooks Davis     }
849b0d29bc4SBrooks Davis     lookup_rw< paths_set_node >(_pimpl->props, "required_files").insert(path);
850b0d29bc4SBrooks Davis     return *this;
851b0d29bc4SBrooks Davis }
852b0d29bc4SBrooks Davis 
853b0d29bc4SBrooks Davis 
854b0d29bc4SBrooks Davis /// Accumulates an additional required program.
855b0d29bc4SBrooks Davis ///
856b0d29bc4SBrooks Davis /// \param path The path to the program.
857b0d29bc4SBrooks Davis ///
858b0d29bc4SBrooks Davis /// \return A reference to this builder.
859b0d29bc4SBrooks Davis ///
860b0d29bc4SBrooks Davis /// \throw model::error If the value is invalid.
861b0d29bc4SBrooks Davis model::metadata_builder&
add_required_program(const fs::path & path)862b0d29bc4SBrooks Davis model::metadata_builder::add_required_program(const fs::path& path)
863b0d29bc4SBrooks Davis {
864b0d29bc4SBrooks Davis     if (!_pimpl->props.is_set("required_programs")) {
865b0d29bc4SBrooks Davis         _pimpl->props.set< paths_set_node >(
866b0d29bc4SBrooks Davis             "required_programs",
867b0d29bc4SBrooks Davis             get_defaults().lookup< paths_set_node >("required_programs"));
868b0d29bc4SBrooks Davis     }
869b0d29bc4SBrooks Davis     lookup_rw< paths_set_node >(_pimpl->props,
870b0d29bc4SBrooks Davis                                 "required_programs").insert(path);
871b0d29bc4SBrooks Davis     return *this;
872b0d29bc4SBrooks Davis }
873b0d29bc4SBrooks Davis 
874b0d29bc4SBrooks Davis 
875b0d29bc4SBrooks Davis /// Sets the architectures allowed by the test.
876b0d29bc4SBrooks Davis ///
877b0d29bc4SBrooks Davis /// \param as Set of architectures.
878b0d29bc4SBrooks Davis ///
879b0d29bc4SBrooks Davis /// \return A reference to this builder.
880b0d29bc4SBrooks Davis ///
881b0d29bc4SBrooks Davis /// \throw model::error If the value is invalid.
882b0d29bc4SBrooks Davis model::metadata_builder&
set_allowed_architectures(const model::strings_set & as)883b0d29bc4SBrooks Davis model::metadata_builder::set_allowed_architectures(
884b0d29bc4SBrooks Davis     const model::strings_set& as)
885b0d29bc4SBrooks Davis {
886b0d29bc4SBrooks Davis     set< config::strings_set_node >(_pimpl->props, "allowed_architectures", as);
887b0d29bc4SBrooks Davis     return *this;
888b0d29bc4SBrooks Davis }
889b0d29bc4SBrooks Davis 
890b0d29bc4SBrooks Davis 
891b0d29bc4SBrooks Davis /// Sets the platforms allowed by the test.
892b0d29bc4SBrooks Davis ///
893b0d29bc4SBrooks Davis /// \return ps Set of platforms.
894b0d29bc4SBrooks Davis ///
895b0d29bc4SBrooks Davis /// \return A reference to this builder.
896b0d29bc4SBrooks Davis ///
897b0d29bc4SBrooks Davis /// \throw model::error If the value is invalid.
898b0d29bc4SBrooks Davis model::metadata_builder&
set_allowed_platforms(const model::strings_set & ps)899b0d29bc4SBrooks Davis model::metadata_builder::set_allowed_platforms(const model::strings_set& ps)
900b0d29bc4SBrooks Davis {
901b0d29bc4SBrooks Davis     set< config::strings_set_node >(_pimpl->props, "allowed_platforms", ps);
902b0d29bc4SBrooks Davis     return *this;
903b0d29bc4SBrooks Davis }
904b0d29bc4SBrooks Davis 
905b0d29bc4SBrooks Davis 
906b0d29bc4SBrooks Davis /// Sets the user-defined properties.
907b0d29bc4SBrooks Davis ///
908b0d29bc4SBrooks Davis /// \param props The custom properties to set.
909b0d29bc4SBrooks Davis ///
910b0d29bc4SBrooks Davis /// \return A reference to this builder.
911b0d29bc4SBrooks Davis ///
912b0d29bc4SBrooks Davis /// \throw model::error If the value is invalid.
913b0d29bc4SBrooks Davis model::metadata_builder&
set_custom(const model::properties_map & props)914b0d29bc4SBrooks Davis model::metadata_builder::set_custom(const model::properties_map& props)
915b0d29bc4SBrooks Davis {
916b0d29bc4SBrooks Davis     for (model::properties_map::const_iterator iter = props.begin();
917b0d29bc4SBrooks Davis          iter != props.end(); ++iter)
918b0d29bc4SBrooks Davis         _pimpl->props.set_string(F("custom.%s") % (*iter).first,
919b0d29bc4SBrooks Davis                                  (*iter).second);
920b0d29bc4SBrooks Davis     return *this;
921b0d29bc4SBrooks Davis }
922b0d29bc4SBrooks Davis 
923b0d29bc4SBrooks Davis 
924b0d29bc4SBrooks Davis /// Sets the description of the test.
925b0d29bc4SBrooks Davis ///
926b0d29bc4SBrooks Davis /// \param description Textual description of the test.
927b0d29bc4SBrooks Davis ///
928b0d29bc4SBrooks Davis /// \return A reference to this builder.
929b0d29bc4SBrooks Davis ///
930b0d29bc4SBrooks Davis /// \throw model::error If the value is invalid.
931b0d29bc4SBrooks Davis model::metadata_builder&
set_description(const std::string & description)932b0d29bc4SBrooks Davis model::metadata_builder::set_description(const std::string& description)
933b0d29bc4SBrooks Davis {
934b0d29bc4SBrooks Davis     set< config::string_node >(_pimpl->props, "description", description);
935b0d29bc4SBrooks Davis     return *this;
936b0d29bc4SBrooks Davis }
937b0d29bc4SBrooks Davis 
938b0d29bc4SBrooks Davis 
939*257e70f1SIgor Ostapenko /// Sets execution environment name.
940*257e70f1SIgor Ostapenko ///
941*257e70f1SIgor Ostapenko /// \param name Execution environment name.
942*257e70f1SIgor Ostapenko ///
943*257e70f1SIgor Ostapenko /// \return A reference to this builder.
944*257e70f1SIgor Ostapenko ///
945*257e70f1SIgor Ostapenko /// \throw model::error If the value is invalid.
946*257e70f1SIgor Ostapenko model::metadata_builder&
set_execenv(const std::string & name)947*257e70f1SIgor Ostapenko model::metadata_builder::set_execenv(const std::string& name)
948*257e70f1SIgor Ostapenko {
949*257e70f1SIgor Ostapenko     set< config::string_node >(_pimpl->props, "execenv", name);
950*257e70f1SIgor Ostapenko     return *this;
951*257e70f1SIgor Ostapenko }
952*257e70f1SIgor Ostapenko 
953*257e70f1SIgor Ostapenko 
954*257e70f1SIgor Ostapenko /// Sets execenv jail(8) parameters string to run the test with.
955*257e70f1SIgor Ostapenko ///
956*257e70f1SIgor Ostapenko /// \param params String of jail parameters.
957*257e70f1SIgor Ostapenko ///
958*257e70f1SIgor Ostapenko /// \return A reference to this builder.
959*257e70f1SIgor Ostapenko ///
960*257e70f1SIgor Ostapenko /// \throw model::error If the value is invalid.
961*257e70f1SIgor Ostapenko model::metadata_builder&
set_execenv_jail_params(const std::string & params)962*257e70f1SIgor Ostapenko model::metadata_builder::set_execenv_jail_params(const std::string& params)
963*257e70f1SIgor Ostapenko {
964*257e70f1SIgor Ostapenko     set< config::string_node >(_pimpl->props, "execenv_jail_params", params);
965*257e70f1SIgor Ostapenko     return *this;
966*257e70f1SIgor Ostapenko }
967*257e70f1SIgor Ostapenko 
968*257e70f1SIgor Ostapenko 
969b0d29bc4SBrooks Davis /// Sets whether the test has a cleanup part or not.
970b0d29bc4SBrooks Davis ///
971b0d29bc4SBrooks Davis /// \param cleanup True if the test has a cleanup part; false otherwise.
972b0d29bc4SBrooks Davis ///
973b0d29bc4SBrooks Davis /// \return A reference to this builder.
974b0d29bc4SBrooks Davis ///
975b0d29bc4SBrooks Davis /// \throw model::error If the value is invalid.
976b0d29bc4SBrooks Davis model::metadata_builder&
set_has_cleanup(const bool cleanup)977b0d29bc4SBrooks Davis model::metadata_builder::set_has_cleanup(const bool cleanup)
978b0d29bc4SBrooks Davis {
979b0d29bc4SBrooks Davis     set< config::bool_node >(_pimpl->props, "has_cleanup", cleanup);
980b0d29bc4SBrooks Davis     return *this;
981b0d29bc4SBrooks Davis }
982b0d29bc4SBrooks Davis 
983b0d29bc4SBrooks Davis 
984b0d29bc4SBrooks Davis /// Sets whether the test is exclusive or not.
985b0d29bc4SBrooks Davis ///
986b0d29bc4SBrooks Davis /// \param exclusive True if the test is exclusive; false otherwise.
987b0d29bc4SBrooks Davis ///
988b0d29bc4SBrooks Davis /// \return A reference to this builder.
989b0d29bc4SBrooks Davis ///
990b0d29bc4SBrooks Davis /// \throw model::error If the value is invalid.
991b0d29bc4SBrooks Davis model::metadata_builder&
set_is_exclusive(const bool exclusive)992b0d29bc4SBrooks Davis model::metadata_builder::set_is_exclusive(const bool exclusive)
993b0d29bc4SBrooks Davis {
994b0d29bc4SBrooks Davis     set< config::bool_node >(_pimpl->props, "is_exclusive", exclusive);
995b0d29bc4SBrooks Davis     return *this;
996b0d29bc4SBrooks Davis }
997b0d29bc4SBrooks Davis 
998b0d29bc4SBrooks Davis 
999b0d29bc4SBrooks Davis /// Sets the list of configuration variables needed by the test.
1000b0d29bc4SBrooks Davis ///
1001b0d29bc4SBrooks Davis /// \param vars Set of configuration variables.
1002b0d29bc4SBrooks Davis ///
1003b0d29bc4SBrooks Davis /// \return A reference to this builder.
1004b0d29bc4SBrooks Davis ///
1005b0d29bc4SBrooks Davis /// \throw model::error If the value is invalid.
1006b0d29bc4SBrooks Davis model::metadata_builder&
set_required_configs(const model::strings_set & vars)1007b0d29bc4SBrooks Davis model::metadata_builder::set_required_configs(const model::strings_set& vars)
1008b0d29bc4SBrooks Davis {
1009b0d29bc4SBrooks Davis     set< config::strings_set_node >(_pimpl->props, "required_configs", vars);
1010b0d29bc4SBrooks Davis     return *this;
1011b0d29bc4SBrooks Davis }
1012b0d29bc4SBrooks Davis 
1013b0d29bc4SBrooks Davis 
1014b0d29bc4SBrooks Davis /// Sets the amount of free disk space required by the test.
1015b0d29bc4SBrooks Davis ///
1016b0d29bc4SBrooks Davis /// \param bytes Number of bytes.
1017b0d29bc4SBrooks Davis ///
1018b0d29bc4SBrooks Davis /// \return A reference to this builder.
1019b0d29bc4SBrooks Davis ///
1020b0d29bc4SBrooks Davis /// \throw model::error If the value is invalid.
1021b0d29bc4SBrooks Davis model::metadata_builder&
set_required_disk_space(const units::bytes & bytes)1022b0d29bc4SBrooks Davis model::metadata_builder::set_required_disk_space(const units::bytes& bytes)
1023b0d29bc4SBrooks Davis {
1024b0d29bc4SBrooks Davis     set< bytes_node >(_pimpl->props, "required_disk_space", bytes);
1025b0d29bc4SBrooks Davis     return *this;
1026b0d29bc4SBrooks Davis }
1027b0d29bc4SBrooks Davis 
1028b0d29bc4SBrooks Davis 
1029b0d29bc4SBrooks Davis /// Sets the list of files needed by the test.
1030b0d29bc4SBrooks Davis ///
1031b0d29bc4SBrooks Davis /// \param files Set of paths.
1032b0d29bc4SBrooks Davis ///
1033b0d29bc4SBrooks Davis /// \return A reference to this builder.
1034b0d29bc4SBrooks Davis ///
1035b0d29bc4SBrooks Davis /// \throw model::error If the value is invalid.
1036b0d29bc4SBrooks Davis model::metadata_builder&
set_required_files(const model::paths_set & files)1037b0d29bc4SBrooks Davis model::metadata_builder::set_required_files(const model::paths_set& files)
1038b0d29bc4SBrooks Davis {
1039b0d29bc4SBrooks Davis     set< paths_set_node >(_pimpl->props, "required_files", files);
1040b0d29bc4SBrooks Davis     return *this;
1041b0d29bc4SBrooks Davis }
1042b0d29bc4SBrooks Davis 
1043b0d29bc4SBrooks Davis 
1044b0d29bc4SBrooks Davis /// Sets the amount of memory required by the test.
1045b0d29bc4SBrooks Davis ///
1046b0d29bc4SBrooks Davis /// \param bytes Number of bytes.
1047b0d29bc4SBrooks Davis ///
1048b0d29bc4SBrooks Davis /// \return A reference to this builder.
1049b0d29bc4SBrooks Davis ///
1050b0d29bc4SBrooks Davis /// \throw model::error If the value is invalid.
1051b0d29bc4SBrooks Davis model::metadata_builder&
set_required_memory(const units::bytes & bytes)1052b0d29bc4SBrooks Davis model::metadata_builder::set_required_memory(const units::bytes& bytes)
1053b0d29bc4SBrooks Davis {
1054b0d29bc4SBrooks Davis     set< bytes_node >(_pimpl->props, "required_memory", bytes);
1055b0d29bc4SBrooks Davis     return *this;
1056b0d29bc4SBrooks Davis }
1057b0d29bc4SBrooks Davis 
1058b0d29bc4SBrooks Davis 
1059b0d29bc4SBrooks Davis /// Sets the list of programs needed by the test.
1060b0d29bc4SBrooks Davis ///
1061b0d29bc4SBrooks Davis /// \param progs Set of paths.
1062b0d29bc4SBrooks Davis ///
1063b0d29bc4SBrooks Davis /// \return A reference to this builder.
1064b0d29bc4SBrooks Davis ///
1065b0d29bc4SBrooks Davis /// \throw model::error If the value is invalid.
1066b0d29bc4SBrooks Davis model::metadata_builder&
set_required_programs(const model::paths_set & progs)1067b0d29bc4SBrooks Davis model::metadata_builder::set_required_programs(const model::paths_set& progs)
1068b0d29bc4SBrooks Davis {
1069b0d29bc4SBrooks Davis     set< paths_set_node >(_pimpl->props, "required_programs", progs);
1070b0d29bc4SBrooks Davis     return *this;
1071b0d29bc4SBrooks Davis }
1072b0d29bc4SBrooks Davis 
1073b0d29bc4SBrooks Davis 
1074b0d29bc4SBrooks Davis /// Sets the user required by the test.
1075b0d29bc4SBrooks Davis ///
1076b0d29bc4SBrooks Davis /// \param user One of unprivileged, root or empty.
1077b0d29bc4SBrooks Davis ///
1078b0d29bc4SBrooks Davis /// \return A reference to this builder.
1079b0d29bc4SBrooks Davis ///
1080b0d29bc4SBrooks Davis /// \throw model::error If the value is invalid.
1081b0d29bc4SBrooks Davis model::metadata_builder&
set_required_user(const std::string & user)1082b0d29bc4SBrooks Davis model::metadata_builder::set_required_user(const std::string& user)
1083b0d29bc4SBrooks Davis {
1084b0d29bc4SBrooks Davis     set< user_node >(_pimpl->props, "required_user", user);
1085b0d29bc4SBrooks Davis     return *this;
1086b0d29bc4SBrooks Davis }
1087b0d29bc4SBrooks Davis 
1088b0d29bc4SBrooks Davis 
1089b0d29bc4SBrooks Davis /// Sets a metadata property by name from its textual representation.
1090b0d29bc4SBrooks Davis ///
1091b0d29bc4SBrooks Davis /// \param key The property to set.
1092b0d29bc4SBrooks Davis /// \param value The value to set the property to.
1093b0d29bc4SBrooks Davis ///
1094b0d29bc4SBrooks Davis /// \return A reference to this builder.
1095b0d29bc4SBrooks Davis ///
1096b0d29bc4SBrooks Davis /// \throw model::error If the value is invalid or the key does not exist.
1097b0d29bc4SBrooks Davis model::metadata_builder&
set_string(const std::string & key,const std::string & value)1098b0d29bc4SBrooks Davis model::metadata_builder::set_string(const std::string& key,
1099b0d29bc4SBrooks Davis                                     const std::string& value)
1100b0d29bc4SBrooks Davis {
1101b0d29bc4SBrooks Davis     try {
1102b0d29bc4SBrooks Davis         _pimpl->props.set_string(key, value);
1103b0d29bc4SBrooks Davis     } catch (const config::unknown_key_error& e) {
1104b0d29bc4SBrooks Davis         throw model::format_error(F("Unknown metadata property %s") % key);
1105b0d29bc4SBrooks Davis     } catch (const config::value_error& e) {
1106b0d29bc4SBrooks Davis         throw model::format_error(
1107b0d29bc4SBrooks Davis             F("Invalid value for metadata property %s: %s") % key % e.what());
1108b0d29bc4SBrooks Davis     }
1109b0d29bc4SBrooks Davis     return *this;
1110b0d29bc4SBrooks Davis }
1111b0d29bc4SBrooks Davis 
1112b0d29bc4SBrooks Davis 
1113b0d29bc4SBrooks Davis /// Sets the timeout of the test.
1114b0d29bc4SBrooks Davis ///
1115b0d29bc4SBrooks Davis /// \param timeout The timeout to set.
1116b0d29bc4SBrooks Davis ///
1117b0d29bc4SBrooks Davis /// \return A reference to this builder.
1118b0d29bc4SBrooks Davis ///
1119b0d29bc4SBrooks Davis /// \throw model::error If the value is invalid.
1120b0d29bc4SBrooks Davis model::metadata_builder&
set_timeout(const datetime::delta & timeout)1121b0d29bc4SBrooks Davis model::metadata_builder::set_timeout(const datetime::delta& timeout)
1122b0d29bc4SBrooks Davis {
1123b0d29bc4SBrooks Davis     set< delta_node >(_pimpl->props, "timeout", timeout);
1124b0d29bc4SBrooks Davis     return *this;
1125b0d29bc4SBrooks Davis }
1126b0d29bc4SBrooks Davis 
1127b0d29bc4SBrooks Davis 
1128b0d29bc4SBrooks Davis /// Creates a new metadata object.
1129b0d29bc4SBrooks Davis ///
1130b0d29bc4SBrooks Davis /// \pre This has not yet been called.  We only support calling this function
1131b0d29bc4SBrooks Davis /// once due to the way the internal tree works: we pass around references, not
1132b0d29bc4SBrooks Davis /// deep copies, so if we allowed a second build, we'd encourage reusing the
1133b0d29bc4SBrooks Davis /// same builder to construct different metadata objects, and this could have
1134b0d29bc4SBrooks Davis /// unintended consequences.
1135b0d29bc4SBrooks Davis ///
1136b0d29bc4SBrooks Davis /// \return The constructed metadata object.
1137b0d29bc4SBrooks Davis model::metadata
build(void) const1138b0d29bc4SBrooks Davis model::metadata_builder::build(void) const
1139b0d29bc4SBrooks Davis {
1140b0d29bc4SBrooks Davis     PRE(!_pimpl->built);
1141b0d29bc4SBrooks Davis     _pimpl->built = true;
1142b0d29bc4SBrooks Davis 
1143b0d29bc4SBrooks Davis     return metadata(_pimpl->props);
1144b0d29bc4SBrooks Davis }
1145