aboutsummaryrefslogtreecommitdiff
path: root/libbutl/standard-version.cxx
blob: 610097154117cdbd9e01b6f8275093caaf63b16e (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
// file      : libbutl/standard-version.cxx
// license   : MIT; see accompanying LICENSE file

#include <string>
#include <cstddef>   // size_t
#include <iostream>
#include <stdexcept> // invalid_argument

#include <libbutl/utility.hxx>          // operator<<(ostream,exception)
#include <libbutl/optional.hxx>
#include <libbutl/standard-version.hxx>

using namespace std;
using namespace butl;

// Usage: argv[0] [<options>] <standard-version>
//
// Check that the specified predicates are true for a standard version.
//
// See standard-version.bash.in for the functionality and options description.
//
int
main (int argc, char* argv[])
{
  using butl::optional;

  // We could probably try to parse the last argument as a version first and
  // then evaluate the predicates while parsing the options. This, however
  // would worsen the diagnostics (think about the `standard-version --beta`
  // command) and would complicate things a bit, since at the time of the
  // version parsing we wouldn't know if to print the diagnostics for an
  // invalid version. Thus, we will parse the arguments in the direct order.
  //
  optional<bool> snapshot;
  optional<bool> latest_sn;
  optional<bool> alpha;
  optional<bool> beta;
  optional<bool> pre_release;
  optional<bool> release;
  optional<bool> final;
  optional<bool> stub;
  optional<bool> earliest;

  bool valid    (false); // --is-version is specified.
  bool opposite (false); // Opposite predicates are specified simultaneously
                         // (i.e. --is-beta and --is-not-beta).

  int i (1);
  for (; i != argc; ++i)
  {
    string op (argv[i]);

    bool is;
    size_t n;

         if (op.compare (0, (n = 9), "--is-not-") == 0) is = false;
    else if (op.compare (0, (n = 5), "--is-")     == 0) is = true;
    else break;

    string p (op, n);

    // Set the predicate expected value. If the opposite value have already
    // been specified, then save this information to exit with code 1 later
    // (note that we still need to validate the rest of the arguments).
    //
    auto set = [is, &opposite] (optional<bool>& v)
    {
      if (!v)
        v = is;
      else if (*v != is)
        opposite = true;
    };

         if (p == "snapshot")        set (snapshot);
    else if (p == "latest-snapshot") set (latest_sn);
    else if (p == "alpha")           set (alpha);
    else if (p == "beta")            set (beta);
    else if (p == "pre-release")     set (pre_release);
    else if (p == "release")         set (release);
    else if (p == "final")           set (final);
    else if (p == "stub")            set (stub);
    else if (p == "earliest")        set (earliest);
    else if (p == "version" && is)   valid = true;
    else break;
  }

  if (i == argc)
  {
    cerr << "error: missing version" << endl;
    return 3;
  }

  string a (argv[i++]);

  if (i != argc)
  {
    cerr << "error: unexpected argument '" << argv[i] << "'" << endl;
    return 3;
  }

  try
  {
    standard_version v (a,
                        (standard_version::allow_earliest |
                         standard_version::allow_stub));

    return !opposite                                                       &&
           (!snapshot    || *snapshot    == v.snapshot())                  &&
           (!latest_sn   || *latest_sn   == v.latest_snapshot ())          &&
           (!alpha       || *alpha       == v.alpha ().has_value ())       &&
           (!beta        || *beta        == v.beta ().has_value ())        &&
           (!pre_release || *pre_release == v.pre_release ().has_value ()) &&
           (!release     || *release     == v.release ())                  &&
           (!final       || *final       == v.final ())                    &&
           (!stub        || *stub        == v.stub ())                     &&
           (!earliest    || *earliest    == v.earliest ())
           ? 0
           : 1;
  }
  catch (const invalid_argument& e)
  {
    if (!valid)
      cerr << "error: " << e << endl;

    return 2;
  }
}