aboutsummaryrefslogtreecommitdiff
path: root/bpkg/utility.txx
blob: 0e71e13879cda170f59a18ddbeb6e8c51950df9f (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
// file      : bpkg/utility.txx -*- C++ -*-
// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license   : MIT; see accompanying LICENSE file

#include <bpkg/diagnostics.hxx>

namespace bpkg
{
  // *_b()
  //
  template <typename O, typename E, typename... A>
  process
  start_b (const common_options& co,
           O&& out,
           E&& err,
           verb_b v,
           A&&... args)
  {
    const char* b (name_b (co));

    try
    {
      // Use our executable directory as a fallback search since normally the
      // entire toolchain is installed into one directory. This way, for
      // example, if we installed into /opt/build2 and run bpkg with absolute
      // path (and without PATH), then bpkg will be able to find "its" b.
      //
      process_path pp (process::path_search (b, exec_dir));

      small_vector<const char*, 1> ops;

      // 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.
      //
      string vl;
      bool no_progress (co.no_progress ());

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

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

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

      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 " << b << ": " << 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;
    }
  }
}