aboutsummaryrefslogtreecommitdiff
path: root/bdep/git.cxx
blob: a5e2be4e0b856a82554fd5a1b967cd60fa959e3e (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
// file      : bdep/git.cxx -*- C++ -*-
// copyright : Copyright (c) 2014-2018 Code Synthesis Ltd
// license   : MIT; see accompanying LICENSE file

#include <bdep/git.hxx>

#include <libbutl/git.mxx>

#include <bdep/diagnostics.hxx>

using namespace butl;

namespace bdep
{
  static optional<semantic_version> git_ver;

  // Check that git is at least of the specified minimum supported version.
  //
  void
  git_check_version (const semantic_version& min_ver)
  {
    // Query and cache git version on the first call.
    //
    if (!git_ver)
    {
      // Make sure that the getline() function call doesn't end up with an
      // infinite recursion.
      //
      git_ver = semantic_version ();

      optional<string> s (git_line (*git_ver,
                                    false /* ignore_error */,
                                    "--version"));

      if (!s || !(git_ver = git_version (*s)))
        fail << "unable to obtain git version";
    }

    // Note that we don't expect the min_ver to contain the build component,
    // that doesn't matter functionality-wise for git.
    //
    if (*git_ver < min_ver)
      fail << "unsupported git version " << *git_ver <<
        info << "minimum supported version is " << min_ver << endf;
  }

  optional<string>
  git_line (process&& pr, fdpipe&& pipe, bool ie)
  {
    optional<string> r;

    bool io (false);
    try
    {
      pipe.out.close ();
      ifdstream is (move (pipe.in), fdstream_mode::skip, ifdstream::badbit);

      string l;
      if (!eof (getline (is, l)))
        r = move (l);

      is.close (); // Detect errors.
    }
    catch (const io_error&)
    {
      io = true; // Presumably git failed so check that first.
    }

    // Note: cannot use finish() since ignoring normal error.
    //
    if (!pr.wait ())
    {
      const process_exit& e (*pr.exit);

      if (!e.normal ())
        fail << "process git " << e;

      if (ie)
        r = nullopt;
      else
        throw failed (); // Assume git issued diagnostics.
    }
    else if (io)
      fail << "unable to read git output";

    return r;
  }
}