aboutsummaryrefslogtreecommitdiff
path: root/build2/context.txx
blob: 922368154d1daa8bf707cf1356a61cf9a3599837 (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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// file      : build2/context.txx -*- C++ -*-
// copyright : Copyright (c) 2014-2016 Code Synthesis Ltd
// license   : MIT; see accompanying LICENSE file

#include <build2/diagnostics>

namespace build2
{
  template <typename T>
  fs_status<butl::rmfile_status>
  rmfile (const path& f, const T& t, uint16_t v)
  {
    using namespace butl;

    // We don't want to print the command if we couldn't remove the file
    // because it does not exist (just like we don't print the update command
    // if the file is up to date). This makes the below code a bit ugly.
    //
    auto print = [&f, &t, v] ()
    {
      if (verb >= v)
      {
        if (verb >= 2)
          text << "rm " << f;
        else if (verb)
          text << "rm " << t;
      }
    };

    rmfile_status rs;

    try
    {
      rs = try_rmfile (f);
    }
    catch (const system_error& e)
    {
      print ();
      error << "unable to remove file " << f << ": " << e.what ();
      throw failed ();
    }

    if (rs == rmfile_status::success)
      print ();

    return rs;
  }

  template <typename T>
  fs_status<butl::rmdir_status>
  rmdir (const dir_path& d, const T& t, uint16_t v)
  {
    using namespace butl;

    bool w (work.sub (d)); // Don't try to remove working directory.
    rmdir_status rs;

    // We don't want to print the command if we couldn't remove the directory
    // because it does not exist (just like we don't print mkdir if it already
    // exists) or if it is not empty. This makes the below code a bit ugly.
    //
    auto print = [&d, &t, v] ()
    {
      if (verb >= v)
      {
        if (verb >= 2)
          text << "rm " << d;
        else if (verb)
          text << "rm " << t;
      }
    };

    try
    {
      rs = !w ? try_rmdir (d) : rmdir_status::not_empty;
    }
    catch (const system_error& e)
    {
      print ();
      error << "unable to remove directory " << d << ": " << e.what ();
      throw failed ();
    }

    switch (rs)
    {
    case rmdir_status::success:
      {
        print ();
        break;
      }
    case rmdir_status::not_empty:
      {
        if (verb >= v && verb >= 2)
        {
          text << d << " is "
               << (w ? "current working directory" : "not empty")
               << ", not removing";
        }
        break;
      }
    case rmdir_status::not_exist:
      break;
    }

    return rs;
  }

  template <typename K>
  basic_path<char, K>
  relative (const basic_path<char, K>& p)
  {
    typedef basic_path<char, K> path;

    const dir_path& b (*relative_base);

    if (b.empty ())
      return p;

    if (p.sub (b))
      return p.leaf (b);

    // If base is a sub-path of {src,out}_root and this path is also a
    // sub-path of it, then use '..' to form a relative path.
    //
    // Don't think this is a good heuristic. For example, why shouldn't
    // we display paths from imported projects as relative if they are
    // more readable than absolute?
    //
    /*
    if ((work.sub (src_root) && p.sub (src_root)) ||
        (work.sub (out_root) && p.sub (out_root)))
      return p.relative (work);
    */

    if (p.root_directory () == b.root_directory ())
    {
      path r (p.relative (b));

      if (r.string ().size () < p.string ().size ())
        return r;
    }

    return p;
  }
}