Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[vcpkg] Initial Registries: Part 2 MVP #14153

Merged
merged 21 commits into from
Nov 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions toolsrc/include/vcpkg/base/delayed_init.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#pragma once

#include <vcpkg/base/optional.h>

#include <memory>
#include <mutex>

namespace vcpkg
{
// implements the equivalent of function static initialization for an object
template<class T>
struct DelayedInit
{
template<class F>
const T& get(F&& f) const
{
std::call_once(underlying_->flag_, [&f, this]() { underlying_->storage_ = std::forward<F>(f)(); });
return *underlying_->storage_.get();
}

private:
struct Storage
{
std::once_flag flag_;
Optional<T> storage_;
};
std::unique_ptr<Storage> underlying_ = std::make_unique<Storage>();
};
}
7 changes: 4 additions & 3 deletions toolsrc/include/vcpkg/base/files.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ namespace fs

path u8path(vcpkg::StringView s);
inline path u8path(const char* first, const char* last) { return u8path(vcpkg::StringView{first, last}); }
inline path u8path(std::initializer_list<char> il) { return u8path(vcpkg::StringView{il.begin(), il.end()}); }
inline path u8path(const char* s) { return u8path(vcpkg::StringView{s, s + ::strlen(s)}); }

#if defined(_MSC_VER)
Expand All @@ -58,6 +59,9 @@ namespace fs
std::string u8string(const path& p);
std::string generic_u8string(const path& p);

// equivalent to p.lexically_normal()
path lexically_normal(const path& p);

#if defined(_WIN32)
enum class file_type
{
Expand Down Expand Up @@ -251,9 +255,6 @@ namespace vcpkg::Files
constexpr char preferred_separator = '/';
#endif // _WIN32

// Adds file as a new path element to the end of base, with an additional slash if necessary
std::string add_filename(StringView base, StringView file);

#if defined(_WIN32)
fs::path win32_fix_path_case(const fs::path& source);
#endif // _WIN32
Expand Down
24 changes: 21 additions & 3 deletions toolsrc/include/vcpkg/base/jsonreader.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,24 @@ namespace vcpkg::Json
m_path.pop_back();
}

// value should be the value at key of the currently visited object
template<class Type>
void visit_at_index(const Value& value, int64_t index, Type& place, IDeserializer<Type>& visitor)
{
m_path.push_back(index);
auto opt = visitor.visit(*this, value);

if (auto p_opt = opt.get())
{
place = std::move(*p_opt);
}
else
{
add_expected_type_error(visitor.type_name());
}
m_path.pop_back();
}

// returns whether key \in obj
template<class Type>
bool optional_object_field(const Object& obj, StringView key, Type& place, IDeserializer<Type>& visitor)
Expand Down Expand Up @@ -167,8 +185,8 @@ namespace vcpkg::Json
}
};

VCPKG_MSVC_WARNING(push);
VCPKG_MSVC_WARNING(disable : 4505);
VCPKG_MSVC_WARNING(push)
VCPKG_MSVC_WARNING(disable : 4505)

template<class Type>
Optional<Type> IDeserializer<Type>::visit(Reader& r, const Value& value)
Expand Down Expand Up @@ -235,7 +253,7 @@ namespace vcpkg::Json
return nullopt;
}

VCPKG_MSVC_WARNING(pop);
VCPKG_MSVC_WARNING(pop)

struct StringDeserializer final : IDeserializer<std::string>
{
Expand Down
4 changes: 2 additions & 2 deletions toolsrc/include/vcpkg/base/optional.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ namespace vcpkg
constexpr OptionalStorage(const T& t) : m_is_present(true), m_t(t) { }
constexpr OptionalStorage(T&& t) : m_is_present(true), m_t(std::move(t)) { }
template<class U, class = std::enable_if_t<!std::is_reference<U>::value>>
constexpr explicit OptionalStorage(Optional<U>&& t) : m_is_present(false), m_inactive()
explicit OptionalStorage(Optional<U>&& t) : m_is_present(false), m_inactive()
{
if (auto p = t.get())
{
Expand All @@ -39,7 +39,7 @@ namespace vcpkg
}
}
template<class U>
constexpr explicit OptionalStorage(const Optional<U>& t) : m_is_present(false), m_inactive()
explicit OptionalStorage(const Optional<U>& t) : m_is_present(false), m_inactive()
{
if (auto p = t.get())
{
Expand Down
1 change: 1 addition & 0 deletions toolsrc/include/vcpkg/base/pragmas.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#define ASSUME(expr)
#endif

// the static_assert(true, "")s are to avoid the extra ';' warning
#ifdef _MSC_VER
#define VCPKG_MSVC_WARNING(...) __pragma(warning(__VA_ARGS__))
#define GCC_DIAGNOSTIC(...)
Expand Down
2 changes: 1 addition & 1 deletion toolsrc/include/vcpkg/configurationdeserializer.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ namespace vcpkg
constexpr static StringLiteral PATH = "path";

constexpr static StringLiteral KIND_BUILTIN = "builtin";
constexpr static StringLiteral KIND_DIRECTORY = "directory";
constexpr static StringLiteral KIND_FILESYSTEM = "filesystem";

virtual StringView type_name() const override;
virtual View<StringView> valid_fields() const override;
Expand Down
4 changes: 1 addition & 3 deletions toolsrc/include/vcpkg/dependencies.h
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,5 @@ namespace vcpkg::Dependencies
std::vector<std::string> features,
CMakeVars::CMakeVarProvider& var_provider);

void print_plan(const ActionPlan& action_plan,
const bool is_recursive = true,
const fs::path& default_ports_dir = {});
void print_plan(const ActionPlan& action_plan, const bool is_recursive = true, const fs::path& vcpkg_root_dir = {});
}
17 changes: 16 additions & 1 deletion toolsrc/include/vcpkg/registries.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,31 @@
#include <vcpkg/base/stringview.h>
#include <vcpkg/base/view.h>

#include <vcpkg/versiont.h>

#include <memory>
#include <string>
#include <system_error>
#include <vector>

namespace vcpkg
{
struct RegistryEntry
{
// returns fs::path() if version doesn't exist
virtual fs::path get_port_directory(const VcpkgPaths& paths, const VersionT& version) const = 0;

virtual ~RegistryEntry() = default;
};

struct RegistryImpl
{
virtual fs::path get_registry_root(const VcpkgPaths& paths) const = 0;
// returns nullptr if the port doesn't exist
virtual std::unique_ptr<RegistryEntry> get_port_entry(const VcpkgPaths& paths, StringView port_name) const = 0;
// appends the names of the ports to the out parameter
virtual void get_all_port_names(std::vector<std::string>& port_names, const VcpkgPaths& paths) const = 0;

virtual Optional<VersionT> get_baseline_version(const VcpkgPaths& paths, StringView port_name) const = 0;

virtual ~RegistryImpl() = default;
};
Expand Down
5 changes: 4 additions & 1 deletion toolsrc/include/vcpkg/vcpkgpaths.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ namespace vcpkg
fs::path buildtrees;
fs::path downloads;
fs::path packages;
fs::path ports;
fs::path installed;
fs::path triplets;
fs::path community_triplets;
Expand Down Expand Up @@ -128,6 +127,10 @@ namespace vcpkg
const FeatureFlagSettings& get_feature_flags() const;
void track_feature_flag_metrics() const;

// the directory of the builtin ports
// this should be used only for helper commands, not core commands like `install`.
fs::path builtin_ports_directory() const { return root / fs::u8path("ports"); }

private:
std::unique_ptr<details::VcpkgPathsImpl> m_pimpl;
};
Expand Down
8 changes: 8 additions & 0 deletions toolsrc/include/vcpkg/versiont.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#pragma once

#include <string>

namespace vcpkg
Expand All @@ -14,6 +15,8 @@ namespace vcpkg
friend bool operator==(const VersionT& left, const VersionT& right);
friend bool operator!=(const VersionT& left, const VersionT& right);

friend struct VersionTMapLess;

private:
std::string value;
int port_version;
Expand All @@ -29,4 +32,9 @@ namespace vcpkg

std::string to_string() const;
};

struct VersionTMapLess
{
bool operator()(const VersionT& left, const VersionT& right) const;
};
}
2 changes: 1 addition & 1 deletion toolsrc/src/vcpkg-test/commands.create.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ TEST_CASE ("create smoke test", "[commands-create]")
VcpkgPaths paths(fsWrapper, args);
const auto exit_code = Commands::Create::perform(args, paths);
REQUIRE(exit_code == 0);
const auto expected_port = paths.ports / fs::u8path("zlib2");
const auto expected_port = paths.builtin_ports_directory() / fs::u8path("zlib2");
const auto expected_portfile_cmake = expected_port / fs::u8path("portfile.cmake");
const auto lines = fsWrapper.read_lines(expected_portfile_cmake);
REQUIRE(lines.has_value());
Expand Down
105 changes: 90 additions & 15 deletions toolsrc/src/vcpkg-test/files.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,96 @@ TEST_CASE ("remove all", "[files]")
CHECK_EC_ON_FILE(temp_dir, ec);
}

TEST_CASE ("lexically_normal", "[files]")
{
const auto lexically_normal = [](const char* s) { return fs::lexically_normal(fs::u8path(s)); };
const auto native = [](const char* s) { return std::move(fs::u8path(s).make_preferred()); };
CHECK(fs::lexically_normal(fs::path()).native() == fs::path().native());

// these test cases are taken from the MS STL tests
CHECK(lexically_normal("cat/./dog/..").native() == native("cat/").native());
CHECK(lexically_normal("cat/.///dog/../").native() == native("cat/").native());

CHECK(lexically_normal("cat/./dog/..").native() == native("cat/").native());
CHECK(lexically_normal("cat/.///dog/../").native() == native("cat/").native());

CHECK(lexically_normal(".").native() == native(".").native());
CHECK(lexically_normal("./").native() == native(".").native());
CHECK(lexically_normal("./.").native() == native(".").native());
CHECK(lexically_normal("././").native() == native(".").native());

CHECK(lexically_normal("../../..").native() == native("../../..").native());
CHECK(lexically_normal("../../../").native() == native("../../..").native());

CHECK(lexically_normal("../../../a/b/c").native() == native("../../../a/b/c").native());

CHECK(lexically_normal("/../../..").native() == native("/").native());
CHECK(lexically_normal("/../../../").native() == native("/").native());

CHECK(lexically_normal("/../../../a/b/c").native() == native("/a/b/c").native());

CHECK(lexically_normal("a/..").native() == native(".").native());
CHECK(lexically_normal("a/../").native() == native(".").native());

#if defined(_WIN32)
CHECK(lexically_normal(R"(X:)").native() == LR"(X:)");

CHECK(lexically_normal(R"(X:DriveRelative)").native() == LR"(X:DriveRelative)");

CHECK(lexically_normal(R"(X:\)").native() == LR"(X:\)");
CHECK(lexically_normal(R"(X:/)").native() == LR"(X:\)");
CHECK(lexically_normal(R"(X:\\\)").native() == LR"(X:\)");
CHECK(lexically_normal(R"(X:///)").native() == LR"(X:\)");

CHECK(lexically_normal(R"(X:\DosAbsolute)").native() == LR"(X:\DosAbsolute)");
CHECK(lexically_normal(R"(X:/DosAbsolute)").native() == LR"(X:\DosAbsolute)");
CHECK(lexically_normal(R"(X:\\\DosAbsolute)").native() == LR"(X:\DosAbsolute)");
CHECK(lexically_normal(R"(X:///DosAbsolute)").native() == LR"(X:\DosAbsolute)");

CHECK(lexically_normal(R"(\RootRelative)").native() == LR"(\RootRelative)");
CHECK(lexically_normal(R"(/RootRelative)").native() == LR"(\RootRelative)");
CHECK(lexically_normal(R"(\\\RootRelative)").native() == LR"(\RootRelative)");
CHECK(lexically_normal(R"(///RootRelative)").native() == LR"(\RootRelative)");

CHECK(lexically_normal(R"(\\server\share)").native() == LR"(\\server\share)");
CHECK(lexically_normal(R"(//server/share)").native() == LR"(\\server\share)");
CHECK(lexically_normal(R"(\\server\\\share)").native() == LR"(\\server\share)");
CHECK(lexically_normal(R"(//server///share)").native() == LR"(\\server\share)");

CHECK(lexically_normal(R"(\\?\device)").native() == LR"(\\?\device)");
CHECK(lexically_normal(R"(//?/device)").native() == LR"(\\?\device)");

CHECK(lexically_normal(R"(\??\device)").native() == LR"(\??\device)");
CHECK(lexically_normal(R"(/??/device)").native() == LR"(\??\device)");

CHECK(lexically_normal(R"(\\.\device)").native() == LR"(\\.\device)");
CHECK(lexically_normal(R"(//./device)").native() == LR"(\\.\device)");

CHECK(lexically_normal(R"(\\?\UNC\server\share)").native() == LR"(\\?\UNC\server\share)");
CHECK(lexically_normal(R"(//?/UNC/server/share)").native() == LR"(\\?\UNC\server\share)");

CHECK(lexically_normal(R"(C:\a/b\\c\/d/\e//f)").native() == LR"(C:\a\b\c\d\e\f)");

CHECK(lexically_normal(R"(C:\meow\)").native() == LR"(C:\meow\)");
CHECK(lexically_normal(R"(C:\meow/)").native() == LR"(C:\meow\)");
CHECK(lexically_normal(R"(C:\meow\\)").native() == LR"(C:\meow\)");
CHECK(lexically_normal(R"(C:\meow\/)").native() == LR"(C:\meow\)");
CHECK(lexically_normal(R"(C:\meow/\)").native() == LR"(C:\meow\)");
CHECK(lexically_normal(R"(C:\meow//)").native() == LR"(C:\meow\)");

CHECK(lexically_normal(R"(C:\a\.\b\.\.\c\.\.\.)").native() == LR"(C:\a\b\c\)");
CHECK(lexically_normal(R"(C:\a\.\b\.\.\c\.\.\.\)").native() == LR"(C:\a\b\c\)");

CHECK(lexically_normal(R"(C:\a\b\c\d\e\..\f\..\..\..\g\h)").native() == LR"(C:\a\b\g\h)");

CHECK(lexically_normal(R"(C:\a\b\c\d\e\..\f\..\..\..\g\h\..)").native() == LR"(C:\a\b\g\)");
CHECK(lexically_normal(R"(C:\a\b\c\d\e\..\f\..\..\..\g\h\..\)").native() == LR"(C:\a\b\g\)");
CHECK(lexically_normal(
R"(/\server/\share/\a/\b/\c/\./\./\d/\../\../\../\../\../\../\../\other/x/y/z/.././..\meow.txt)")
.native() == LR"(\\server\other\x\meow.txt)");
#endif
}

#if defined(_WIN32)
TEST_CASE ("win32_fix_path_case", "[files]")
{
Expand Down Expand Up @@ -250,21 +340,6 @@ TEST_CASE ("win32_fix_path_case", "[files]")
}
#endif // _WIN32

TEST_CASE ("add_filename", "[files]")
{
using vcpkg::Files::add_filename;
using vcpkg::Files::preferred_separator;

CHECK(add_filename("a/b", "c") == std::string("a/b") + preferred_separator + "c");
CHECK(add_filename("a/b/", "c") == "a/b/c");
CHECK(add_filename("a/b\\", "c") == "a/b\\c");
CHECK(add_filename("", "c") == "c");

// note that we don't special case slashes in the second argument; the caller shouldn't do that
CHECK(add_filename("a/b/", "\\c") == "a/b/\\c");
CHECK(add_filename("a/b\\", "/c") == "a/b\\/c");
}

#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
TEST_CASE ("remove all -- benchmarks", "[files][!benchmark]")
{
Expand Down
2 changes: 1 addition & 1 deletion toolsrc/src/vcpkg-test/manifests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ TEST_CASE ("Serialize all the ports", "[manifests]")

std::vector<SourceControlFile> scfs;

for (auto dir : fs::directory_iterator(paths.ports))
for (auto dir : fs::directory_iterator(paths.builtin_ports_directory()))
{
const auto control = dir / fs::u8path("CONTROL");
const auto manifest = dir / fs::u8path("vcpkg.json");
Expand Down
Loading