aboutsummaryrefslogtreecommitdiff
path: root/build2/version/utility.cxx
blob: 0f8ea86362e960fdd91f92bef4b3e6900c6a3109 (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
// file      : build2/version/utility.cxx -*- C++ -*-
// copyright : Copyright (c) 2014-2017 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 <build2/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));

      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 ();

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