aboutsummaryrefslogtreecommitdiff
path: root/build2/context.txx
blob: 3233092c0ebe8584a7455da5d6ccad756558d5f4 (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
// 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, bool verbose)
  {
    using namespace butl;

    // Verbosity thresholds.
    //
    uint16_t l1 (verbose ? 2 : 3);
    uint16_t l2 (verbose ? 1 : 3);

    // 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.
    //
    rmfile_status rs;

    try
    {
      rs = try_rmfile (f);
    }
    catch (const system_error& e)
    {
      if (verb >= l1)
        text << "rm " << f;
      else if (verb >= l2)
        text << "rm " << t;

      fail << "unable to remove file " << f << ": " << e.what ();
    }

    if (rs == rmfile_status::success)
    {
      if (verb >= l1)
        text << "rm " << f;
      else if (verb >= l2)
        text << "rm " << t;
    }

    return rs;
  }

  template <typename T>
  fs_status<butl::rmdir_status>
  rmdir (const dir_path& d, const T& t)
  {
    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.
    //
    try
    {
      rs = !w ? try_rmdir (d) : rmdir_status::not_empty;
    }
    catch (const system_error& e)
    {
      if (verb >= 2)
        text << "rmdir " << d;
      else if (verb)
        text << "rmdir " << t;

      fail << "unable to remove directory " << d << ": " << e.what ();
    }

    switch (rs)
    {
    case rmdir_status::success:
      {
        if (verb >= 2)
          text << "rmdir " << d;
        else if (verb)
          text << "rmdir " << t;

        break;
      }
    case rmdir_status::not_empty:
      {
        if (verb >= 2)
          text << "directory " << 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;
  }
}