aboutsummaryrefslogtreecommitdiff
path: root/build2/filesystem.hxx
blob: 2ba928cb3f728558bfa710ac83ca095c433176c0 (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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
// file      : build2/filesystem.hxx -*- C++ -*-
// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license   : MIT; see accompanying LICENSE file

#ifndef BUILD2_FILESYSTEM_HXX
#define BUILD2_FILESYSTEM_HXX

#include <libbutl/filesystem.mxx>

#include <build2/types.hxx>
#include <build2/utility.hxx>

// Higher-level filesystem utilities built on top of <libbutl/filesystem.mxx>.
//
// Compared to the libbutl's versions, these handle errors and issue
// diagnostics. Some of them also print the corresponding command line
// equivalent at the specified verbosity level. Note that most of such
// functions also respect the dry_run flag.
//
namespace build2
{
  using butl::auto_rmfile;
  using butl::auto_rmdir;

  // The dual interface wrapper for the {mk,rm}{file,dir}() functions
  // below that allows you to use it as a true/false return or a more
  // detailed enum from <libbutl/filesystem.mxx>
  //
  template <typename T>
  struct fs_status
  {
    T v;
    fs_status (T v): v (v) {};
    operator T () const {return v;}
    explicit operator bool () const {return v == T::success;}
  };

  // Set the file access and modification times (unless dry-run) to the
  // current time printing the standard diagnostics starting from the
  // specified verbosity level. If the file does not exist and create is true,
  // create it and fail otherwise.
  //
  void
  touch (const path&, bool create, uint16_t verbosity = 1);

  // Return the modification time for an existing regular file and
  // timestamp_nonexistent otherwise. Print the diagnostics and fail on system
  // error.
  //
  timestamp
  mtime (const char*);

  inline timestamp
  mtime (const path& p)
  {
    return mtime (p.string ().c_str ());
  }

  // Create the directory and print the standard diagnostics starting from the
  // specified verbosity level.
  //
  // Note that these functions ignore the dry_run flag (we might need to save
  // something in such a directory, such as depdb, ignoring dry_run). Overall,
  // it feels like we should establish the structure even for dry-run.
  //
  // Note that the implementation may not be suitable if the performance is
  // important and it is expected that the directory will exist in most cases.
  // See the fsdir{} rule for details.
  //
  using mkdir_status = butl::mkdir_status;

  fs_status<mkdir_status>
  mkdir (const dir_path&, uint16_t verbosity = 1);

  fs_status<mkdir_status>
  mkdir_p (const dir_path&, uint16_t verbosity = 1);

  // Remove the file (unless dry-run) and print the standard diagnostics
  // starting from the specified verbosity level. The second argument is only
  // used in diagnostics, to print the target name. Passing the path for
  // target will result in the relative path being printed.
  //
  using rmfile_status = butl::rmfile_status;

  template <typename T>
  fs_status<rmfile_status>
  rmfile (const path&, const T& target, uint16_t verbosity = 1);

  inline fs_status<rmfile_status>
  rmfile (const path& f, int verbosity = 1) // Literal overload (int).
  {
    return rmfile (f, f, static_cast<uint16_t> (verbosity));
  }

  inline fs_status<rmfile_status>
  rmfile (const path& f, uint16_t verbosity) // Overload (verb_never).
  {
    return rmfile (f, f, verbosity);
  }

  // Similar to rmfile() but for symlinks.
  //
  fs_status<rmfile_status>
  rmsymlink (const path&, bool dir, uint16_t verbosity);

  // Similar to rmfile() but for directories (note: not -r).
  //
  using rmdir_status = butl::rmdir_status;

  template <typename T>
  fs_status<rmdir_status>
  rmdir (const dir_path&, const T& target, uint16_t verbosity = 1);

  inline fs_status<rmdir_status>
  rmdir (const dir_path& d, int verbosity = 1) // Literal overload (int).
  {
    return rmdir (d, d, static_cast<uint16_t> (verbosity));
  }

  inline fs_status<rmdir_status>
  rmdir (const dir_path& d, uint16_t verbosity) // Overload (verb_never).
  {
    return rmdir (d, d, verbosity);
  }

  // Remove the directory recursively (unless dry-run) and print the standard
  // diagnostics starting from the specified verbosity level. Note that this
  // function returns not_empty if we try to remove a working directory. If
  // the dir argument is false, then the directory itself is not removed.
  //
  // @@ Collides (via ADL) with butl::rmdir_r(), which sucks.
  //
  fs_status<rmdir_status>
  rmdir_r (const dir_path&, bool dir = true, uint16_t verbosity = 1);

  // Check for a file, directory or filesystem entry existence. Print the
  // diagnostics and fail on system error, unless ignore_error is true.
  //
  bool
  exists (const path&, bool follow_symlinks = true, bool ignore_error = false);

  bool
  exists (const dir_path&, bool ignore_error = false);

  bool
  entry_exists (const path&,
                bool follow_symlinks = false,
                bool ignore_error = false);

  // Check for a directory emptiness. Print the diagnostics and fail on system
  // error.
  //
  bool
  empty (const dir_path&);

  // Directories containing .buildignore (or .build2ignore in the alternative
  // naming scheme) file are automatically ignored by recursive name patterns.
  // For now the file is just a marker and its contents don't matter. Note
  // that these functions ignore dry-run.

  // Create a directory containing an empty .buildignore file.
  //
  fs_status<mkdir_status>
  mkdir_buildignore (const dir_path&, const path&, uint16_t verbosity = 1);

  // Return true if the directory is empty or only contains the .buildignore
  // file. Fail if the directory doesn't exist.
  //
  bool
  empty_buildignore (const dir_path&, const path&);

  // Remove a directory if it is empty or only contains the .buildignore file.
  //
  fs_status<rmdir_status>
  rmdir_buildignore (const dir_path&, const path&, uint16_t verbosity = 1);
}

#include <build2/filesystem.txx>

#endif // BUILD2_FILESYSTEM_HXX