1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
// file : bpkg/package-configuration.cxx -*- C++ -*-
// license : MIT; see accompanying LICENSE file
#include <bpkg/package-configuration.hxx>
#include <bpkg/package-skeleton.hxx>
namespace bpkg
{
using build2::config::variable_origin;
bool
up_negotiate_configuration (
package_configurations& cfgs,
package_skeleton& dept,
pair<size_t, size_t> pos,
const small_vector<reference_wrapper<package_skeleton>, 1>& depcs)
{
dependent_config_variable_values old_cfgs;
// Step 1: save a snapshot of the old configuration while unsetting values
// that have this dependent as the originator and reloading the defaults.
//
// While at it, also collect the configurations to pass to dependent's
// evaluate_*() calls.
//
package_skeleton::dependency_configurations depc_cfgs;
depc_cfgs.reserve (depcs.size ());
for (package_skeleton& depc: depcs)
{
package_configuration& cfg (cfgs[depc.key]);
for (config_variable_value& v: cfg)
{
if (v.origin == variable_origin::buildfile)
{
if (*v.dependent == dept.key)
{
old_cfgs.push_back (
dependent_config_variable_value {
v.name, move (v.value), move (*v.dependent)});
v.origin = variable_origin::undefined;
v.dependent = nullopt;
}
else
old_cfgs.push_back (
dependent_config_variable_value {v.name, v.value, *v.dependent});
}
}
depc.reload_defaults (cfg);
depc_cfgs.push_back (cfg);
}
// Step 2: execute the prefer/accept or requires clauses.
//
pos.first--; pos.second--; // Convert to 0-base.
const dependency_alternative& da (
dept.available.get ().dependencies[pos.first][pos.second]);
if (!(da.require
? dept.evaluate_require (depc_cfgs, *da.require, pos.first)
: dept.evaluate_prefer_accept (depc_cfgs,
*da.prefer, *da.accept, pos.first)))
{
fail << "unable to negotiate acceptable configuration"; // @@ TODO
}
// Check if anything changed by comparing to entries in old_cfgs.
//
{
optional<size_t> n (0); // Number of unchanged.
for (package_skeleton& depc: depcs)
{
package_configuration& cfg (cfgs[depc.key]);
for (config_variable_value& v: cfg)
{
if (v.origin == variable_origin::buildfile)
{
auto i (find_if (old_cfgs.begin (), old_cfgs.end (),
[&v] (const dependent_config_variable_value& o)
{
return v.name == o.name;
}));
if (i == old_cfgs.end () ||
i->value != v.value ||
i->dependent != *v.dependent)
{
n = nullopt;
break;
}
++*n;
}
}
if (!n)
break;
}
// If we haven't seen any changed and we've seen the same number, then
// nothing has changed.
//
if (n && *n == old_cfgs.size ())
return false;
}
// @@ TODO: look for cycles in change history.
// @@ TODO: save in change history.
//
/*
dependent_config_variable_values new_cfgs; // @@ TODO.
old_cfgs.sort ();
new_cfgs.sort ();
*/
return true;
}
}
|