aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/functions-filesystem.cxx
blob: 15946234be0ad542d15c82c3e4b827dd0eab53f1 (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
// file      : libbuild2/functions-filesystem.cxx -*- C++ -*-
// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license   : MIT; see accompanying LICENSE file

#include <libbutl/filesystem.mxx>

#include <libbuild2/function.hxx>
#include <libbuild2/variable.hxx>

using namespace std;

namespace build2
{
  // Return paths of filesystem entries that match the pattern. See
  // path_search() overloads (below) for details.
  //
  static names
  path_search (const path& pattern, const optional<dir_path>& start)
  {
    names r;
    auto add = [&r] (path&& p, const std::string&, bool interm) -> bool
    {
      // Canonicalizing paths seems to be the right thing to do. Otherwise, we
      // can end up with different separators in the same path on Windows.
      //
      if (!interm)
        r.emplace_back (
          value_traits<path>::reverse (move (p.canonicalize ())));

      return true;
    };

    // Print paths "as is" in the diagnostics.
    //
    try
    {
      if (pattern.absolute ())
        path_search (pattern, add);
      else
      {
        // An absolute start directory must be specified for the relative
        // pattern.
        //
        if (!start || start->relative ())
        {
          diag_record dr (fail);

          if (!start)
            dr << "start directory is not specified";
          else
            dr << "start directory '" << start->representation ()
               << "' is relative";

          dr << info << "pattern '" << pattern.representation ()
             << "' is relative";
        }

        path_search (pattern, add, *start);
      }
    }
    catch (const system_error& e)
    {
      diag_record d (fail);
      d << "unable to scan";

      // If the pattern is absolute, then the start directory is not used, and
      // so printing it would be misleading.
      //
      if (start && pattern.relative ())
        d << " '" << start->representation () << "'";

      d << ": " << e
        << info << "pattern: '" << pattern.representation () << "'";
    }

    return r;
  }

  void
  filesystem_functions (function_map& m)
  {
    function_family f (m, "filesystem");

    // path_search
    //
    // Return filesystem paths that match the pattern. If the pattern is an
    // absolute path, then the start directory is ignored (if present).
    // Otherwise, the start directory must be specified and be absolute.
    //
    f["path_search"] = [](path pattern, optional<dir_path> start)
    {
      return path_search (pattern, start);
    };

    f["path_search"] = [](path pattern, names start)
    {
      return path_search (pattern, convert<dir_path> (move (start)));
    };

    f["path_search"] = [](names pattern, optional<dir_path> start)
    {
      return path_search (convert<path> (move (pattern)), start);
    };

    f["path_search"] = [](names pattern, names start)
    {
      return path_search (convert<path>     (move (pattern)),
                          convert<dir_path> (move (start)));
    };
  }
}