Skip to content

Commit

Permalink
[vcpkg] Initial Registries: Part 2 MVP (microsoft#14153)
Browse files Browse the repository at this point in the history
* [vcpkg wip] start implementation of registries pt. 2

* Remove the `ports` field of `VcpkgPaths`

This is an implementation detail, and so we want to make sure that
it's obvious that this is an internal detail; thus, we add a new function
`builtin_ports_directory()`,
which returns the directory where the builtin ports backing store is.

* continue WIP

* wip

* It works!

* format

* fix some issues

* switch from function static to DelayedInit
* fix lexically_normal for experimental::filesystem

* format

* fix missing include

* add STL notice

* whee error handling

* moar error handling!

* ignore extra files in registries

* formatting

* Billy CRs

* Update toolsrc/include/vcpkg/versiont.h

* fix add_filename test

* fix tests

* remove unused function add_filename
  • Loading branch information
strega-nil authored Nov 9, 2020
1 parent b5e7a72 commit 3d2c4d8
Show file tree
Hide file tree
Showing 29 changed files with 771 additions and 127 deletions.
29 changes: 29 additions & 0 deletions 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 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 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 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 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 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 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 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 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 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 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 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 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

0 comments on commit 3d2c4d8

Please sign in to comment.