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

#include <build2/version/utility.hxx>

#include <libbutl/manifest-parser.mxx>
#include <libbutl/manifest-serializer.mxx>

#include <libbuild2/diagnostics.hxx>

using namespace butl;

namespace build2
{
  namespace version
  {
    auto_rmfile
    fixup_manifest (const path& in, path out, const standard_version& v)
    {
      auto_rmfile r (move (out), !dry_run /* active */);

      if (!dry_run)
      {
        try
        {
          permissions perm (path_permissions (in));

          ifdstream ifs (in);
          manifest_parser p (ifs, in.string ());

          auto_fd ofd (fdopen (r.path,
                               fdopen_mode::out       |
                               fdopen_mode::create    |
                               fdopen_mode::exclusive |
                               fdopen_mode::binary,
                               perm));

          ofdstream ofs (move (ofd));
          manifest_serializer s (ofs, r.path.string ());

          manifest_name_value nv (p.next ());
          assert (nv.name.empty () && nv.value == "1"); // We just loaded it.
          s.next (nv.name, nv.value);

          for (nv = p.next (); !nv.empty (); nv = p.next ())
          {
            if (nv.name == "version")
              nv.value = v.string ();

            s.next (nv.name, nv.value);
          }

          s.next (nv.name, nv.value); // End of manifest.
          s.next (nv.name, nv.value); // End of stream.

          ofs.close ();
          ifs.close ();
        }
        catch (const manifest_parsing& e)
        {
          location l (&in, e.line, e.column);
          fail (l) << e.description;
        }
        catch (const manifest_serialization& e)
        {
          location l (&r.path);
          fail (l) << e.description;
        }
        catch (const io_error& e)
        {
          fail << "io error: " << e <<
            info << "while reading " << in <<
            info << "while writing " << r.path;
        }
      }

      return r;
    }
  }
}