[vcpkg] Initial addition of Filesystem abstraction to enable testing.

This commit is contained in:
Robert Schumacher 2017-04-08 16:26:26 -07:00
parent 19123677d1
commit c434dc9986
22 changed files with 86 additions and 62 deletions

View File

@ -11,16 +11,16 @@ namespace vcpkg::Paragraphs
{
using ParagraphDataMap = std::unordered_map<std::string, std::string>;
Expected<ParagraphDataMap> get_single_paragraph(const fs::path& control_path);
Expected<std::vector<ParagraphDataMap>> get_paragraphs(const fs::path& control_path);
Expected<ParagraphDataMap> get_single_paragraph(Files::Filesystem& fs, const fs::path& control_path);
Expected<std::vector<ParagraphDataMap>> get_paragraphs(Files::Filesystem& fs, const fs::path& control_path);
Expected<ParagraphDataMap> parse_single_paragraph(const std::string& str);
Expected<std::vector<ParagraphDataMap>> parse_paragraphs(const std::string& str);
Expected<SourceParagraph> try_load_port(const fs::path& control_path);
Expected<SourceParagraph> try_load_port(Files::Filesystem& fs, const fs::path& control_path);
Expected<BinaryParagraph> try_load_cached_package(const VcpkgPaths& paths, const PackageSpec& spec);
std::vector<SourceParagraph> load_all_ports(const fs::path& ports_dir);
std::vector<SourceParagraph> load_all_ports(Files::Filesystem& fs, const fs::path& ports_dir);
std::map<std::string, VersionT> extract_port_names_and_versions(const std::vector<SourceParagraph>& source_paragraphs);
}

View File

@ -1,6 +1,7 @@
#pragma once
#include "filesystem_fs.h"
#include "vcpkg_Files.h"
#include "PostBuildLint_BuildPolicies.h"
#include "OptBool.h"
#include "PostBuildLint_LinkageType.h"
@ -17,5 +18,5 @@ namespace vcpkg::PostBuildLint
std::map<BuildPolicies::Type, OptBoolT> policies;
};
BuildInfo read_build_info(const fs::path& filepath);
BuildInfo read_build_info(Files::Filesystem& fs, const fs::path& filepath);
}

View File

@ -4,6 +4,7 @@
#include "PackageSpec.h"
#include "BinaryParagraph.h"
#include "Lazy.h"
#include "vcpkg_Files.h"
namespace vcpkg
{
@ -49,6 +50,8 @@ namespace vcpkg
const fs::path& get_nuget_exe() const;
const Toolset& get_toolset() const;
Files::Filesystem& get_filesystem() const;
private:
Lazy<fs::path> cmake_exe;
Lazy<fs::path> git_exe;

View File

@ -6,11 +6,17 @@
namespace vcpkg::Files
{
__interface Filesystem
{
virtual Expected<std::string> read_contents(const fs::path& file_path) noexcept = 0;
};
Filesystem& get_real_filesystem();
static const char* FILESYSTEM_INVALID_CHARACTERS = R"(\/:*?"<>|)";
bool has_invalid_chars_for_filesystem(const std::string& s);
Expected<std::string> read_contents(const fs::path& file_path) noexcept;
Expected<std::vector<std::string>> read_all_lines(const fs::path& file_path);

View File

@ -172,9 +172,9 @@ namespace vcpkg::Paragraphs
}
};
Expected<std::unordered_map<std::string, std::string>> get_single_paragraph(const fs::path& control_path)
Expected<std::unordered_map<std::string, std::string>> get_single_paragraph(Files::Filesystem& fs, const fs::path& control_path)
{
const Expected<std::string> contents = Files::read_contents(control_path);
const Expected<std::string> contents = fs.read_contents(control_path);
if (auto spgh = contents.get())
{
return parse_single_paragraph(*spgh);
@ -183,9 +183,9 @@ namespace vcpkg::Paragraphs
return contents.error_code();
}
Expected<std::vector<std::unordered_map<std::string, std::string>>> get_paragraphs(const fs::path& control_path)
Expected<std::vector<std::unordered_map<std::string, std::string>>> get_paragraphs(Files::Filesystem& fs, const fs::path& control_path)
{
const Expected<std::string> contents = Files::read_contents(control_path);
const Expected<std::string> contents = fs.read_contents(control_path);
if (auto spgh = contents.get())
{
return parse_paragraphs(*spgh);
@ -211,9 +211,9 @@ namespace vcpkg::Paragraphs
return Parser(str.c_str(), str.c_str() + str.size()).get_paragraphs();
}
Expected<SourceParagraph> try_load_port(const fs::path& path)
Expected<SourceParagraph> try_load_port(Files::Filesystem& fs, const fs::path& path)
{
Expected<std::unordered_map<std::string, std::string>> pghs = get_single_paragraph(path / "CONTROL");
Expected<std::unordered_map<std::string, std::string>> pghs = get_single_paragraph(fs, path / "CONTROL");
if (auto p = pghs.get())
{
return SourceParagraph(*p);
@ -224,7 +224,7 @@ namespace vcpkg::Paragraphs
Expected<BinaryParagraph> try_load_cached_package(const VcpkgPaths& paths, const PackageSpec& spec)
{
Expected<std::unordered_map<std::string, std::string>> pghs = get_single_paragraph(paths.package_dir(spec) / "CONTROL");
Expected<std::unordered_map<std::string, std::string>> pghs = get_single_paragraph(paths.get_filesystem(), paths.package_dir(spec) / "CONTROL");
if (auto p = pghs.get())
{
@ -234,13 +234,13 @@ namespace vcpkg::Paragraphs
return pghs.error_code();
}
std::vector<SourceParagraph> load_all_ports(const fs::path& ports_dir)
std::vector<SourceParagraph> load_all_ports(Files::Filesystem& fs, const fs::path& ports_dir)
{
std::vector<SourceParagraph> output;
for (auto it = fs::directory_iterator(ports_dir); it != fs::directory_iterator(); ++it)
{
const fs::path& path = it->path();
Expected<SourceParagraph> source_paragraph = try_load_port(path);
Expected<SourceParagraph> source_paragraph = try_load_port(fs, path);
if (auto srcpgh = source_paragraph.get())
{
output.emplace_back(std::move(*srcpgh));

View File

@ -624,7 +624,7 @@ namespace vcpkg::PostBuildLint
// for dumpbin
const Toolset& toolset = paths.get_toolset();
BuildInfo build_info = read_build_info(paths.build_info_file_path(spec));
BuildInfo build_info = read_build_info(paths.get_filesystem(), paths.build_info_file_path(spec));
const fs::path package_dir = paths.package_dir(spec);
size_t error_count = 0;

View File

@ -37,9 +37,9 @@ namespace vcpkg::PostBuildLint
return build_info;
}
BuildInfo read_build_info(const fs::path& filepath)
BuildInfo read_build_info(Files::Filesystem& fs, const fs::path& filepath)
{
const Expected<std::unordered_map<std::string, std::string>> pghs = Paragraphs::get_single_paragraph(filepath);
const Expected<std::unordered_map<std::string, std::string>> pghs = Paragraphs::get_single_paragraph(fs, filepath);
Checks::check_exit(VCPKG_LINE_INFO, pghs.get() != nullptr, "Invalid BUILD_INFO file for package");
return BuildInfo::create(*pghs.get());
}

View File

@ -6,6 +6,7 @@
#include "PackageSpec.h"
#include "vcpkg_Files.h"
#include "vcpkg_Util.h"
#include "..\include\VcpkgPaths.h"
namespace vcpkg
{
@ -335,4 +336,8 @@ namespace vcpkg
{
return this->toolset.get_lazy([this]() { return find_toolset_instance(*this); });
}
Files::Filesystem & VcpkgPaths::get_filesystem() const
{
return Files::get_real_filesystem();
}
}

View File

@ -140,7 +140,7 @@ namespace vcpkg::Commands::Build
Checks::exit_success(VCPKG_LINE_INFO);
}
const Expected<SourceParagraph> maybe_spgh = Paragraphs::try_load_port(port_dir);
const Expected<SourceParagraph> maybe_spgh = Paragraphs::try_load_port(paths.get_filesystem(), port_dir);
Checks::check_exit(VCPKG_LINE_INFO, !maybe_spgh.error_code(), "Could not find package named %s: %s", spec, maybe_spgh.error_code().message());
const SourceParagraph& spgh = *maybe_spgh.get();

View File

@ -13,7 +13,7 @@ namespace vcpkg::Commands::Cache
for (auto it = fs::directory_iterator(paths.packages); it != fs::directory_iterator(); ++it)
{
const fs::path& path = it->path();
const Expected<std::unordered_map<std::string, std::string>> pghs = Paragraphs::get_single_paragraph(path / "CONTROL");
const Expected<std::unordered_map<std::string, std::string>> pghs = Paragraphs::get_single_paragraph(paths.get_filesystem(), path / "CONTROL");
if (auto p = pghs.get())
{
const BinaryParagraph binary_paragraph = BinaryParagraph(*p);

View File

@ -14,9 +14,9 @@ namespace vcpkg::Commands::CI
using Dependencies::InstallPlanType;
using Build::BuildResult;
static std::vector<PackageSpec> load_all_package_specs(const fs::path& ports_directory, const Triplet& target_triplet)
static std::vector<PackageSpec> load_all_package_specs(Files::Filesystem& fs, const fs::path& ports_directory, const Triplet& target_triplet)
{
std::vector<SourceParagraph> ports = Paragraphs::load_all_ports(ports_directory);
std::vector<SourceParagraph> ports = Paragraphs::load_all_ports(fs, ports_directory);
std::vector<PackageSpec> specs;
for (const SourceParagraph& p : ports)
{
@ -33,7 +33,7 @@ namespace vcpkg::Commands::CI
const Triplet target_triplet = args.command_arguments.size() == 1 ? Triplet::from_canonical_name(args.command_arguments.at(0)) : default_target_triplet;
Input::check_triplet(target_triplet, paths);
args.check_and_get_optional_command_arguments({});
const std::vector<PackageSpec> specs = load_all_package_specs(paths.ports, target_triplet);
const std::vector<PackageSpec> specs = load_all_package_specs(paths.get_filesystem(), paths.ports, target_triplet);
StatusParagraphs status_db = database_load_check(paths);
const std::vector<PackageSpecWithInstallPlan> install_plan = Dependencies::create_install_plan(paths, specs, status_db);

View File

@ -12,7 +12,7 @@ namespace vcpkg::Commands::DependInfo
args.check_exact_arg_count(0, example);
args.check_and_get_optional_command_arguments({});
const std::vector<SourceParagraph> source_paragraphs = Paragraphs::load_all_ports(paths.ports);
const std::vector<SourceParagraph> source_paragraphs = Paragraphs::load_all_ports(paths.get_filesystem(), paths.ports);
for (const SourceParagraph& source_paragraph : source_paragraphs)
{

View File

@ -78,7 +78,7 @@ namespace vcpkg::Commands::Import
const fs::path include_directory(args.command_arguments[1]);
const fs::path project_directory(args.command_arguments[2]);
const Expected<std::unordered_map<std::string, std::string>> pghs = Paragraphs::get_single_paragraph(control_file_path);
const Expected<std::unordered_map<std::string, std::string>> pghs = Paragraphs::get_single_paragraph(paths.get_filesystem(), control_file_path);
Checks::check_exit(VCPKG_LINE_INFO, pghs.get() != nullptr, "Invalid control file %s for package", control_file_path.generic_string());
StatusParagraph spgh;

View File

@ -166,7 +166,7 @@ namespace vcpkg::Commands::Integrate
fs::create_directory(tmp_dir);
bool should_install_system = true;
const Expected<std::string> system_wide_file_contents = Files::read_contents(system_wide_targets_file);
const Expected<std::string> system_wide_file_contents = paths.get_filesystem().read_contents(system_wide_targets_file);
if (auto contents_data = system_wide_file_contents.get())
{
std::regex re(R"###(<!-- version (\d+) -->)###");

View File

@ -85,7 +85,7 @@ namespace vcpkg::Commands::PortsDiff
L".vcpkg-root",
git_exe.native());
System::cmd_execute_clean(cmd);
const std::vector<SourceParagraph> source_paragraphs = Paragraphs::load_all_ports(temp_checkout_path / ports_dir_name_as_string);
const std::vector<SourceParagraph> source_paragraphs = Paragraphs::load_all_ports(paths.get_filesystem(), temp_checkout_path / ports_dir_name_as_string);
const std::map<std::string, VersionT> names_and_versions = Paragraphs::extract_port_names_and_versions(source_paragraphs);
fs::remove_all(temp_checkout_path);
return names_and_versions;

View File

@ -59,7 +59,7 @@ namespace vcpkg::Commands::Search
args.check_max_arg_count(1, example);
const std::unordered_set<std::string> options = args.check_and_get_optional_command_arguments({ OPTION_GRAPH });
const std::vector<SourceParagraph> source_paragraphs = Paragraphs::load_all_ports(paths.ports);
const std::vector<SourceParagraph> source_paragraphs = Paragraphs::load_all_ports(paths.get_filesystem(), paths.ports);
if (options.find(OPTION_GRAPH) != options.cend())
{
const std::string graph_as_string = create_graph_as_string(source_paragraphs);

View File

@ -14,7 +14,7 @@ namespace vcpkg::Commands::Update
std::vector<OutdatedPackage> find_outdated_packages(const VcpkgPaths& paths, const StatusParagraphs& status_db)
{
const std::vector<SourceParagraph> source_paragraphs = Paragraphs::load_all_ports(paths.ports);
const std::vector<SourceParagraph> source_paragraphs = Paragraphs::load_all_ports(paths.get_filesystem(), paths.ports);
const std::map<std::string, VersionT> src_names_to_versions = Paragraphs::extract_port_names_and_versions(source_paragraphs);
const std::vector<StatusParagraph*> installed_packages = get_installed_ports(status_db);
@ -64,7 +64,7 @@ namespace vcpkg::Commands::Update
" vcpkg install <pkgs>...");
}
auto version_file = Files::read_contents(paths.root / "toolsrc" / "VERSION.txt");
auto version_file = paths.get_filesystem().read_contents(paths.root / "toolsrc" / "VERSION.txt");
if (auto version_contents = version_file.get())
{
int maj1, min1, rev1;

View File

@ -111,7 +111,7 @@ static void loadConfig()
try
{
auto maybe_pghs = Paragraphs::get_paragraphs(localappdata / "vcpkg" / "config");
auto maybe_pghs = Paragraphs::get_paragraphs(Files::get_real_filesystem(), localappdata / "vcpkg" / "config");
if (auto p_pghs = maybe_pghs.get())
{
const auto& pghs = *p_pghs;

View File

@ -100,7 +100,7 @@ namespace vcpkg::Dependencies
continue;
}
Expected<SourceParagraph> maybe_spgh = Paragraphs::try_load_port(paths.port_dir(spec));
Expected<SourceParagraph> maybe_spgh = Paragraphs::try_load_port(paths.get_filesystem(), paths.port_dir(spec));
if (auto spgh = maybe_spgh.get())
{
process_dependencies(filter_dependencies(spgh->depends, spec.target_triplet()));

View File

@ -6,36 +6,45 @@ namespace vcpkg::Files
{
static const std::regex FILESYSTEM_INVALID_CHARACTERS_REGEX = std::regex(R"([\/:*?"<>|])");
struct RealFilesystem : Filesystem
{
Expected<std::string> read_contents(const fs::path& file_path) noexcept override
{
std::fstream file_stream(file_path, std::ios_base::in | std::ios_base::binary);
if (file_stream.fail())
{
return std::errc::no_such_file_or_directory;
}
file_stream.seekg(0, file_stream.end);
auto length = file_stream.tellg();
file_stream.seekg(0, file_stream.beg);
if (length > SIZE_MAX)
{
return std::errc::file_too_large;
}
std::string output;
output.resize(static_cast<size_t>(length));
file_stream.read(&output[0], length);
file_stream.close();
return std::move(output);
}
};
Filesystem & get_real_filesystem()
{
static RealFilesystem real_fs;
return real_fs;
}
bool has_invalid_chars_for_filesystem(const std::string& s)
{
return std::regex_search(s, FILESYSTEM_INVALID_CHARACTERS_REGEX);
}
Expected<std::string> read_contents(const fs::path& file_path) noexcept
{
std::fstream file_stream(file_path, std::ios_base::in | std::ios_base::binary);
if (file_stream.fail())
{
return std::errc::no_such_file_or_directory;
}
file_stream.seekg(0, file_stream.end);
auto length = file_stream.tellg();
file_stream.seekg(0, file_stream.beg);
if (length > SIZE_MAX)
{
return std::errc::file_too_large;
}
std::string output;
output.resize(static_cast<size_t>(length));
file_stream.read(&output[0], length);
file_stream.close();
return std::move(output);
}
Expected<std::vector<std::string>> read_all_lines(const fs::path& file_path)
{
std::fstream file_stream(file_path, std::ios_base::in | std::ios_base::binary);

View File

@ -11,5 +11,5 @@ int WINAPI WinMain(_In_ HINSTANCE, _In_opt_ HINSTANCE, _In_ LPSTR, _In_ int)
LPWSTR * szArgList = CommandLineToArgvW(GetCommandLineW(), &argCount);
Checks::check_exit(VCPKG_LINE_INFO, argCount == 2, "Requires exactly one argument, the path to the payload file");
Metrics::upload(Files::read_contents(szArgList[1]).value_or_exit(VCPKG_LINE_INFO));
Metrics::upload(Files::get_real_filesystem().read_contents(szArgList[1]).value_or_exit(VCPKG_LINE_INFO));
}

View File

@ -9,7 +9,7 @@ namespace vcpkg
{
bool g_debugging = false;
static StatusParagraphs load_current_database(const fs::path& vcpkg_dir_status_file, const fs::path& vcpkg_dir_status_file_old)
static StatusParagraphs load_current_database(Files::Filesystem& fs, const fs::path& vcpkg_dir_status_file, const fs::path& vcpkg_dir_status_file_old)
{
if (!fs::exists(vcpkg_dir_status_file))
{
@ -22,7 +22,7 @@ namespace vcpkg
fs::rename(vcpkg_dir_status_file_old, vcpkg_dir_status_file);
}
auto pghs = Paragraphs::get_paragraphs(vcpkg_dir_status_file).value_or_exit(VCPKG_LINE_INFO);
auto pghs = Paragraphs::get_paragraphs(fs, vcpkg_dir_status_file).value_or_exit(VCPKG_LINE_INFO);
std::vector<std::unique_ptr<StatusParagraph>> status_pghs;
for (auto&& p : pghs)
@ -47,7 +47,7 @@ namespace vcpkg
const fs::path status_file_old = status_file.parent_path() / "status-old";
const fs::path status_file_new = status_file.parent_path() / "status-new";
StatusParagraphs current_status_db = load_current_database(status_file, status_file_old);
StatusParagraphs current_status_db = load_current_database(paths.get_filesystem(), status_file, status_file_old);
auto b = fs::directory_iterator(updates_dir);
auto e = fs::directory_iterator();
@ -64,7 +64,7 @@ namespace vcpkg
if (b->path().filename() == "incomplete")
continue;
auto pghs = Paragraphs::get_paragraphs(b->path()).value_or_exit(VCPKG_LINE_INFO);
auto pghs = Paragraphs::get_paragraphs(paths.get_filesystem(), b->path()).value_or_exit(VCPKG_LINE_INFO);
for (auto&& p : pghs)
{
current_status_db.insert(std::make_unique<StatusParagraph>(p));