aboutsummaryrefslogtreecommitdiff
path: root/bpkg/package-skeleton.hxx
blob: 1b7e019596f22b5bddcc55d9294c205255d70dec (plain)
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
// file      : bpkg/package-skeleton.hxx -*- C++ -*-
// license   : MIT; see accompanying LICENSE file

#ifndef BPKG_PACKAGE_SKELETON_HXX
#define BPKG_PACKAGE_SKELETON_HXX

#include <libbuild2/forward.hxx> // build2::context

#include <bpkg/types.hxx>
#include <bpkg/utility.hxx>

#include <bpkg/package.hxx>
#include <bpkg/common-options.hxx>

namespace bpkg
{
  // A build system skeleton of a package used to evaluate buildfile clauses
  // during dependency resolution (enable, reflect, require or prefer/accept).
  //
  class package_skeleton
  {
  public:
    // If the package is external, then the existing package source root
    // directory needs to be specified (as absolute and normalized). In this
    // case, if output root is specified (as absolute and normalized; normally
    // <config-dir>/<package-name>), then it's used as is. Otherwise, an empty
    // skeleton directory is used as output root.
    //
    // If the package is not external, then none of the root directories
    // should be specified.
    //
    // The disfigure argument should indicate whether the package is being
    // reconfigured from scratch (--disfigure).
    //
    // The config_vars argument contains configuration variables specified by
    // the user in this bpkg execution. Optional config_srcs is used to
    // extract (from config.build or equivalent) configuration variables
    // specified by the user in previous bpkg executions. It should be NULL if
    // this is the first build of the package. The extracted variables are
    // merged with config_vars and the combined result is returned by
    // collect_config() below.
    //
    // @@ TODO: speaking of the "config.build or equivalent" part, the
    //    equivalent is likely to be extracted configuration (probably saved
    //    to file in tmp somewhere) that we will load with config.config.load.
    //    It doesn't seem like a good idea to pass it as part of config_vars
    //    (because sometimes we may need to omit it) so most likely it will be
    //    passed as a separate arguments (likely a file path).
    //
    // Note that the options, database, available_package, and config_srcs are
    // expected to outlive this object.
    //
    // Note also that this creates an "unloaded" skeleton and is therefore
    // relatively cheap.
    //
    package_skeleton (const common_options& co,
                      database&,
                      const available_package&,
                      strings config_vars,
                      bool disfigure,
                      const vector<config_variable>* config_srcs,
                      optional<dir_path> src_root,
                      optional<dir_path> out_root);

    const package_name&
    name () const {return available_->id.name;}

    // The following functions should be called in the following sequence
    // (* -- zero or more, ? -- zero or one):
    //
    // * load_defaults()
    // * verify_sensible()
    // ? dependent_config()
    // * evaluate_enable() | evaluate_reflect()
    //   collect_config()
    //
    // Note that a copy of the skeleton is expected to continue with the
    // sequence rather than starting from scratch.
    //
  public:
    // Load the default values and type information for configuration
    // variables of the package given a "tentative" dependent configuration.
    //
    // @@ TODO: if it will be more convenient to pass it as something other
    //    than strings, then this can be accomodated.
    //
    void
    load_defaults (const strings& dependent_vars);

    // Verify the specified "tentative" dependents configuration is sensible,
    // that is, acceptable to the package. If it is not, then the second half
    // of the result contains the diagnostics.
    //
    // @@ TODO: if it will be more convenient to pass it as something other
    //    than strings, then this can be accomodated.
    //
    pair<bool, string>
    verify_sensible (const strings& dependent_vars);

    // Incorporate the "final" dependent configuration into subsequent
    // evaluations. Dependent configuration variables are expected not to
    // clash with user.
    //
    void
    dependent_config (strings&&);

    // For the following evaluate_*() functions assume that the clause belongs
    // to the specified (by index) depends value (used to print its location
    // on failure for an external package).
    //

    // Evaluate the enable clause.
    //
    bool
    evaluate_enable (const string&, size_t depends_index);

    // Evaluate the reflect clause.
    //
    void
    evaluate_reflect (const string&, size_t depends_index);

    // Return the accumulated configuration variables (first) and project
    // configuration variable sources (second). Note that the arrays are not
    // necessarily parallel (config_vars may contain non-project variables).
    //
    // Note that the dependent and reflect variables are merged with
    // config_vars/config_srcs and should be used instead rather than in
    // addition to config_vars.
    //
    // Note also that this should be the final call on this object.
    //
    pair<strings, vector<config_variable>>
    collect_config () &&;

    // Implementation details.
    //
  public:
    // We have to define these because context is forward-declared. Also, copy
    // constructor has some special logic.
    //
    ~package_skeleton ();
    package_skeleton (package_skeleton&&);
    package_skeleton& operator= (package_skeleton&&);

    package_skeleton (const package_skeleton&);
    package_skeleton& operator= (const package_skeleton&) = delete;

  private:
    // Load old user configuration variables from config.build (or equivalent)
    // and merge them into config_vars_.
    //
    // This should be done before any attempt to load the configuration with
    // config.config.disfigure and, if this did not happen, inside
    // collect_config() (since the package will be reconfigured with
    // config.config.disfigure).
    //
    void
    load_old_config ();

    // (Re)load the build system state.
    //
    // Call this function before evaluating every clause.
    //
    build2::scope&
    load ();

    // Merge command line variable overrides into one list (normally to be
    // passed to bootstrap()).
    //
    // If cache is true, then assume the result can be reused on subsequent
    // calls.
    //
    const strings&
    merge_cmd_vars (const strings& dependent_vars, bool cache = false);

    // Implementation details (public for bootstrap()).
    //
  public:
    // NOTE: remember to update move/copy constructors!
    //
    const common_options* co_;
    database* db_;
    const available_package* available_;

    strings config_vars_;
    bool disfigure_;
    const vector<config_variable>* config_srcs_; // NULL if nothing to do or
                                                 // already done.

    dir_path src_root_; // Must be absolute and normalized.
    dir_path out_root_; // If empty, the same as src_root_.

    bool created_ = false;
    bool verified_ = false;
    unique_ptr<build2::context> ctx_;
    build2::scope* rs_ = nullptr;

    // Storage for merged build2_cmd_vars and config_vars_ and extra overrides
    // (like config.config.disfigure). If cache is true, then the existing
    // content can be reused.
    //
    strings cmd_vars_;
    bool cmd_vars_cache_ = false;

    strings dependent_vars_; // Dependent configuration variable overrides.
    strings reflect_vars_;   // Reflect configuration variable overrides.
    string  reflect_frag_;   // Reflect configuration variables fragment.
  };
}

#endif // BPKG_PACKAGE_SKELETON_HXX