mirror of
https://github.com/microsoft/vcpkg.git
synced 2025-06-07 19:42:46 +08:00
Merge pull request #3676 from martin-s/feature-graph
Dependency graph as new command
This commit is contained in:
commit
bf6708576c
@ -1,61 +1,166 @@
|
|||||||
#include "pch.h"
|
#include "pch.h"
|
||||||
|
|
||||||
#include <vcpkg/base/strings.h>
|
#include <vcpkg/base/strings.h>
|
||||||
#include <vcpkg/base/system.h>
|
#include <vcpkg/base/system.h>
|
||||||
#include <vcpkg/base/util.h>
|
#include <vcpkg/base/util.h>
|
||||||
#include <vcpkg/commands.h>
|
#include <vcpkg/commands.h>
|
||||||
#include <vcpkg/help.h>
|
#include <vcpkg/help.h>
|
||||||
#include <vcpkg/paragraphs.h>
|
#include <vcpkg/paragraphs.h>
|
||||||
|
|
||||||
namespace vcpkg::Commands::DependInfo
|
namespace vcpkg::Commands::DependInfo
|
||||||
{
|
{
|
||||||
const CommandStructure COMMAND_STRUCTURE = {
|
constexpr StringLiteral OPTION_DOT = "--dot";
|
||||||
Help::create_example_string(R"###(depend-info [pat])###"),
|
constexpr StringLiteral OPTION_DGML = "--dgml";
|
||||||
0,
|
|
||||||
1,
|
constexpr std::array<CommandSwitch, 2> DEPEND_SWITCHES = { {
|
||||||
{},
|
{ OPTION_DOT, "Creates graph on basis of dot" },
|
||||||
nullptr,
|
{ OPTION_DGML, "Creates graph on basis of dgml" },
|
||||||
};
|
} };
|
||||||
|
|
||||||
void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths)
|
const CommandStructure COMMAND_STRUCTURE = {
|
||||||
{
|
Help::create_example_string(R"###(depend-info [pat])###"),
|
||||||
Util::unused(args.parse_arguments(COMMAND_STRUCTURE));
|
0,
|
||||||
|
1,
|
||||||
std::vector<std::unique_ptr<SourceControlFile>> source_control_files =
|
{ DEPEND_SWITCHES,{} },
|
||||||
Paragraphs::load_all_ports(paths.get_filesystem(), paths.ports);
|
nullptr,
|
||||||
|
};
|
||||||
if (args.command_arguments.size() == 1)
|
|
||||||
{
|
std::string replace_dashes_with_underscore(const std::string& input)
|
||||||
const std::string filter = args.command_arguments.at(0);
|
{
|
||||||
|
std::string output = input;
|
||||||
Util::erase_remove_if(source_control_files,
|
std::replace(output.begin(), output.end(), '-', '_');
|
||||||
[&](const std::unique_ptr<SourceControlFile>& source_control_file) {
|
return output;
|
||||||
const SourceParagraph& source_paragraph = *source_control_file->core_paragraph;
|
}
|
||||||
|
|
||||||
if (Strings::case_insensitive_ascii_contains(source_paragraph.name, filter))
|
std::string create_dot_as_string(
|
||||||
{
|
const std::vector<std::unique_ptr<SourceControlFile>>& source_control_files)
|
||||||
return false;
|
{
|
||||||
}
|
int empty_node_count = 0;
|
||||||
|
|
||||||
for (const Dependency& dependency : source_paragraph.depends)
|
std::string s;
|
||||||
{
|
s.append("digraph G{ rankdir=LR; edge [minlen=3]; overlap=false;");
|
||||||
if (Strings::case_insensitive_ascii_contains(dependency.name(), filter))
|
|
||||||
{
|
for (const auto& source_control_file : source_control_files)
|
||||||
return false;
|
{
|
||||||
}
|
const SourceParagraph& source_paragraph = *source_control_file->core_paragraph;
|
||||||
}
|
if (source_paragraph.depends.empty())
|
||||||
|
{
|
||||||
return true;
|
empty_node_count++;
|
||||||
});
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto&& source_control_file : source_control_files)
|
const std::string name = replace_dashes_with_underscore(source_paragraph.name);
|
||||||
{
|
s.append(Strings::format("%s;", name));
|
||||||
const SourceParagraph& source_paragraph = *source_control_file->core_paragraph;
|
for (const Dependency& d : source_paragraph.depends)
|
||||||
const auto s = Strings::join(", ", source_paragraph.depends, [](const Dependency& d) { return d.name(); });
|
{
|
||||||
System::println("%s: %s", source_paragraph.name, s);
|
const std::string dependency_name = replace_dashes_with_underscore(d.name());
|
||||||
}
|
s.append(Strings::format("%s -> %s;", name, dependency_name));
|
||||||
|
}
|
||||||
Checks::exit_success(VCPKG_LINE_INFO);
|
}
|
||||||
}
|
|
||||||
}
|
s.append(Strings::format("empty [label=\"%d singletons...\"]; }", empty_node_count));
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string create_dgml_as_string(
|
||||||
|
const std::vector<std::unique_ptr<SourceControlFile>>& source_control_files)
|
||||||
|
{
|
||||||
|
std::string s;
|
||||||
|
s.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
|
||||||
|
s.append("<DirectedGraph xmlns=\"http://schemas.microsoft.com/vs/2009/dgml\">");
|
||||||
|
|
||||||
|
std::string nodes, links;
|
||||||
|
for (const auto& source_control_file : source_control_files)
|
||||||
|
{
|
||||||
|
const SourceParagraph& source_paragraph = *source_control_file->core_paragraph;
|
||||||
|
const std::string name = source_paragraph.name;
|
||||||
|
nodes.append(Strings::format("<Node Id=\"%s\" />", name));
|
||||||
|
|
||||||
|
// Iterate over dependencies.
|
||||||
|
for (const Dependency& d : source_paragraph.depends)
|
||||||
|
{
|
||||||
|
links.append(Strings::format("<Link Source=\"%s\" Target=\"%s\" />", name, d.name()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate over feature dependencies.
|
||||||
|
const std::vector<std::unique_ptr<FeatureParagraph>>& feature_paragraphs = source_control_file->feature_paragraphs;
|
||||||
|
for (const auto& feature_paragraph : feature_paragraphs)
|
||||||
|
{
|
||||||
|
for (const Dependency& d : feature_paragraph->depends)
|
||||||
|
{
|
||||||
|
links.append(Strings::format("<Link Source=\"%s\" Target=\"%s\" />", name, d.name()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s.append(Strings::format("<Nodes>%s</Nodes>", nodes));
|
||||||
|
|
||||||
|
s.append(Strings::format("<Links>%s</Links>", links));
|
||||||
|
|
||||||
|
s.append("</DirectedGraph>");
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string create_graph_as_string(
|
||||||
|
const std::unordered_set<std::string>& switches,
|
||||||
|
const std::vector<std::unique_ptr<SourceControlFile>>& source_control_files)
|
||||||
|
{
|
||||||
|
if (Util::Sets::contains(switches, OPTION_DOT))
|
||||||
|
{
|
||||||
|
return create_dot_as_string(source_control_files);
|
||||||
|
}
|
||||||
|
else if (Util::Sets::contains(switches, OPTION_DGML))
|
||||||
|
{
|
||||||
|
return create_dgml_as_string(source_control_files);
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths)
|
||||||
|
{
|
||||||
|
const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE);
|
||||||
|
|
||||||
|
auto source_control_files = Paragraphs::load_all_ports(paths.get_filesystem(), paths.ports);
|
||||||
|
|
||||||
|
if (args.command_arguments.size() == 1)
|
||||||
|
{
|
||||||
|
const std::string filter = args.command_arguments.at(0);
|
||||||
|
|
||||||
|
Util::erase_remove_if(source_control_files,
|
||||||
|
[&](const std::unique_ptr<SourceControlFile>& source_control_file) {
|
||||||
|
const SourceParagraph& source_paragraph = *source_control_file->core_paragraph;
|
||||||
|
|
||||||
|
if (Strings::case_insensitive_ascii_contains(source_paragraph.name, filter))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const Dependency& dependency : source_paragraph.depends)
|
||||||
|
{
|
||||||
|
if (Strings::case_insensitive_ascii_contains(dependency.name(), filter))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!options.switches.empty())
|
||||||
|
{
|
||||||
|
const std::string graph_as_string = create_graph_as_string(options.switches, source_control_files);
|
||||||
|
System::println(graph_as_string);
|
||||||
|
Checks::exit_success(VCPKG_LINE_INFO);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto&& source_control_file : source_control_files)
|
||||||
|
{
|
||||||
|
const SourceParagraph& source_paragraph = *source_control_file->core_paragraph;
|
||||||
|
const auto s = Strings::join(", ", source_paragraph.depends, [](const Dependency& d) { return d.name(); });
|
||||||
|
System::println("%s: %s", source_paragraph.name, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
Checks::exit_success(VCPKG_LINE_INFO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -10,46 +10,9 @@
|
|||||||
|
|
||||||
namespace vcpkg::Commands::Search
|
namespace vcpkg::Commands::Search
|
||||||
{
|
{
|
||||||
static constexpr StringLiteral OPTION_GRAPH = "--graph"; // TODO: This should find a better home, eventually
|
|
||||||
static constexpr StringLiteral OPTION_FULLDESC =
|
static constexpr StringLiteral OPTION_FULLDESC =
|
||||||
"--x-full-desc"; // TODO: This should find a better home, eventually
|
"--x-full-desc"; // TODO: This should find a better home, eventually
|
||||||
|
|
||||||
static std::string replace_dashes_with_underscore(const std::string& input)
|
|
||||||
{
|
|
||||||
std::string output = input;
|
|
||||||
std::replace(output.begin(), output.end(), '-', '_');
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string create_graph_as_string(
|
|
||||||
const std::vector<std::unique_ptr<SourceControlFile>>& source_control_files)
|
|
||||||
{
|
|
||||||
int empty_node_count = 0;
|
|
||||||
|
|
||||||
std::string s;
|
|
||||||
s.append("digraph G{ rankdir=LR; edge [minlen=3]; overlap=false;");
|
|
||||||
|
|
||||||
for (const auto& source_control_file : source_control_files)
|
|
||||||
{
|
|
||||||
const SourceParagraph& source_paragraph = *source_control_file->core_paragraph;
|
|
||||||
if (source_paragraph.depends.empty())
|
|
||||||
{
|
|
||||||
empty_node_count++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string name = replace_dashes_with_underscore(source_paragraph.name);
|
|
||||||
s.append(Strings::format("%s;", name));
|
|
||||||
for (const Dependency& d : source_paragraph.depends)
|
|
||||||
{
|
|
||||||
const std::string dependency_name = replace_dashes_with_underscore(d.name());
|
|
||||||
s.append(Strings::format("%s -> %s;", name, dependency_name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
s.append(Strings::format("empty [label=\"%d singletons...\"]; }", empty_node_count));
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
static void do_print(const SourceParagraph& source_paragraph, bool full_desc)
|
static void do_print(const SourceParagraph& source_paragraph, bool full_desc)
|
||||||
{
|
{
|
||||||
if (full_desc)
|
if (full_desc)
|
||||||
@ -80,8 +43,7 @@ namespace vcpkg::Commands::Search
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr std::array<CommandSwitch, 2> SEARCH_SWITCHES = {{
|
static constexpr std::array<CommandSwitch, 1> SEARCH_SWITCHES = {{
|
||||||
{OPTION_GRAPH, "Open editor into the port-specific buildtree subfolder"},
|
|
||||||
{OPTION_FULLDESC, "Do not truncate long text"},
|
{OPTION_FULLDESC, "Do not truncate long text"},
|
||||||
}};
|
}};
|
||||||
|
|
||||||
@ -102,13 +64,6 @@ namespace vcpkg::Commands::Search
|
|||||||
|
|
||||||
auto source_paragraphs = Paragraphs::load_all_ports(paths.get_filesystem(), paths.ports);
|
auto source_paragraphs = Paragraphs::load_all_ports(paths.get_filesystem(), paths.ports);
|
||||||
|
|
||||||
if (Util::Sets::contains(options.switches, OPTION_GRAPH))
|
|
||||||
{
|
|
||||||
const std::string graph_as_string = create_graph_as_string(source_paragraphs);
|
|
||||||
System::println(graph_as_string);
|
|
||||||
Checks::exit_success(VCPKG_LINE_INFO);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (args.command_arguments.empty())
|
if (args.command_arguments.empty())
|
||||||
{
|
{
|
||||||
for (const auto& source_control_file : source_paragraphs)
|
for (const auto& source_control_file : source_paragraphs)
|
||||||
|
Loading…
Reference in New Issue
Block a user