mirror of
https://github.com/microsoft/vcpkg.git
synced 2025-06-07 03:12:48 +08:00
[vcpkg-ci] Do not rebuild libraries that were previously successful or failed
This commit is contained in:
parent
39c63d2276
commit
eab1d5c531
21
toolsrc/include/vcpkg/base/cache.h
Normal file
21
toolsrc/include/vcpkg/base/cache.h
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace vcpkg
|
||||
{
|
||||
template<class Key, class Value>
|
||||
struct Cache
|
||||
{
|
||||
template<class F>
|
||||
Value const& get_lazy(const Key& k, const F& f) const
|
||||
{
|
||||
auto it = m_cache.find(k);
|
||||
if (it != m_cache.end()) return it->second;
|
||||
return m_cache.emplace(k, f()).first->second;
|
||||
}
|
||||
|
||||
private:
|
||||
mutable std::map<Key, Value> m_cache;
|
||||
};
|
||||
}
|
@ -24,10 +24,10 @@ namespace vcpkg::Util
|
||||
|
||||
namespace Sets
|
||||
{
|
||||
template<class Container>
|
||||
bool contains(const Container& container, const ElementT<Container>& item)
|
||||
template<class Container, class Key>
|
||||
bool contains(const Container& container, const Key& item)
|
||||
{
|
||||
return container.find(item) != container.cend();
|
||||
return container.find(item) != container.end();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -204,4 +204,21 @@ namespace vcpkg::Build
|
||||
};
|
||||
|
||||
BuildInfo read_build_info(const Files::Filesystem& fs, const fs::path& filepath);
|
||||
|
||||
struct AbiEntry
|
||||
{
|
||||
std::string key;
|
||||
std::string value;
|
||||
};
|
||||
|
||||
struct AbiTagAndFile
|
||||
{
|
||||
std::string tag;
|
||||
fs::path tag_file;
|
||||
};
|
||||
|
||||
Optional<AbiTagAndFile> compute_abi_tag(const VcpkgPaths& paths,
|
||||
const BuildPackageConfig& config,
|
||||
const PreBuildInfo& pre_build_info,
|
||||
Span<const AbiEntry> dependency_abis);
|
||||
}
|
||||
|
@ -7,6 +7,8 @@
|
||||
#include <vcpkg/vcpkgpaths.h>
|
||||
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace vcpkg::Commands
|
||||
{
|
||||
@ -23,7 +25,17 @@ namespace vcpkg::Commands
|
||||
|
||||
namespace CI
|
||||
{
|
||||
struct UnknownCIPortsResults
|
||||
{
|
||||
std::vector<PackageSpec> unknown;
|
||||
std::map<PackageSpec, Build::BuildResult> known;
|
||||
};
|
||||
|
||||
extern const CommandStructure COMMAND_STRUCTURE;
|
||||
UnknownCIPortsResults find_unknown_ports_for_ci(const VcpkgPaths& paths,
|
||||
const std::set<std::string>& exclusions,
|
||||
const Dependencies::PortFileProvider& provider,
|
||||
const std::vector<FeatureSpec>& fspecs);
|
||||
void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const Triplet& default_triplet);
|
||||
}
|
||||
|
||||
|
@ -45,7 +45,8 @@ namespace vcpkg::Dependencies
|
||||
InstallPlanAction(const PackageSpec& spec,
|
||||
const SourceControlFile& scf,
|
||||
const std::set<std::string>& features,
|
||||
const RequestType& request_type);
|
||||
const RequestType& request_type,
|
||||
std::vector<PackageSpec>&& dependencies);
|
||||
|
||||
std::string displayname() const;
|
||||
|
||||
@ -58,6 +59,8 @@ namespace vcpkg::Dependencies
|
||||
RequestType request_type;
|
||||
Build::BuildPackageOptions build_options;
|
||||
std::set<std::string> feature_list;
|
||||
|
||||
std::vector<PackageSpec> computed_dependencies;
|
||||
};
|
||||
|
||||
enum class RemovePlanType
|
||||
|
@ -37,6 +37,7 @@ namespace vcpkg::Install
|
||||
std::string total_elapsed_time;
|
||||
|
||||
void print() const;
|
||||
static std::string xunit_result(const PackageSpec& spec, Chrono::ElapsedTime time, Build::BuildResult code);
|
||||
std::string xunit_results() const;
|
||||
};
|
||||
|
||||
|
@ -63,6 +63,8 @@ namespace vcpkg
|
||||
|
||||
std::unique_ptr<SourceParagraph> core_paragraph;
|
||||
std::vector<std::unique_ptr<FeatureParagraph>> feature_paragraphs;
|
||||
|
||||
Optional<const FeatureParagraph&> find_feature(const std::string& featurename) const;
|
||||
};
|
||||
|
||||
void print_error_message(Span<const std::unique_ptr<Parse::ParseControlErrorInfo>> error_info_list);
|
||||
|
@ -593,6 +593,87 @@ namespace UnitTest1
|
||||
features_check(&install_plan[0], "a", {"core"}, Triplet::X64_WINDOWS);
|
||||
}
|
||||
|
||||
TEST_METHOD(install_plan_action_dependencies)
|
||||
{
|
||||
std::vector<std::unique_ptr<StatusParagraph>> status_paragraphs;
|
||||
|
||||
// Add a port "a" which depends on the core of "b", which was already
|
||||
// installed explicitly
|
||||
PackageSpecMap spec_map(Triplet::X64_WINDOWS);
|
||||
auto spec_c = spec_map.emplace("c");
|
||||
auto spec_b = spec_map.emplace("b", "c");
|
||||
spec_map.emplace("a", "b");
|
||||
|
||||
// Install "a" (without explicit feature specification)
|
||||
auto install_specs = FullPackageSpec::from_string("a", Triplet::X64_WINDOWS);
|
||||
auto install_plan = Dependencies::create_feature_install_plan(
|
||||
spec_map.map,
|
||||
FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}),
|
||||
StatusParagraphs(std::move(status_paragraphs)));
|
||||
|
||||
Assert::IsTrue(install_plan.size() == 3);
|
||||
features_check(&install_plan[0], "c", {"core"}, Triplet::X64_WINDOWS);
|
||||
|
||||
features_check(&install_plan[1], "b", {"core"}, Triplet::X64_WINDOWS);
|
||||
Assert::IsTrue(install_plan[1].install_action.get()->computed_dependencies ==
|
||||
std::vector<PackageSpec>{spec_c});
|
||||
|
||||
features_check(&install_plan[2], "a", {"core"}, Triplet::X64_WINDOWS);
|
||||
Assert::IsTrue(install_plan[2].install_action.get()->computed_dependencies ==
|
||||
std::vector<PackageSpec>{spec_b});
|
||||
}
|
||||
|
||||
TEST_METHOD(install_plan_action_dependencies_2)
|
||||
{
|
||||
std::vector<std::unique_ptr<StatusParagraph>> status_paragraphs;
|
||||
|
||||
// Add a port "a" which depends on the core of "b", which was already
|
||||
// installed explicitly
|
||||
PackageSpecMap spec_map(Triplet::X64_WINDOWS);
|
||||
auto spec_c = spec_map.emplace("c");
|
||||
auto spec_b = spec_map.emplace("b", "c");
|
||||
spec_map.emplace("a", "c, b");
|
||||
|
||||
// Install "a" (without explicit feature specification)
|
||||
auto install_specs = FullPackageSpec::from_string("a", Triplet::X64_WINDOWS);
|
||||
auto install_plan = Dependencies::create_feature_install_plan(
|
||||
spec_map.map,
|
||||
FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}),
|
||||
StatusParagraphs(std::move(status_paragraphs)));
|
||||
|
||||
Assert::IsTrue(install_plan.size() == 3);
|
||||
features_check(&install_plan[0], "c", {"core"}, Triplet::X64_WINDOWS);
|
||||
|
||||
features_check(&install_plan[1], "b", {"core"}, Triplet::X64_WINDOWS);
|
||||
Assert::IsTrue(install_plan[1].install_action.get()->computed_dependencies ==
|
||||
std::vector<PackageSpec>{spec_c});
|
||||
|
||||
features_check(&install_plan[2], "a", {"core"}, Triplet::X64_WINDOWS);
|
||||
Assert::IsTrue(install_plan[2].install_action.get()->computed_dependencies ==
|
||||
std::vector<PackageSpec>{spec_b, spec_c});
|
||||
}
|
||||
|
||||
TEST_METHOD(install_plan_action_dependencies_3)
|
||||
{
|
||||
std::vector<std::unique_ptr<StatusParagraph>> status_paragraphs;
|
||||
|
||||
// Add a port "a" which depends on the core of "b", which was already
|
||||
// installed explicitly
|
||||
PackageSpecMap spec_map(Triplet::X64_WINDOWS);
|
||||
spec_map.emplace("a", "", {{"0", ""}, {"1", "a[0]"}}, {"1"});
|
||||
|
||||
// Install "a" (without explicit feature specification)
|
||||
auto install_specs = FullPackageSpec::from_string("a", Triplet::X64_WINDOWS);
|
||||
auto install_plan = Dependencies::create_feature_install_plan(
|
||||
spec_map.map,
|
||||
FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}),
|
||||
StatusParagraphs(std::move(status_paragraphs)));
|
||||
|
||||
Assert::IsTrue(install_plan.size() == 1);
|
||||
features_check(&install_plan[0], "a", {"1", "0", "core"}, Triplet::X64_WINDOWS);
|
||||
Assert::IsTrue(install_plan[0].install_action.get()->computed_dependencies == std::vector<PackageSpec>{});
|
||||
}
|
||||
|
||||
TEST_METHOD(upgrade_with_default_features_1)
|
||||
{
|
||||
std::vector<std::unique_ptr<StatusParagraph>> pghs;
|
||||
@ -619,7 +700,6 @@ namespace UnitTest1
|
||||
Assert::IsTrue(plan[0].remove_action.has_value());
|
||||
|
||||
Assert::AreEqual("a", plan[1].spec().name().c_str());
|
||||
Assert::IsTrue(plan[1].install_action.has_value());
|
||||
features_check(&plan[1], "a", {"core", "0"}, Triplet::X86_WINDOWS);
|
||||
}
|
||||
|
||||
@ -651,11 +731,9 @@ namespace UnitTest1
|
||||
Assert::IsTrue(plan[0].remove_action.has_value());
|
||||
|
||||
Assert::AreEqual("b", plan[1].spec().name().c_str());
|
||||
Assert::IsTrue(plan[1].install_action.has_value());
|
||||
features_check(&plan[1], "b", {"b0", "core"}, Triplet::X64_WINDOWS);
|
||||
|
||||
Assert::AreEqual("a", plan[2].spec().name().c_str());
|
||||
Assert::IsTrue(plan[2].install_action.has_value());
|
||||
features_check(&plan[2], "a", {"core"}, Triplet::X64_WINDOWS);
|
||||
}
|
||||
|
||||
|
@ -314,6 +314,8 @@ namespace vcpkg::System
|
||||
// Flush stdout before launching external process
|
||||
fflush(stdout);
|
||||
|
||||
auto timer = Chrono::ElapsedTimer::create_started();
|
||||
|
||||
#if defined(_WIN32)
|
||||
const auto actual_cmd_line = Strings::format(R"###("%s 2>&1")###", cmd_line);
|
||||
|
||||
@ -335,8 +337,10 @@ namespace vcpkg::System
|
||||
}
|
||||
|
||||
const auto ec = _pclose(pipe);
|
||||
Debug::println("_pclose() returned %d", ec);
|
||||
remove_byte_order_marks(&output);
|
||||
|
||||
Debug::println("_pclose() returned %d after %8d us", ec, (int)timer.microseconds());
|
||||
|
||||
return {ec, Strings::to_utf8(output)};
|
||||
#else
|
||||
const auto actual_cmd_line = Strings::format(R"###(%s 2>&1)###", cmd_line);
|
||||
@ -359,7 +363,9 @@ namespace vcpkg::System
|
||||
}
|
||||
|
||||
const auto ec = pclose(pipe);
|
||||
Debug::println("pclose() returned %d", ec);
|
||||
|
||||
Debug::println("_pclose() returned %d after %8d us", ec, (int)timer.microseconds());
|
||||
|
||||
return {ec, output};
|
||||
#endif
|
||||
}
|
||||
|
@ -273,12 +273,10 @@ namespace vcpkg::Build
|
||||
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());
|
||||
auto maybe_feature = config.scf.find_feature(feature);
|
||||
Checks::check_exit(VCPKG_LINE_INFO, maybe_feature.has_value());
|
||||
|
||||
return filter_dependencies(it->get()->depends, triplet);
|
||||
return filter_dependencies(maybe_feature.get()->depends, triplet);
|
||||
});
|
||||
|
||||
auto dep_fspecs = FeatureSpec::from_strings_and_triplet(dep_strings, triplet);
|
||||
@ -423,22 +421,10 @@ namespace vcpkg::Build
|
||||
return result;
|
||||
}
|
||||
|
||||
struct AbiEntry
|
||||
{
|
||||
std::string key;
|
||||
std::string value;
|
||||
};
|
||||
|
||||
struct AbiTagAndFile
|
||||
{
|
||||
std::string tag;
|
||||
fs::path tag_file;
|
||||
};
|
||||
|
||||
static Optional<AbiTagAndFile> compute_abi_tag(const VcpkgPaths& paths,
|
||||
const BuildPackageConfig& config,
|
||||
const PreBuildInfo& pre_build_info,
|
||||
Span<const AbiEntry> dependency_abis)
|
||||
Optional<AbiTagAndFile> compute_abi_tag(const VcpkgPaths& paths,
|
||||
const BuildPackageConfig& config,
|
||||
const PreBuildInfo& pre_build_info,
|
||||
Span<const AbiEntry> dependency_abis)
|
||||
{
|
||||
if (!GlobalState::g_binary_caching) return nullopt;
|
||||
|
||||
@ -584,17 +570,17 @@ namespace vcpkg::Build
|
||||
|
||||
const auto pre_build_info = PreBuildInfo::from_triplet_file(paths, triplet);
|
||||
|
||||
auto abi_tag_and_file = compute_abi_tag(paths, config, pre_build_info, dependency_abis);
|
||||
auto maybe_abi_tag_and_file = compute_abi_tag(paths, config, pre_build_info, dependency_abis);
|
||||
|
||||
std::unique_ptr<BinaryControlFile> bcf;
|
||||
|
||||
auto maybe_abi_tag_and_file = abi_tag_and_file.get();
|
||||
auto abi_tag_and_file = maybe_abi_tag_and_file.get();
|
||||
|
||||
if (GlobalState::g_binary_caching && maybe_abi_tag_and_file)
|
||||
if (GlobalState::g_binary_caching && abi_tag_and_file)
|
||||
{
|
||||
auto archives_root_dir = paths.root / "archives";
|
||||
auto archive_name = maybe_abi_tag_and_file->tag + ".zip";
|
||||
auto archive_subpath = fs::u8path(maybe_abi_tag_and_file->tag.substr(0, 2)) / archive_name;
|
||||
auto archive_name = abi_tag_and_file->tag + ".zip";
|
||||
auto archive_subpath = fs::u8path(abi_tag_and_file->tag.substr(0, 2)) / archive_name;
|
||||
auto archive_path = archives_root_dir / archive_subpath;
|
||||
auto archive_tombstone_path = archives_root_dir / "fail" / archive_subpath;
|
||||
|
||||
@ -617,12 +603,12 @@ namespace vcpkg::Build
|
||||
System::println("Could not locate cached archive: %s", archive_path.u8string());
|
||||
|
||||
ExtendedBuildResult result = do_build_package_and_clean_buildtrees(
|
||||
paths, pre_build_info, spec, abi_tag_and_file.value_or(AbiTagAndFile{}).tag, config, status_db);
|
||||
paths, pre_build_info, spec, maybe_abi_tag_and_file.value_or(AbiTagAndFile{}).tag, config, status_db);
|
||||
|
||||
std::error_code ec;
|
||||
fs.create_directories(paths.package_dir(spec) / "share" / spec.name(), ec);
|
||||
auto abi_file_in_package = paths.package_dir(spec) / "share" / spec.name() / "vcpkg_abi_info.txt";
|
||||
fs.copy_file(maybe_abi_tag_and_file->tag_file, abi_file_in_package, fs::stdfs::copy_options::none, ec);
|
||||
fs.copy_file(abi_tag_and_file->tag_file, abi_file_in_package, fs::stdfs::copy_options::none, ec);
|
||||
Checks::check_exit(VCPKG_LINE_INFO, !ec, "Could not copy into file: %s", abi_file_in_package.u8string());
|
||||
|
||||
if (result.code == BuildResult::SUCCEEDED)
|
||||
@ -648,7 +634,7 @@ namespace vcpkg::Build
|
||||
else
|
||||
{
|
||||
return do_build_package_and_clean_buildtrees(
|
||||
paths, pre_build_info, spec, abi_tag_and_file.value_or(AbiTagAndFile{}).tag, config, status_db);
|
||||
paths, pre_build_info, spec, maybe_abi_tag_and_file.value_or(AbiTagAndFile{}).tag, config, status_db);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "pch.h"
|
||||
|
||||
#include <vcpkg/base/cache.h>
|
||||
#include <vcpkg/base/files.h>
|
||||
#include <vcpkg/base/stringliteral.h>
|
||||
#include <vcpkg/base/system.h>
|
||||
@ -7,6 +8,7 @@
|
||||
#include <vcpkg/build.h>
|
||||
#include <vcpkg/commands.h>
|
||||
#include <vcpkg/dependencies.h>
|
||||
#include <vcpkg/globalstate.h>
|
||||
#include <vcpkg/help.h>
|
||||
#include <vcpkg/input.h>
|
||||
#include <vcpkg/install.h>
|
||||
@ -44,8 +46,120 @@ namespace vcpkg::Commands::CI
|
||||
nullptr,
|
||||
};
|
||||
|
||||
UnknownCIPortsResults find_unknown_ports_for_ci(const VcpkgPaths& paths,
|
||||
const std::set<std::string>& exclusions,
|
||||
const Dependencies::PortFileProvider& provider,
|
||||
const std::vector<FeatureSpec>& fspecs)
|
||||
{
|
||||
UnknownCIPortsResults ret;
|
||||
|
||||
auto& fs = paths.get_filesystem();
|
||||
|
||||
std::map<PackageSpec, std::string> abi_tag_map;
|
||||
std::set<PackageSpec> will_fail;
|
||||
|
||||
const Build::BuildPackageOptions install_plan_options = {Build::UseHeadVersion::NO,
|
||||
Build::AllowDownloads::YES,
|
||||
Build::CleanBuildtrees::YES,
|
||||
Build::CleanPackages::YES};
|
||||
|
||||
vcpkg::Cache<Triplet, Build::PreBuildInfo> pre_build_info_cache;
|
||||
|
||||
auto action_plan = Dependencies::create_feature_install_plan(provider, fspecs, StatusParagraphs{});
|
||||
|
||||
for (auto&& action : action_plan)
|
||||
{
|
||||
if (auto p = action.install_action.get())
|
||||
{
|
||||
// determine abi tag
|
||||
std::string abi;
|
||||
if (auto scf = p->source_control_file.get())
|
||||
{
|
||||
auto triplet = p->spec.triplet();
|
||||
|
||||
const Build::BuildPackageConfig build_config{p->source_control_file.value_or_exit(VCPKG_LINE_INFO),
|
||||
triplet,
|
||||
paths.port_dir(p->spec),
|
||||
install_plan_options,
|
||||
p->feature_list};
|
||||
|
||||
auto dependency_abis =
|
||||
Util::fmap(p->computed_dependencies, [&](const PackageSpec& spec) -> Build::AbiEntry {
|
||||
auto it = abi_tag_map.find(spec);
|
||||
|
||||
if (it == abi_tag_map.end())
|
||||
return {spec.name(), ""};
|
||||
else
|
||||
return {spec.name(), it->second};
|
||||
});
|
||||
const auto& pre_build_info = pre_build_info_cache.get_lazy(
|
||||
triplet, [&]() { return Build::PreBuildInfo::from_triplet_file(paths, triplet); });
|
||||
|
||||
auto maybe_tag_and_file =
|
||||
Build::compute_abi_tag(paths, build_config, pre_build_info, dependency_abis);
|
||||
if (auto tag_and_file = maybe_tag_and_file.get())
|
||||
{
|
||||
abi = tag_and_file->tag;
|
||||
abi_tag_map.emplace(p->spec, abi);
|
||||
}
|
||||
}
|
||||
else if (auto ipv = p->installed_package.get())
|
||||
{
|
||||
abi = ipv->core->package.abi;
|
||||
if (!abi.empty()) abi_tag_map.emplace(p->spec, abi);
|
||||
}
|
||||
|
||||
std::string state;
|
||||
|
||||
auto archives_root_dir = paths.root / "archives";
|
||||
auto archive_name = abi + ".zip";
|
||||
auto archive_subpath = fs::u8path(abi.substr(0, 2)) / archive_name;
|
||||
auto archive_path = archives_root_dir / archive_subpath;
|
||||
auto archive_tombstone_path = archives_root_dir / "fail" / archive_subpath;
|
||||
|
||||
bool b_will_build = false;
|
||||
|
||||
if (Util::Sets::contains(exclusions, p->spec.name()))
|
||||
{
|
||||
ret.known.emplace(p->spec, BuildResult::EXCLUDED);
|
||||
will_fail.emplace(p->spec);
|
||||
}
|
||||
else if (std::any_of(p->computed_dependencies.begin(),
|
||||
p->computed_dependencies.end(),
|
||||
[&](const PackageSpec& spec) { return Util::Sets::contains(will_fail, spec); }))
|
||||
{
|
||||
ret.known.emplace(p->spec, BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES);
|
||||
will_fail.emplace(p->spec);
|
||||
}
|
||||
else if (fs.exists(archive_path))
|
||||
{
|
||||
state += "pass";
|
||||
ret.known.emplace(p->spec, BuildResult::SUCCEEDED);
|
||||
}
|
||||
else if (fs.exists(archive_tombstone_path))
|
||||
{
|
||||
state += "fail";
|
||||
ret.known.emplace(p->spec, BuildResult::BUILD_FAILED);
|
||||
will_fail.emplace(p->spec);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret.unknown.push_back(p->spec);
|
||||
b_will_build = true;
|
||||
}
|
||||
|
||||
System::println("%40s: %1s %8s: %s", p->spec, (b_will_build ? "*" : " "), state, abi);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const Triplet& default_triplet)
|
||||
{
|
||||
Checks::check_exit(
|
||||
VCPKG_LINE_INFO, GlobalState::g_binary_caching, "The ci command requires binary caching to be enabled.");
|
||||
|
||||
const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE);
|
||||
|
||||
std::set<std::string> exclusions_set;
|
||||
@ -77,16 +191,21 @@ namespace vcpkg::Commands::CI
|
||||
Build::CleanBuildtrees::YES,
|
||||
Build::CleanPackages::YES};
|
||||
|
||||
std::vector<std::string> ports = Install::get_all_port_names(paths);
|
||||
std::vector<std::map<PackageSpec, BuildResult>> all_known_results;
|
||||
|
||||
std::vector<std::string> all_ports = Install::get_all_port_names(paths);
|
||||
std::vector<TripletAndSummary> results;
|
||||
for (const Triplet& triplet : triplets)
|
||||
{
|
||||
Input::check_triplet(triplet, paths);
|
||||
std::vector<PackageSpec> specs = PackageSpec::to_package_specs(ports, triplet);
|
||||
// Install the default features for every package
|
||||
const auto featurespecs = Util::fmap(specs, [](auto& spec) { return FeatureSpec(spec, ""); });
|
||||
|
||||
auto action_plan = Dependencies::create_feature_install_plan(paths_port_file, featurespecs, status_db);
|
||||
std::vector<PackageSpec> specs = PackageSpec::to_package_specs(all_ports, triplet);
|
||||
// Install the default features for every package
|
||||
auto all_fspecs = Util::fmap(specs, [](auto& spec) { return FeatureSpec(spec, ""); });
|
||||
auto split_specs = find_unknown_ports_for_ci(paths, exclusions_set, paths_port_file, all_fspecs);
|
||||
auto fspecs = Util::fmap(split_specs.unknown, [](auto& spec) { return FeatureSpec(spec, ""); });
|
||||
|
||||
auto action_plan = Dependencies::create_feature_install_plan(paths_port_file, fspecs, status_db);
|
||||
|
||||
for (auto&& action : action_plan)
|
||||
{
|
||||
@ -107,7 +226,10 @@ namespace vcpkg::Commands::CI
|
||||
else
|
||||
{
|
||||
auto summary = Install::perform(action_plan, Install::KeepGoing::YES, paths, status_db);
|
||||
for (auto&& result : summary.results)
|
||||
split_specs.known.erase(result.spec);
|
||||
results.push_back({triplet, std::move(summary)});
|
||||
all_known_results.emplace_back(std::move(split_specs.known));
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,6 +247,14 @@ namespace vcpkg::Commands::CI
|
||||
|
||||
for (auto&& result : results)
|
||||
xunit_doc += result.summary.xunit_results();
|
||||
for (auto&& known_result : all_known_results)
|
||||
{
|
||||
for (auto&& result : known_result)
|
||||
{
|
||||
xunit_doc +=
|
||||
Install::InstallSummary::xunit_result(result.first, Chrono::ElapsedTime{}, result.second);
|
||||
}
|
||||
}
|
||||
|
||||
xunit_doc += "</collection></assembly></assemblies>\n";
|
||||
paths.get_filesystem().write_contents(fs::u8path(it_xunit->second), xunit_doc);
|
||||
|
@ -144,12 +144,14 @@ namespace vcpkg::Dependencies
|
||||
InstallPlanAction::InstallPlanAction(const PackageSpec& spec,
|
||||
const SourceControlFile& scf,
|
||||
const std::set<std::string>& features,
|
||||
const RequestType& request_type)
|
||||
const RequestType& request_type,
|
||||
std::vector<PackageSpec>&& dependencies)
|
||||
: spec(spec)
|
||||
, source_control_file(scf)
|
||||
, plan_type(InstallPlanType::BUILD_AND_INSTALL)
|
||||
, request_type(request_type)
|
||||
, feature_list(features)
|
||||
, computed_dependencies(std::move(dependencies))
|
||||
{
|
||||
}
|
||||
|
||||
@ -162,6 +164,7 @@ namespace vcpkg::Dependencies
|
||||
, plan_type(InstallPlanType::ALREADY_INSTALLED)
|
||||
, request_type(request_type)
|
||||
, feature_list(features)
|
||||
, computed_dependencies(installed_package.get()->dependencies())
|
||||
{
|
||||
}
|
||||
|
||||
@ -683,11 +686,17 @@ namespace vcpkg::Dependencies
|
||||
// If it will be transiently uninstalled, we need to issue a full installation command
|
||||
auto pscf = p_cluster->source_control_file.value_or_exit(VCPKG_LINE_INFO);
|
||||
Checks::check_exit(VCPKG_LINE_INFO, pscf != nullptr);
|
||||
|
||||
auto dep_specs = Util::fmap(m_graph_plan->install_graph.adjacency_list(p_cluster),
|
||||
[](ClusterPtr const& p) { return p->spec; });
|
||||
Util::sort_unique_erase(dep_specs);
|
||||
|
||||
plan.emplace_back(InstallPlanAction{
|
||||
p_cluster->spec,
|
||||
*pscf,
|
||||
p_cluster->to_install_features,
|
||||
p_cluster->request_type,
|
||||
std::move(dep_specs),
|
||||
});
|
||||
}
|
||||
else
|
||||
|
@ -668,39 +668,42 @@ namespace vcpkg::Install
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string InstallSummary::xunit_result(const PackageSpec& spec, Chrono::ElapsedTime time, BuildResult code)
|
||||
{
|
||||
std::string inner_block;
|
||||
const char* result_string = "";
|
||||
switch (code)
|
||||
{
|
||||
case BuildResult::POST_BUILD_CHECKS_FAILED:
|
||||
case BuildResult::FILE_CONFLICTS:
|
||||
case BuildResult::BUILD_FAILED:
|
||||
result_string = "Fail";
|
||||
inner_block = Strings::format("<failure><message><![CDATA[%s]]></message></failure>", to_string(code));
|
||||
break;
|
||||
case BuildResult::EXCLUDED:
|
||||
case BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES:
|
||||
result_string = "Skip";
|
||||
inner_block = Strings::format("<reason><![CDATA[%s]]></reason>", to_string(code));
|
||||
break;
|
||||
case BuildResult::SUCCEEDED: result_string = "Pass"; break;
|
||||
default: Checks::exit_fail(VCPKG_LINE_INFO);
|
||||
}
|
||||
|
||||
return Strings::format(R"(<test name="%s" method="%s" time="%lld" result="%s">%s</test>)"
|
||||
"\n",
|
||||
spec,
|
||||
spec,
|
||||
time.as<std::chrono::seconds>().count(),
|
||||
result_string,
|
||||
inner_block);
|
||||
}
|
||||
|
||||
std::string InstallSummary::xunit_results() const
|
||||
{
|
||||
std::string xunit_doc;
|
||||
for (auto&& result : results)
|
||||
{
|
||||
std::string inner_block;
|
||||
const char* result_string = "";
|
||||
switch (result.build_result.code)
|
||||
{
|
||||
case BuildResult::POST_BUILD_CHECKS_FAILED:
|
||||
case BuildResult::FILE_CONFLICTS:
|
||||
case BuildResult::BUILD_FAILED:
|
||||
result_string = "Fail";
|
||||
inner_block = Strings::format("<failure><message><![CDATA[%s]]></message></failure>",
|
||||
to_string(result.build_result.code));
|
||||
break;
|
||||
case BuildResult::EXCLUDED:
|
||||
case BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES:
|
||||
result_string = "Skip";
|
||||
inner_block =
|
||||
Strings::format("<reason><![CDATA[%s]]></reason>", to_string(result.build_result.code));
|
||||
break;
|
||||
case BuildResult::SUCCEEDED: result_string = "Pass"; break;
|
||||
default: Checks::exit_fail(VCPKG_LINE_INFO);
|
||||
}
|
||||
|
||||
xunit_doc += Strings::format(R"(<test name="%s" method="%s" time="%lld" result="%s">%s</test>)"
|
||||
"\n",
|
||||
result.spec,
|
||||
result.spec,
|
||||
result.timing.as<std::chrono::seconds>().count(),
|
||||
result_string,
|
||||
inner_block);
|
||||
xunit_doc += xunit_result(result.spec, result.timing, result.build_result.code);
|
||||
}
|
||||
return xunit_doc;
|
||||
}
|
||||
|
@ -158,6 +158,16 @@ namespace vcpkg
|
||||
return std::move(control_file);
|
||||
}
|
||||
|
||||
Optional<const FeatureParagraph&> SourceControlFile::find_feature(const std::string& featurename) const
|
||||
{
|
||||
auto it = Util::find_if(feature_paragraphs,
|
||||
[&](const std::unique_ptr<FeatureParagraph>& p) { return p->name == featurename; });
|
||||
if (it != feature_paragraphs.end())
|
||||
return **it;
|
||||
else
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
Dependency Dependency::parse_dependency(std::string name, std::string qualifier)
|
||||
{
|
||||
Dependency dep;
|
||||
|
Loading…
Reference in New Issue
Block a user