[vcpkg] Fix "just-in-time" requirements calculation

This commit is contained in:
Robert Schumacher 2018-02-25 10:13:57 -08:00
parent 99d30fa105
commit 8b97ae2dc1
8 changed files with 115 additions and 57 deletions

View File

@ -127,6 +127,15 @@ namespace vcpkg::Util
std::sort(begin(cont), end(cont));
}
template<class Range>
void sort_unique_erase(Range& cont)
{
using std::begin;
using std::end;
std::sort(begin(cont), end(cont));
cont.erase(std::unique(begin(cont), end(cont)), end(cont));
}
template<class Range1, class Range2>
bool all_equal(const Range1& r1, const Range2& r2)
{

View File

@ -12,6 +12,7 @@
#include <array>
#include <map>
#include <set>
#include <vector>
namespace vcpkg::Build
@ -125,7 +126,7 @@ namespace vcpkg::Build
const Triplet& triplet,
fs::path&& port_dir,
const BuildPackageOptions& build_package_options,
const std::unordered_set<std::string>& feature_list)
const std::set<std::string>& feature_list)
: scf(src)
, triplet(triplet)
, port_dir(std::move(port_dir))
@ -138,7 +139,7 @@ namespace vcpkg::Build
const Triplet& triplet;
fs::path port_dir;
const BuildPackageOptions& build_package_options;
const std::unordered_set<std::string>& feature_list;
const std::set<std::string>& feature_list;
};
ExtendedBuildResult build_package(const VcpkgPaths& paths,

View File

@ -120,6 +120,7 @@ namespace vcpkg::Commands
namespace Hash
{
void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths);
std::string get_file_hash(fs::path const& cmake_exe_path, fs::path const& path, std::string const& hash_type);
}
template<class T>

View File

@ -39,12 +39,12 @@ namespace vcpkg::Dependencies
InstallPlanAction(const PackageSpec& spec,
InstalledPackageView&& spghs,
const std::unordered_set<std::string>& features,
const std::set<std::string>& features,
const RequestType& request_type);
InstallPlanAction(const PackageSpec& spec,
const SourceControlFile& scf,
const std::unordered_set<std::string>& features,
const std::set<std::string>& features,
const RequestType& request_type);
std::string displayname() const;
@ -57,7 +57,7 @@ namespace vcpkg::Dependencies
InstallPlanType plan_type;
RequestType request_type;
Build::BuildPackageOptions build_options;
std::unordered_set<std::string> feature_list;
std::set<std::string> feature_list;
};
enum class RemovePlanType

View File

@ -66,7 +66,8 @@ namespace vcpkg::Build::Command
Build::CleanBuildtrees::NO,
Build::CleanPackages::NO};
const std::unordered_set<std::string> features_as_set(full_spec.features.begin(), full_spec.features.end());
std::set<std::string> features_as_set(full_spec.features.begin(), full_spec.features.end());
features_as_set.emplace("core");
const Build::BuildPackageConfig build_config{
*scf, spec.triplet(), fs::path{port_dir}, build_package_options, features_as_set};
@ -260,56 +261,93 @@ namespace vcpkg::Build
paths.get_filesystem().write_contents(binary_control_file, start);
}
static std::vector<FeatureSpec> compute_required_feature_specs(const BuildPackageConfig& config,
const StatusParagraphs& status_db)
{
const Triplet& triplet = config.triplet;
auto dep_strings =
Util::fmap_flatten(config.feature_list, [&](std::string const& feature) -> std::vector<std::string> {
if (feature == "core")
{
return filter_dependencies(config.scf.core_paragraph->depends, triplet);
}
auto it =
Util::find_if(config.scf.feature_paragraphs,
[&](std::unique_ptr<FeatureParagraph> const& fpgh) { return fpgh->name == feature; });
Checks::check_exit(VCPKG_LINE_INFO, it != config.scf.feature_paragraphs.end());
return filter_dependencies(it->get()->depends, triplet);
});
auto dep_fspecs = FeatureSpec::from_strings_and_triplet(dep_strings, triplet);
Util::sort_unique_erase(dep_fspecs);
// expand defaults
std::vector<FeatureSpec> ret;
for (auto&& fspec : dep_fspecs)
{
if (fspec.feature().empty())
{
// reference to default features
auto it = status_db.find_installed(fspec.spec());
if (it == status_db.end())
{
// not currently installed, so just leave the default reference so it will fail later
ret.push_back(fspec);
}
else
{
ret.push_back(FeatureSpec{fspec.spec(), "core"});
for (auto&& default_feature : it->get()->package.default_features)
ret.push_back(FeatureSpec{fspec.spec(), default_feature});
}
}
else
{
ret.push_back(fspec);
}
}
Util::sort_unique_erase(ret);
return ret;
}
static ExtendedBuildResult do_build_package(const VcpkgPaths& paths,
const BuildPackageConfig& config,
const StatusParagraphs& status_db)
{
const PackageSpec spec = PackageSpec::from_name_and_triplet(config.scf.core_paragraph->name, config.triplet)
.value_or_exit(VCPKG_LINE_INFO);
auto& fs = paths.get_filesystem();
const Triplet& triplet = config.triplet;
const PackageSpec spec =
PackageSpec::from_name_and_triplet(config.scf.core_paragraph->name, triplet).value_or_exit(VCPKG_LINE_INFO);
std::vector<FeatureSpec> required_fspecs = compute_required_feature_specs(config, status_db);
// Find all features that aren't installed. This destroys required_fspecs.
Util::unstable_keep_if(required_fspecs,
[&](FeatureSpec const& fspec) { return !status_db.is_installed(fspec); });
if (!required_fspecs.empty())
{
std::vector<FeatureSpec> missing_specs;
for (auto&& dep : filter_dependencies(config.scf.core_paragraph->depends, triplet))
{
auto dep_specs = FeatureSpec::from_strings_and_triplet({dep}, triplet);
for (auto&& feature : dep_specs)
{
if (!status_db.is_installed(feature))
{
missing_specs.push_back(std::move(feature));
}
}
}
// Fail the build if any dependencies were missing
if (!missing_specs.empty())
{
return {BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES, std::move(missing_specs)};
}
return {BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES, std::move(required_fspecs)};
}
const fs::path& cmake_exe_path = paths.get_cmake_exe();
const fs::path& git_exe_path = paths.get_git_exe();
const fs::path ports_cmake_script_path = paths.ports_cmake;
const auto pre_build_info = PreBuildInfo::from_triplet_file(paths, triplet);
std::string features;
std::string features = Strings::join(";", config.feature_list);
std::string all_features;
if (GlobalState::feature_packages)
for (auto& feature : config.scf.feature_paragraphs)
{
for (auto&& feature : config.feature_list)
{
features.append(feature + ";");
}
if (!features.empty())
{
features.pop_back();
}
for (auto& feature : config.scf.feature_paragraphs)
{
all_features.append(feature->name + ";");
}
all_features.append(feature->name + ";");
}
const Toolset& toolset = paths.get_toolset(pre_build_info);
@ -351,7 +389,7 @@ namespace vcpkg::Build
}
}
const BuildInfo build_info = read_build_info(paths.get_filesystem(), paths.build_info_file_path(spec));
const BuildInfo build_info = read_build_info(fs, paths.build_info_file_path(spec));
const size_t error_count = PostBuildLint::perform_all_checks(spec, paths, pre_build_info, build_info);
auto bcf = create_binary_control_file(*config.scf.core_paragraph, triplet, build_info);
@ -360,16 +398,13 @@ namespace vcpkg::Build
{
return BuildResult::POST_BUILD_CHECKS_FAILED;
}
if (GlobalState::feature_packages)
for (auto&& feature : config.feature_list)
{
for (auto&& feature : config.feature_list)
for (auto&& f_pgh : config.scf.feature_paragraphs)
{
for (auto&& f_pgh : config.scf.feature_paragraphs)
{
if (f_pgh->name == feature)
bcf->features.push_back(
create_binary_feature_control_file(*config.scf.core_paragraph, *f_pgh, triplet));
}
if (f_pgh->name == feature)
bcf->features.push_back(
create_binary_feature_control_file(*config.scf.core_paragraph, *f_pgh, triplet));
}
}

View File

@ -7,7 +7,7 @@
namespace vcpkg::Commands::Hash
{
static void do_file_hash(fs::path const& cmake_exe_path, fs::path const& path, std::string const& hash_type)
std::string get_file_hash(fs::path const& cmake_exe_path, fs::path const& path, std::string const& hash_type)
{
const std::string cmd_line = Strings::format(
R"("%s" -E %ssum %s)", cmake_exe_path.u8string(), Strings::ascii_to_lowercase(hash_type), path.u8string());
@ -27,7 +27,7 @@ namespace vcpkg::Commands::Hash
auto hash = output.substr(0, start);
Util::erase_remove_if(hash, isspace);
System::println(hash);
return hash;
}
const CommandStructure COMMAND_STRUCTURE = {
@ -45,11 +45,13 @@ namespace vcpkg::Commands::Hash
if (args.command_arguments.size() == 1)
{
do_file_hash(paths.get_cmake_exe(), args.command_arguments[0], "SHA512");
auto hash = get_file_hash(paths.get_cmake_exe(), args.command_arguments[0], "SHA512");
System::println(hash);
}
if (args.command_arguments.size() == 2)
{
do_file_hash(paths.get_cmake_exe(), args.command_arguments[0], args.command_arguments[1]);
auto hash = get_file_hash(paths.get_cmake_exe(), args.command_arguments[0], args.command_arguments[1]);
System::println(hash);
}
Checks::exit_success(VCPKG_LINE_INFO);

View File

@ -30,8 +30,8 @@ namespace vcpkg::Dependencies
Optional<const SourceControlFile*> source_control_file;
PackageSpec spec;
std::unordered_map<std::string, FeatureNodeEdges> edges;
std::unordered_set<std::string> to_install_features;
std::unordered_set<std::string> original_features;
std::set<std::string> to_install_features;
std::set<std::string> original_features;
bool will_remove = false;
bool transient_uninstalled = true;
RequestType request_type = RequestType::AUTO_SELECTED;
@ -143,7 +143,7 @@ namespace vcpkg::Dependencies
InstallPlanAction::InstallPlanAction(const PackageSpec& spec,
const SourceControlFile& scf,
const std::unordered_set<std::string>& features,
const std::set<std::string>& features,
const RequestType& request_type)
: spec(spec)
, source_control_file(scf)
@ -155,7 +155,7 @@ namespace vcpkg::Dependencies
InstallPlanAction::InstallPlanAction(const PackageSpec& spec,
InstalledPackageView&& ipv,
const std::unordered_set<std::string>& features,
const std::set<std::string>& features,
const RequestType& request_type)
: spec(spec)
, installed_package(std::move(ipv))

View File

@ -54,6 +54,11 @@ namespace vcpkg
const Triplet& triplet,
const std::string& feature)
{
if (feature == "core")
{
// The core feature maps to .feature == ""
return find(name, triplet, "");
}
return std::find_if(begin(), end(), [&](const std::unique_ptr<StatusParagraph>& pgh) {
const PackageSpec& spec = pgh->package.spec;
return spec.name() == name && spec.triplet() == triplet && pgh->package.feature == feature;
@ -64,6 +69,11 @@ namespace vcpkg
const Triplet& triplet,
const std::string& feature) const
{
if (feature == "core")
{
// The core feature maps to .feature == ""
return find(name, triplet, "");
}
return std::find_if(begin(), end(), [&](const std::unique_ptr<StatusParagraph>& pgh) {
const PackageSpec& spec = pgh->package.spec;
return spec.name() == name && spec.triplet() == triplet && pgh->package.feature == feature;