2016-09-18 20:50:08 -07:00
|
|
|
#pragma once
|
|
|
|
|
2017-10-13 18:37:41 -07:00
|
|
|
#include <vcpkg/base/expected.h>
|
|
|
|
|
2020-01-18 00:36:08 +01:00
|
|
|
#if USE_STD_FILESYSTEM
|
|
|
|
#include <filesystem>
|
|
|
|
#else
|
VS 2019 16.3 deprecates <experimental/filesystem>. (#6968)
VS 2019 16.3 will contain a couple of source-breaking changes:
* <experimental/filesystem> will be deprecated via an
impossible-to-miss preprocessor "#error The <experimental/filesystem>
header providing std::experimental::filesystem is deprecated by
Microsoft and will be REMOVED. It is superseded by the C++17
<filesystem> header providing std::filesystem. You can define
_SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING to acknowledge
that you have received this warning."
* <filesystem> will no longer include <experimental/filesystem>.
In the long term, I believe that vcpkg should detect when it's being
built with VS 2017 15.7 or newer, compile in C++17 mode, include
<filesystem>, and use std::filesystem. (Activating this for VS 2019 16.0
or newer would also be reasonable.) Similarly for other toolsets
supporting std::filesystem.
In the short term, this commit makes vcpkg compatible with the upcoming
deprecation. First, we need to define the silencing macro before
including the appropriate header. I've chosen to define it
unconditionally (without checking for platform or version), since it
has no effect for other platforms or versions. Second, we need to deal
with <filesystem> no longer including <experimental/filesystem>.
I verified that VS 2015 Update 3 contained <experimental/filesystem>
(back then, it simply included the <filesystem> header, where the
experimental implementation was defined; this was later reorganized).
Therefore, all of vcpkg's supported MSVC toolsets have
<experimental/filesystem>, so we can simply always include it.
I've verified that this builds with both VS 2015 Update 3 and
VS 2019 16.1.3 (the current production version).
2019-06-20 11:46:55 -07:00
|
|
|
#define _SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING
|
2017-10-16 11:44:04 -07:00
|
|
|
#include <experimental/filesystem>
|
2020-01-18 00:36:08 +01:00
|
|
|
#endif
|
2017-10-13 18:37:41 -07:00
|
|
|
|
|
|
|
namespace fs
|
|
|
|
{
|
2020-01-18 00:36:08 +01:00
|
|
|
#if USE_STD_FILESYSTEM
|
|
|
|
namespace stdfs = std::filesystem;
|
|
|
|
#else
|
2017-10-13 18:37:41 -07:00
|
|
|
namespace stdfs = std::experimental::filesystem;
|
2020-01-18 00:36:08 +01:00
|
|
|
#endif
|
2017-10-13 18:37:41 -07:00
|
|
|
|
|
|
|
using stdfs::copy_options;
|
|
|
|
using stdfs::path;
|
2019-07-11 18:16:10 -07:00
|
|
|
using stdfs::perms;
|
2017-11-20 19:15:47 -08:00
|
|
|
using stdfs::u8path;
|
2017-10-13 18:37:41 -07:00
|
|
|
|
[vcpkg] Make Filesystem::remove_all faster #7570
I added benchmarks to measure how fast the parallel remove_all code was
-- it turns out, about 3x slower than stdfs::remove_all. Since this was
the case, I removed all of the parallelism and rewrote it serially, and
ended up about 30% faster than stdfs::remove_all (in addition to
supporting symlinks).
In addition, I did the following three orthogonal changes:
- simplified the work queue, basing it on Billy O'Neal's idea
- Fix warnings on older versions of compilers in tests, by splitting
the pragmas out of pch.h.
- Ran clang-format on some files
In fixing up remove_all, the following changes were made:
- On Windows, regular symlinks and directory symlinks are distinct;
as an example, to remove directory symlinks (and junctions, for that
matter), one must use RemoveDirectory. Only on Windows, I added new
`file_type` and `file_status` types, with `file_type` including a new
`directory_symlink` enumerator, and `file_status` being exactly the
same as the old one except using the new `file_type`. On Unix, I
didn't make that change since they don't make a distinction.
- I added new `symlink_status` and `status` functions which use the
new `file_status` on Windows.
- I made `Filesystem::exists` call `fs::exists(status(p))`, as opposed
to the old version which called `stdfs::exists` directly.
- Added benchmarks to `vcpkg-test/files.cpp`. They test the
performance of `remove_all` on small directories (~20 files), with
symlinks and without, and on large directories (~2000 files), with
symlinks and without.
2019-08-02 16:49:45 -07:00
|
|
|
#if defined(_WIN32)
|
|
|
|
enum class file_type
|
|
|
|
{
|
|
|
|
none = 0,
|
|
|
|
not_found = -1,
|
|
|
|
regular = 1,
|
|
|
|
directory = 2,
|
|
|
|
symlink = 3,
|
|
|
|
block = 4,
|
|
|
|
character = 5,
|
|
|
|
fifo = 6,
|
|
|
|
socket = 7,
|
|
|
|
unknown = 8,
|
|
|
|
// also stands for a junction
|
|
|
|
directory_symlink = 42
|
|
|
|
};
|
|
|
|
|
|
|
|
struct file_status
|
|
|
|
{
|
|
|
|
explicit file_status(file_type type = file_type::none, perms permissions = perms::unknown) noexcept
|
|
|
|
: m_type(type), m_permissions(permissions)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
file_type type() const noexcept { return m_type; }
|
|
|
|
void type(file_type type) noexcept { m_type = type; }
|
|
|
|
|
|
|
|
perms permissions() const noexcept { return m_permissions; }
|
|
|
|
void permissions(perms perm) noexcept { m_permissions = perm; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
file_type m_type;
|
|
|
|
perms m_permissions;
|
|
|
|
};
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
using stdfs::file_type;
|
2019-08-09 12:00:43 -07:00
|
|
|
// to set up ADL correctly on `file_status` objects, we are defining
|
|
|
|
// this in our own namespace
|
2019-08-10 11:57:15 -07:00
|
|
|
struct file_status : private stdfs::file_status
|
|
|
|
{
|
2019-08-09 12:00:43 -07:00
|
|
|
using stdfs::file_status::file_status;
|
|
|
|
using stdfs::file_status::permissions;
|
2019-08-10 11:57:15 -07:00
|
|
|
using stdfs::file_status::type;
|
2019-08-09 12:00:43 -07:00
|
|
|
};
|
[vcpkg] Make Filesystem::remove_all faster #7570
I added benchmarks to measure how fast the parallel remove_all code was
-- it turns out, about 3x slower than stdfs::remove_all. Since this was
the case, I removed all of the parallelism and rewrote it serially, and
ended up about 30% faster than stdfs::remove_all (in addition to
supporting symlinks).
In addition, I did the following three orthogonal changes:
- simplified the work queue, basing it on Billy O'Neal's idea
- Fix warnings on older versions of compilers in tests, by splitting
the pragmas out of pch.h.
- Ran clang-format on some files
In fixing up remove_all, the following changes were made:
- On Windows, regular symlinks and directory symlinks are distinct;
as an example, to remove directory symlinks (and junctions, for that
matter), one must use RemoveDirectory. Only on Windows, I added new
`file_type` and `file_status` types, with `file_type` including a new
`directory_symlink` enumerator, and `file_status` being exactly the
same as the old one except using the new `file_type`. On Unix, I
didn't make that change since they don't make a distinction.
- I added new `symlink_status` and `status` functions which use the
new `file_status` on Windows.
- I made `Filesystem::exists` call `fs::exists(status(p))`, as opposed
to the old version which called `stdfs::exists` directly.
- Added benchmarks to `vcpkg-test/files.cpp`. They test the
performance of `remove_all` on small directories (~20 files), with
symlinks and without, and on large directories (~2000 files), with
symlinks and without.
2019-08-02 16:49:45 -07:00
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2019-08-09 12:00:43 -07:00
|
|
|
inline bool is_symlink(file_status s) noexcept
|
2019-07-11 18:16:10 -07:00
|
|
|
{
|
[vcpkg] Make Filesystem::remove_all faster #7570
I added benchmarks to measure how fast the parallel remove_all code was
-- it turns out, about 3x slower than stdfs::remove_all. Since this was
the case, I removed all of the parallelism and rewrote it serially, and
ended up about 30% faster than stdfs::remove_all (in addition to
supporting symlinks).
In addition, I did the following three orthogonal changes:
- simplified the work queue, basing it on Billy O'Neal's idea
- Fix warnings on older versions of compilers in tests, by splitting
the pragmas out of pch.h.
- Ran clang-format on some files
In fixing up remove_all, the following changes were made:
- On Windows, regular symlinks and directory symlinks are distinct;
as an example, to remove directory symlinks (and junctions, for that
matter), one must use RemoveDirectory. Only on Windows, I added new
`file_type` and `file_status` types, with `file_type` including a new
`directory_symlink` enumerator, and `file_status` being exactly the
same as the old one except using the new `file_type`. On Unix, I
didn't make that change since they don't make a distinction.
- I added new `symlink_status` and `status` functions which use the
new `file_status` on Windows.
- I made `Filesystem::exists` call `fs::exists(status(p))`, as opposed
to the old version which called `stdfs::exists` directly.
- Added benchmarks to `vcpkg-test/files.cpp`. They test the
performance of `remove_all` on small directories (~20 files), with
symlinks and without, and on large directories (~2000 files), with
symlinks and without.
2019-08-02 16:49:45 -07:00
|
|
|
#if defined(_WIN32)
|
2019-08-09 12:00:43 -07:00
|
|
|
if (s.type() == file_type::directory_symlink) return true;
|
[vcpkg] Make Filesystem::remove_all faster #7570
I added benchmarks to measure how fast the parallel remove_all code was
-- it turns out, about 3x slower than stdfs::remove_all. Since this was
the case, I removed all of the parallelism and rewrote it serially, and
ended up about 30% faster than stdfs::remove_all (in addition to
supporting symlinks).
In addition, I did the following three orthogonal changes:
- simplified the work queue, basing it on Billy O'Neal's idea
- Fix warnings on older versions of compilers in tests, by splitting
the pragmas out of pch.h.
- Ran clang-format on some files
In fixing up remove_all, the following changes were made:
- On Windows, regular symlinks and directory symlinks are distinct;
as an example, to remove directory symlinks (and junctions, for that
matter), one must use RemoveDirectory. Only on Windows, I added new
`file_type` and `file_status` types, with `file_type` including a new
`directory_symlink` enumerator, and `file_status` being exactly the
same as the old one except using the new `file_type`. On Unix, I
didn't make that change since they don't make a distinction.
- I added new `symlink_status` and `status` functions which use the
new `file_status` on Windows.
- I made `Filesystem::exists` call `fs::exists(status(p))`, as opposed
to the old version which called `stdfs::exists` directly.
- Added benchmarks to `vcpkg-test/files.cpp`. They test the
performance of `remove_all` on small directories (~20 files), with
symlinks and without, and on large directories (~2000 files), with
symlinks and without.
2019-08-02 16:49:45 -07:00
|
|
|
#endif
|
2019-08-09 12:00:43 -07:00
|
|
|
return s.type() == file_type::symlink;
|
|
|
|
}
|
2019-08-10 11:57:15 -07:00
|
|
|
inline bool is_regular_file(file_status s) { return s.type() == file_type::regular; }
|
|
|
|
inline bool is_directory(file_status s) { return s.type() == file_type::directory; }
|
|
|
|
inline bool exists(file_status s) { return s.type() != file_type::not_found && s.type() != file_type::none; }
|
2017-10-13 18:37:41 -07:00
|
|
|
}
|
2016-09-18 20:50:08 -07:00
|
|
|
|
2019-07-10 14:35:10 -07:00
|
|
|
/*
|
|
|
|
if someone attempts to use unqualified `symlink_status` or `is_symlink`,
|
|
|
|
they might get the ADL version, which is broken.
|
2019-08-09 12:00:43 -07:00
|
|
|
Therefore, put `(symlink_)?status` as deleted in the global namespace, so
|
|
|
|
that they get an error.
|
2019-07-11 15:01:29 -07:00
|
|
|
|
[vcpkg] Make Filesystem::remove_all faster #7570
I added benchmarks to measure how fast the parallel remove_all code was
-- it turns out, about 3x slower than stdfs::remove_all. Since this was
the case, I removed all of the parallelism and rewrote it serially, and
ended up about 30% faster than stdfs::remove_all (in addition to
supporting symlinks).
In addition, I did the following three orthogonal changes:
- simplified the work queue, basing it on Billy O'Neal's idea
- Fix warnings on older versions of compilers in tests, by splitting
the pragmas out of pch.h.
- Ran clang-format on some files
In fixing up remove_all, the following changes were made:
- On Windows, regular symlinks and directory symlinks are distinct;
as an example, to remove directory symlinks (and junctions, for that
matter), one must use RemoveDirectory. Only on Windows, I added new
`file_type` and `file_status` types, with `file_type` including a new
`directory_symlink` enumerator, and `file_status` being exactly the
same as the old one except using the new `file_type`. On Unix, I
didn't make that change since they don't make a distinction.
- I added new `symlink_status` and `status` functions which use the
new `file_status` on Windows.
- I made `Filesystem::exists` call `fs::exists(status(p))`, as opposed
to the old version which called `stdfs::exists` directly.
- Added benchmarks to `vcpkg-test/files.cpp`. They test the
performance of `remove_all` on small directories (~20 files), with
symlinks and without, and on large directories (~2000 files), with
symlinks and without.
2019-08-02 16:49:45 -07:00
|
|
|
We also want to poison the ADL on the other functions, because
|
2019-07-11 15:01:29 -07:00
|
|
|
we don't want people calling these functions on paths
|
2019-07-10 14:35:10 -07:00
|
|
|
*/
|
2019-08-09 12:00:43 -07:00
|
|
|
void status(const fs::path& p) = delete;
|
|
|
|
void status(const fs::path& p, std::error_code& ec) = delete;
|
|
|
|
void symlink_status(const fs::path& p) = delete;
|
|
|
|
void symlink_status(const fs::path& p, std::error_code& ec) = delete;
|
|
|
|
void is_symlink(const fs::path& p) = delete;
|
|
|
|
void is_symlink(const fs::path& p, std::error_code& ec) = delete;
|
|
|
|
void is_regular_file(const fs::path& p) = delete;
|
|
|
|
void is_regular_file(const fs::path& p, std::error_code& ec) = delete;
|
|
|
|
void is_directory(const fs::path& p) = delete;
|
|
|
|
void is_directory(const fs::path& p, std::error_code& ec) = delete;
|
2019-07-10 14:35:10 -07:00
|
|
|
|
2017-01-05 12:47:08 -08:00
|
|
|
namespace vcpkg::Files
|
2016-09-18 20:50:08 -07:00
|
|
|
{
|
2017-10-16 11:44:04 -07:00
|
|
|
struct Filesystem
|
2017-04-08 16:26:26 -07:00
|
|
|
{
|
2019-06-19 11:49:57 -07:00
|
|
|
std::string read_contents(const fs::path& file_path, LineInfo linfo) const;
|
2017-04-08 20:19:35 -07:00
|
|
|
virtual Expected<std::string> read_contents(const fs::path& file_path) const = 0;
|
2017-04-12 23:00:42 -07:00
|
|
|
virtual Expected<std::vector<std::string>> read_lines(const fs::path& file_path) const = 0;
|
2017-04-08 20:19:35 -07:00
|
|
|
virtual fs::path find_file_recursively_up(const fs::path& starting_dir, const std::string& filename) const = 0;
|
2017-04-12 23:15:02 -07:00
|
|
|
virtual std::vector<fs::path> get_files_recursive(const fs::path& dir) const = 0;
|
|
|
|
virtual std::vector<fs::path> get_files_non_recursive(const fs::path& dir) const = 0;
|
2019-06-19 11:49:57 -07:00
|
|
|
void write_lines(const fs::path& file_path, const std::vector<std::string>& lines, LineInfo linfo);
|
|
|
|
virtual void write_lines(const fs::path& file_path,
|
|
|
|
const std::vector<std::string>& lines,
|
|
|
|
std::error_code& ec) = 0;
|
|
|
|
void write_contents(const fs::path& path, const std::string& data, LineInfo linfo);
|
2018-02-21 22:18:15 -08:00
|
|
|
virtual void write_contents(const fs::path& file_path, const std::string& data, std::error_code& ec) = 0;
|
2019-06-19 11:49:57 -07:00
|
|
|
void rename(const fs::path& oldpath, const fs::path& newpath, LineInfo linfo);
|
2018-03-19 15:45:35 -07:00
|
|
|
virtual void rename(const fs::path& oldpath, const fs::path& newpath, std::error_code& ec) = 0;
|
2018-06-27 17:40:51 -07:00
|
|
|
virtual void rename_or_copy(const fs::path& oldpath,
|
|
|
|
const fs::path& newpath,
|
|
|
|
StringLiteral temp_suffix,
|
|
|
|
std::error_code& ec) = 0;
|
2019-06-19 11:49:57 -07:00
|
|
|
bool remove(const fs::path& path, LineInfo linfo);
|
2017-04-11 15:16:39 -07:00
|
|
|
virtual bool remove(const fs::path& path, std::error_code& ec) = 0;
|
2019-07-11 15:01:29 -07:00
|
|
|
|
[vcpkg] Make Filesystem::remove_all faster #7570
I added benchmarks to measure how fast the parallel remove_all code was
-- it turns out, about 3x slower than stdfs::remove_all. Since this was
the case, I removed all of the parallelism and rewrote it serially, and
ended up about 30% faster than stdfs::remove_all (in addition to
supporting symlinks).
In addition, I did the following three orthogonal changes:
- simplified the work queue, basing it on Billy O'Neal's idea
- Fix warnings on older versions of compilers in tests, by splitting
the pragmas out of pch.h.
- Ran clang-format on some files
In fixing up remove_all, the following changes were made:
- On Windows, regular symlinks and directory symlinks are distinct;
as an example, to remove directory symlinks (and junctions, for that
matter), one must use RemoveDirectory. Only on Windows, I added new
`file_type` and `file_status` types, with `file_type` including a new
`directory_symlink` enumerator, and `file_status` being exactly the
same as the old one except using the new `file_type`. On Unix, I
didn't make that change since they don't make a distinction.
- I added new `symlink_status` and `status` functions which use the
new `file_status` on Windows.
- I made `Filesystem::exists` call `fs::exists(status(p))`, as opposed
to the old version which called `stdfs::exists` directly.
- Added benchmarks to `vcpkg-test/files.cpp`. They test the
performance of `remove_all` on small directories (~20 files), with
symlinks and without, and on large directories (~2000 files), with
symlinks and without.
2019-08-02 16:49:45 -07:00
|
|
|
virtual void remove_all(const fs::path& path, std::error_code& ec, fs::path& failure_point) = 0;
|
|
|
|
void remove_all(const fs::path& path, LineInfo li);
|
|
|
|
bool exists(const fs::path& path, std::error_code& ec) const;
|
|
|
|
bool exists(LineInfo li, const fs::path& path) const;
|
|
|
|
// this should probably not exist, but would require a pass through of
|
|
|
|
// existing code to fix
|
|
|
|
bool exists(const fs::path& path) const;
|
2017-04-08 20:19:35 -07:00
|
|
|
virtual bool is_directory(const fs::path& path) const = 0;
|
|
|
|
virtual bool is_regular_file(const fs::path& path) const = 0;
|
|
|
|
virtual bool is_empty(const fs::path& path) const = 0;
|
|
|
|
virtual bool create_directory(const fs::path& path, std::error_code& ec) = 0;
|
2017-04-17 17:44:15 -07:00
|
|
|
virtual bool create_directories(const fs::path& path, std::error_code& ec) = 0;
|
2017-04-08 20:19:35 -07:00
|
|
|
virtual void copy(const fs::path& oldpath, const fs::path& newpath, fs::copy_options opts) = 0;
|
2017-10-16 11:44:04 -07:00
|
|
|
virtual bool copy_file(const fs::path& oldpath,
|
|
|
|
const fs::path& newpath,
|
|
|
|
fs::copy_options opts,
|
|
|
|
std::error_code& ec) = 0;
|
2018-10-17 12:46:27 -06:00
|
|
|
virtual void copy_symlink(const fs::path& oldpath, const fs::path& newpath, std::error_code& ec) = 0;
|
2017-04-11 15:16:39 -07:00
|
|
|
virtual fs::file_status status(const fs::path& path, std::error_code& ec) const = 0;
|
2018-10-17 12:46:27 -06:00
|
|
|
virtual fs::file_status symlink_status(const fs::path& path, std::error_code& ec) const = 0;
|
2019-08-09 12:00:43 -07:00
|
|
|
fs::file_status status(LineInfo li, const fs::path& p) const noexcept;
|
|
|
|
fs::file_status symlink_status(LineInfo li, const fs::path& p) const noexcept;
|
|
|
|
virtual fs::path canonical(const fs::path& path, std::error_code& ec) const = 0;
|
|
|
|
fs::path canonical(LineInfo li, const fs::path& path) const;
|
2018-02-21 22:18:15 -08:00
|
|
|
|
2018-06-27 16:29:16 -07:00
|
|
|
virtual std::vector<fs::path> find_from_PATH(const std::string& name) const = 0;
|
2017-04-08 16:26:26 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
Filesystem& get_real_filesystem();
|
|
|
|
|
2018-04-12 00:47:17 -07:00
|
|
|
static constexpr const char* FILESYSTEM_INVALID_CHARACTERS = R"(\/:*?"<>|)";
|
2016-09-23 17:57:18 -07:00
|
|
|
|
2016-12-16 19:38:02 -08:00
|
|
|
bool has_invalid_chars_for_filesystem(const std::string& s);
|
2016-09-23 17:57:18 -07:00
|
|
|
|
2016-11-30 14:08:43 -08:00
|
|
|
void print_paths(const std::vector<fs::path>& paths);
|
2017-01-05 12:47:08 -08:00
|
|
|
}
|