1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
|
#include "pch.h"
#include "vcpkg_Dependencies.h"
#include "vcpkg_Graphs.h"
#include "VcpkgPaths.h"
#include "PackageSpec.h"
#include "StatusParagraphs.h"
#include "vcpkg_Files.h"
#include "Paragraphs.h"
namespace vcpkg::Dependencies
{
std::string to_output_string(RequestType request_type, const CStringView s)
{
switch (request_type)
{
case RequestType::AUTO_SELECTED:
return Strings::format(" * %s", s);
case RequestType::USER_REQUESTED:
return Strings::format(" %s", s);
default:
Checks::unreachable(VCPKG_LINE_INFO);
}
}
InstallPlanAction::InstallPlanAction() : plan_type(InstallPlanType::UNKNOWN), request_type(RequestType::UNKNOWN), binary_pgh(nullopt), source_pgh(nullopt) { }
InstallPlanAction::InstallPlanAction(const InstallPlanType& plan_type, const RequestType& request_type, Optional<BinaryParagraph> binary_pgh, Optional<SourceParagraph> source_pgh)
: plan_type(std::move(plan_type)), request_type(request_type), binary_pgh(std::move(binary_pgh)), source_pgh(std::move(source_pgh)) { }
bool PackageSpecWithInstallPlan::compare_by_name(const PackageSpecWithInstallPlan* left, const PackageSpecWithInstallPlan* right)
{
return left->spec.name() < right->spec.name();
}
PackageSpecWithInstallPlan::PackageSpecWithInstallPlan(const PackageSpec& spec, InstallPlanAction&& plan) : spec(spec), plan(std::move(plan)) { }
RemovePlanAction::RemovePlanAction() : plan_type(RemovePlanType::UNKNOWN), request_type(RequestType::UNKNOWN) { }
RemovePlanAction::RemovePlanAction(const RemovePlanType& plan_type, const Dependencies::RequestType& request_type) : plan_type(plan_type), request_type(request_type) { }
bool PackageSpecWithRemovePlan::compare_by_name(const PackageSpecWithRemovePlan* left, const PackageSpecWithRemovePlan* right)
{
return left->spec.name() < right->spec.name();
}
PackageSpecWithRemovePlan::PackageSpecWithRemovePlan(const PackageSpec& spec, RemovePlanAction&& plan)
: spec(spec), plan(std::move(plan)) { }
std::vector<PackageSpecWithInstallPlan> create_install_plan(const VcpkgPaths& paths, const std::vector<PackageSpec>& specs, const StatusParagraphs& status_db)
{
std::unordered_set<PackageSpec> specs_as_set(specs.cbegin(), specs.cend());
std::unordered_map<PackageSpec, InstallPlanAction> was_examined; // Examine = we have checked its immediate (non-recursive) dependencies
Graphs::Graph<PackageSpec> graph;
graph.add_vertices(specs);
std::vector<PackageSpec> examine_stack(specs);
while (!examine_stack.empty())
{
const PackageSpec spec = examine_stack.back();
examine_stack.pop_back();
if (was_examined.find(spec) != was_examined.end())
{
continue;
}
auto process_dependencies = [&](const std::vector<std::string>& dependencies_as_string)
{
for (const std::string& dep_as_string : dependencies_as_string)
{
const PackageSpec current_dep = PackageSpec::from_name_and_triplet(dep_as_string, spec.target_triplet()).value_or_exit(VCPKG_LINE_INFO);
graph.add_edge(spec, current_dep);
if (was_examined.find(current_dep) == was_examined.end())
{
examine_stack.push_back(std::move(current_dep));
}
}
};
const RequestType request_type = specs_as_set.find(spec) != specs_as_set.end() ? RequestType::USER_REQUESTED : RequestType::AUTO_SELECTED;
auto it = status_db.find(spec);
if (it != status_db.end() && (*it)->want == Want::INSTALL)
{
was_examined.emplace(spec, InstallPlanAction{ InstallPlanType::ALREADY_INSTALLED, request_type, nullopt, nullopt });
continue;
}
Expected<BinaryParagraph> maybe_bpgh = Paragraphs::try_load_cached_package(paths, spec);
if (BinaryParagraph* bpgh = maybe_bpgh.get())
{
process_dependencies(bpgh->depends);
was_examined.emplace(spec, InstallPlanAction{ InstallPlanType::INSTALL, request_type, std::move(*bpgh), nullopt });
continue;
}
Expected<SourceParagraph> maybe_spgh = Paragraphs::try_load_port(paths.port_dir(spec));
if (auto spgh = maybe_spgh.get())
{
process_dependencies(filter_dependencies(spgh->depends, spec.target_triplet()));
was_examined.emplace(spec, InstallPlanAction{ InstallPlanType::BUILD_AND_INSTALL, request_type, nullopt, std::move(*spgh) });
}
else
{
Checks::exit_with_message(VCPKG_LINE_INFO, "Cannot find package %s", spec.name());
}
}
std::vector<PackageSpecWithInstallPlan> ret;
const std::vector<PackageSpec> pkgs = graph.find_topological_sort();
for (const PackageSpec& pkg : pkgs)
{
ret.push_back(PackageSpecWithInstallPlan(pkg, std::move(was_examined[pkg])));
}
return ret;
}
std::vector<PackageSpecWithRemovePlan> create_remove_plan(const std::vector<PackageSpec>& specs, const StatusParagraphs& status_db)
{
std::unordered_set<PackageSpec> specs_as_set(specs.cbegin(), specs.cend());
std::unordered_map<PackageSpec, RemovePlanAction> was_examined; // Examine = we have checked its immediate (non-recursive) dependencies
Graphs::Graph<PackageSpec> graph;
graph.add_vertices(specs);
std::vector<PackageSpec> examine_stack(specs);
while (!examine_stack.empty())
{
const PackageSpec spec = examine_stack.back();
examine_stack.pop_back();
if (was_examined.find(spec) != was_examined.end())
{
continue;
}
const StatusParagraphs::const_iterator it = status_db.find(spec);
if (it == status_db.end() || (*it)->state == InstallState::NOT_INSTALLED)
{
was_examined.emplace(spec, RemovePlanAction(RemovePlanType::NOT_INSTALLED, RequestType::USER_REQUESTED));
continue;
}
for (const std::unique_ptr<StatusParagraph>& an_installed_package : status_db)
{
if (an_installed_package->want != Want::INSTALL)
continue;
if (an_installed_package->package.spec.target_triplet() != spec.target_triplet())
continue;
const std::vector<std::string>& deps = an_installed_package->package.depends;
if (std::find(deps.begin(), deps.end(), spec.name()) == deps.end())
{
continue;
}
graph.add_edge(spec, an_installed_package.get()->package.spec);
examine_stack.push_back(an_installed_package.get()->package.spec);
}
const RequestType request_type = specs_as_set.find(spec) != specs_as_set.end() ? RequestType::USER_REQUESTED : RequestType::AUTO_SELECTED;
was_examined.emplace(spec, RemovePlanAction(RemovePlanType::REMOVE, request_type));
}
std::vector<PackageSpecWithRemovePlan> ret;
const std::vector<PackageSpec> pkgs = graph.find_topological_sort();
for (const PackageSpec& pkg : pkgs)
{
ret.push_back(PackageSpecWithRemovePlan(pkg, std::move(was_examined[pkg])));
}
return ret;
}
}
|