aboutsummaryrefslogtreecommitdiff
path: root/bpkg/utility.txx
blob: 33bb71122364c55e34f3d7408ca7991b7a51f30f (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
// file      : bpkg/utility.txx -*- C++ -*-
// license   : MIT; see accompanying LICENSE file

#include <bpkg/diagnostics.hxx>

namespace bpkg
{
  // *_b()
  //
  template <typename V>
  void
  map_verb_b (const common_options& co, verb_b v, V& ops, string& verb_arg)
  {
    // Map verbosity level. If we are running quiet or at level 1,
    // then run build2 quiet. Otherwise, run it at the same level
    // as us.
    //
    bool progress    (co.progress ());
    bool no_progress (co.no_progress ());

    if (verb == 0)
    {
      ops.push_back ("-q");
      no_progress = false;  // Already suppressed with -q.
    }
    else if (verb == 1)
    {
      // NOTE: search for verb_b usage if changing anything here.
      //
      if (v != verb_b::normal)
      {
        ops.push_back ("-q");

        if (!no_progress)
        {
          if (v == verb_b::progress && stderr_term)
          {
            ops.push_back ("--progress");
              progress = false; // The option is already added.
          }
        }
        else
          no_progress = false; // Already suppressed with -q.
      }
    }
    else if (verb == 2)
      ops.push_back ("-v");
    else
    {
      verb_arg = to_string (verb);
      ops.push_back ("--verbose");
      ops.push_back (verb_arg.c_str ());
    }

    if (progress)
      ops.push_back ("--progress");

    if (no_progress)
      ops.push_back ("--no-progress");
  }

  template <typename... A>
  void
  print_b (const common_options& co, verb_b v, A&&... args)
  {
    process_path pp (search_b (co));

    small_vector<const char*, 1> ops;

    // As in start_b() below.
    //
    string verb_arg;
    map_verb_b (co, v, ops, verb_arg);

    if (co.diag_color ())
      ops.push_back ("--diag-color");

    if (co.no_diag_color ())
      ops.push_back ("--no-diag-color");

    process_print_callback (
      [] (const char* const args[], size_t n)
      {
        print_process (args, n);
      },
      pp,
      ops,
      co.build_option (),
      forward<A> (args)...);
  }

  template <typename O, typename E, typename... A>
  process
  start_b (const common_options& co,
           O&& out,
           E&& err,
           verb_b v,
           A&&... args)
  {
    process_path pp (search_b (co));

    try
    {
      small_vector<const char*, 1> ops;

      // NOTE: see print_b() above if changing anything here.
      //
      // NOTE: see custom versions in system_package_manager* if adding
      //       anything new here (search for search_b()).

      string verb_arg;
      map_verb_b (co, v, ops, verb_arg);

      // Forward our --[no]diag-color options.
      //
      if (co.diag_color ())
        ops.push_back ("--diag-color");

      if (co.no_diag_color ())
        ops.push_back ("--no-diag-color");

      return process_start_callback (
        [] (const char* const args[], size_t n)
        {
          if (verb >= 2)
            print_process (args, n);
        },
        0 /* stdin */,
        forward<O> (out),
        forward<E> (err),
        pp,
        ops,
        co.build_option (),
        forward<A> (args)...);
    }
    catch (const process_error& e)
    {
      fail << "unable to execute " << pp.recall_string () << ": " << e << endf;
    }
  }

  template <typename... A>
  void
  run_b (const common_options& co, verb_b v, A&&... args)
  {
    process pr (
      start_b (co, 1 /* stdout */, 2 /* stderr */, v, forward<A> (args)...));

    if (!pr.wait ())
    {
      const process_exit& e (*pr.exit);

      if (e.normal ())
        throw failed (); // Assume the child issued diagnostics.

      fail << "process " << name_b (co) << " " << e;
    }
  }
}