* Add --format to depend-info.

Add error handling and testing to depend-info switch handling.

Documentation update: https://github.com/microsoft/vcpkg-docs/pull/89

* xtree => x-tree, can not => cannot
This commit is contained in:
Billy O'Neal 2023-05-30 09:28:21 -07:00 коммит произвёл GitHub
Родитель 2e31d678b4
Коммит 528fe75d7c
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
8 изменённых файлов: 546 добавлений и 156 удалений

Просмотреть файл

@ -466,16 +466,31 @@ DECLARE_MESSAGE(CmdAddVersionOptSkipFormatChk, (), "", "Skips the formatting che
DECLARE_MESSAGE(CmdAddVersionOptSkipVersionFormatChk, (), "", "Skips the version format check.")
DECLARE_MESSAGE(CmdAddVersionOptVerbose, (), "", "Print success messages instead of just errors.")
DECLARE_MESSAGE(CmdContactOptSurvey, (), "", "Launch default browser to the current vcpkg survey")
DECLARE_MESSAGE(CmdDependInfoOptDepth, (), "", "Show recursion depth in output")
DECLARE_MESSAGE(CmdDependInfoOptDGML, (), "", "Creates graph on basis of dgml")
DECLARE_MESSAGE(CmdDependInfoOptDot, (), "", "Creates graph on basis of dot")
DECLARE_MESSAGE(CmdDependInfoOptMaxRecurse, (), "", "Set max recursion depth, a value of -1 indicates no limit")
DECLARE_MESSAGE(CmdDependInfoOptSort,
DECLARE_MESSAGE(CmdDependInfoFormatConflict,
(),
"",
"Set sort order for the list of dependencies, accepted values are: lexicographical, topological "
"(default), x-tree, "
"reverse")
"Conflicting formats specified. Only one of --format, --dgml, or --dot are accepted.")
DECLARE_MESSAGE(CmdDependInfoFormatHelp,
(),
"The alternatives in ``s must not be localized.",
"Choose output format, one of `list`, `tree`, `dot`, or `dgml`.")
DECLARE_MESSAGE(
CmdDependInfoFormatInvalid,
(msg::value),
"The alternatives in ``s must not be localized. {value} is what the user specified.",
"--format={value} is not a recognized format. --format must be one of `list`, `tree`, `dot`, or `dgml`.")
DECLARE_MESSAGE(CmdDependInfoShowDepthFormatMismatch,
(),
"",
"--show-depth can only be used with `list` and `tree` formats.")
DECLARE_MESSAGE(CmdDependInfoXtreeTree, (), "", "--sort=x-tree cannot be used with formats other than tree")
DECLARE_MESSAGE(CmdDependInfoOptDepth, (), "", "Show recursion depth in `list` output.")
DECLARE_MESSAGE(CmdDependInfoOptMaxRecurse, (), "", "Set max recursion depth. Default is no limit.")
DECLARE_MESSAGE(CmdDependInfoOptSort,
(),
"The alternatives in ``s must not be localized, but the localized text can explain what each value "
"means. The value `reverse` means 'reverse-topological'.",
"Choose sort order for the `list` format, one of `lexicographical`, `topological` (default), `reverse`")
DECLARE_MESSAGE(CmdEditOptAll, (), "", "Open editor into the port as well as the port-specific buildtree subfolder")
DECLARE_MESSAGE(CmdEditOptBuildTrees, (), "", "Open editor into the port-specific buildtree subfolder")
DECLARE_MESSAGE(CmdEnvOptions, (msg::path, msg::env_var), "", "Add installed {path} to {env_var}")
@ -1844,7 +1859,7 @@ DECLARE_MESSAGE(MultipleFeatures,
DECLARE_MESSAGE(MutuallyExclusiveOption,
(msg::value, msg::option),
"{value} is a second {option} switch",
"--{value} can not be used with --{option}.")
"--{value} cannot be used with --{option}.")
DECLARE_MESSAGE(NavigateToNPS, (msg::url), "", "Please navigate to {url} in your preferred browser.")
DECLARE_MESSAGE(NewConfigurationAlreadyExists,
(msg::path),

Просмотреть файл

@ -1,5 +1,7 @@
#pragma once
#include <vcpkg/base/fwd/expected.h>
#include <vcpkg/fwd/triplet.h>
#include <vcpkg/fwd/vcpkgcmdarguments.h>
#include <vcpkg/fwd/vcpkgpaths.h>
@ -8,6 +10,31 @@ namespace vcpkg::Commands::DependInfo
{
extern const CommandStructure COMMAND_STRUCTURE;
enum class DependInfoSortMode
{
Lexicographical,
Topological,
ReverseTopological
};
enum class DependInfoFormat
{
List,
Tree,
Dot,
Dgml
};
struct DependInfoStrategy
{
DependInfoSortMode sort_mode;
DependInfoFormat format;
int max_depth;
bool show_depth;
};
ExpectedL<DependInfoStrategy> determine_depend_info_mode(const ParsedArguments& args);
void perform_and_exit(const VcpkgCmdArguments& args,
const VcpkgPaths& paths,
Triplet default_triplet,

Просмотреть файл

@ -272,11 +272,17 @@
"CmdAddVersionOptSkipVersionFormatChk": "Skips the version format check.",
"CmdAddVersionOptVerbose": "Print success messages instead of just errors.",
"CmdContactOptSurvey": "Launch default browser to the current vcpkg survey",
"CmdDependInfoOptDGML": "Creates graph on basis of dgml",
"CmdDependInfoOptDepth": "Show recursion depth in output",
"CmdDependInfoOptDot": "Creates graph on basis of dot",
"CmdDependInfoOptMaxRecurse": "Set max recursion depth, a value of -1 indicates no limit",
"CmdDependInfoOptSort": "Set sort order for the list of dependencies, accepted values are: lexicographical, topological (default), x-tree, reverse",
"CmdDependInfoFormatConflict": "Conflicting formats specified. Only one of --format, --dgml, or --dot are accepted.",
"CmdDependInfoFormatHelp": "Choose output format, one of `list`, `tree`, `dot`, or `dgml`.",
"_CmdDependInfoFormatHelp.comment": "The alternatives in ``s must not be localized.",
"CmdDependInfoFormatInvalid": "--format={value} is not a recognized format. --format must be one of `list`, `tree`, `dot`, or `dgml`.",
"_CmdDependInfoFormatInvalid.comment": "The alternatives in ``s must not be localized. {value} is what the user specified.",
"CmdDependInfoOptDepth": "Show recursion depth in `list` output.",
"CmdDependInfoOptMaxRecurse": "Set max recursion depth. Default is no limit.",
"CmdDependInfoOptSort": "Choose sort order for the `list` format, one of `lexicographical`, `topological` (default), `reverse`",
"_CmdDependInfoOptSort.comment": "The alternatives in ``s must not be localized, but the localized text can explain what each value means. The value `reverse` means 'reverse-topological'.",
"CmdDependInfoShowDepthFormatMismatch": "--show-depth can only be used with `list` and `tree` formats.",
"CmdDependInfoXtreeTree": "--sort=x-tree cannot be used with formats other than tree",
"CmdEditOptAll": "Open editor into the port as well as the port-specific buildtree subfolder",
"CmdEditOptBuildTrees": "Open editor into the port-specific buildtree subfolder",
"CmdEnvOptions": "Add installed {path} to {env_var}",
@ -1034,7 +1040,7 @@
"_MultiArch.comment": "An example of {option} is editable.",
"MultipleFeatures": "{package_name} declares {feature} multiple times; please ensure that features have distinct names",
"_MultipleFeatures.comment": "An example of {package_name} is zlib. An example of {feature} is avisynthplus.",
"MutuallyExclusiveOption": "--{value} can not be used with --{option}.",
"MutuallyExclusiveOption": "--{value} cannot be used with --{option}.",
"_MutuallyExclusiveOption.comment": "{value} is a second {option} switch An example of {option} is editable.",
"NavigateToNPS": "Please navigate to {url} in your preferred browser.",
"_NavigateToNPS.comment": "An example of {url} is https://github.com/microsoft/vcpkg.",
@ -1565,10 +1571,10 @@
"_UnrecognizedCommand$.comment": "\n'${p0}' (aka 'commandline.inputs[0]') is a parameter of type 'string'\n",
"Use$ToGetHelp": "Use ${p0} to get help",
"_Use$ToGetHelp.comment": "\n'${p0}' is a parameter of type 'string'\n",
"FatalTheRootFolder$CanNotBeCreated": "Fatal: The root folder '${p0}' can not be created",
"_FatalTheRootFolder$CanNotBeCreated.comment": "\n'${p0}' (aka 'this.homeFolder.fsPath') is a parameter of type 'string'\n",
"FatalTheGlobalConfigurationFile$CanNotBeCreated": "Fatal: The global configuration file '${p0}' can not be created",
"_FatalTheGlobalConfigurationFile$CanNotBeCreated.comment": "\n'${p0}' (aka 'this.globalConfig.fsPath') is a parameter of type 'string'\n",
"FatalTheRootFolder$CannotBeCreated": "Fatal: The root folder '${p0}' cannot be created",
"_FatalTheRootFolder$CannotBeCreated.comment": "\n'${p0}' (aka 'this.homeFolder.fsPath') is a parameter of type 'string'\n",
"FatalTheGlobalConfigurationFile$CannotBeCreated": "Fatal: The global configuration file '${p0}' cannot be created",
"_FatalTheGlobalConfigurationFile$CannotBeCreated.comment": "\n'${p0}' (aka 'this.globalConfig.fsPath') is a parameter of type 'string'\n",
"VCPKGCOMMANDWasNotSet": "VCPKG_COMMAND was not set",
"RunningVcpkgInternallyReturnedANonzeroExitCode$": "Running vcpkg internally returned a nonzero exit code: ${p0}",
"_RunningVcpkgInternallyReturnedANonzeroExitCode$.comment": "\n'${p0}' is a parameter of type 'number'\n",

Просмотреть файл

@ -0,0 +1,257 @@
#include <catch2/catch.hpp>
#include <vcpkg/commands.dependinfo.h>
#include <vcpkg/vcpkgcmdarguments.h>
#include <limits.h>
using namespace vcpkg;
using namespace vcpkg::Commands::DependInfo;
TEST_CASE ("determine_depend_info_mode no args", "[depend-info]")
{
ParsedArguments pa;
auto result = determine_depend_info_mode(pa).value_or_exit(VCPKG_LINE_INFO);
REQUIRE(result.sort_mode == DependInfoSortMode::Topological);
REQUIRE(result.format == DependInfoFormat::List);
REQUIRE(result.max_depth == INT_MAX);
REQUIRE(!result.show_depth);
}
TEST_CASE ("determine_depend_info_mode formats", "[depend-info]")
{
ParsedArguments pa;
DependInfoFormat expected = DependInfoFormat::List;
SECTION ("list")
{
pa.settings.emplace("format", "list");
}
SECTION ("tree")
{
pa.settings.emplace("format", "tree");
expected = DependInfoFormat::Tree;
}
SECTION ("tree sort")
{
pa.settings.emplace("sort", "x-tree");
expected = DependInfoFormat::Tree;
}
SECTION ("tree tree sort")
{
pa.settings.emplace("format", "tree");
pa.settings.emplace("sort", "x-tree");
expected = DependInfoFormat::Tree;
}
SECTION ("dot")
{
pa.switches.insert("dot");
expected = DependInfoFormat::Dot;
}
SECTION ("dot format")
{
pa.settings.emplace("format", "dot");
expected = DependInfoFormat::Dot;
}
SECTION ("dot and format")
{
pa.switches.insert("dot");
pa.settings.emplace("format", "dot");
expected = DependInfoFormat::Dot;
}
SECTION ("dgml")
{
pa.switches.insert("dgml");
expected = DependInfoFormat::Dgml;
}
SECTION ("dgml format")
{
pa.settings.emplace("format", "dgml");
expected = DependInfoFormat::Dgml;
}
SECTION ("dgml and format")
{
pa.switches.insert("dgml");
pa.settings.emplace("format", "dgml");
expected = DependInfoFormat::Dgml;
}
auto result = determine_depend_info_mode(pa).value_or_exit(VCPKG_LINE_INFO);
REQUIRE(result.sort_mode == DependInfoSortMode::Topological);
REQUIRE(result.format == expected);
REQUIRE(result.max_depth == INT_MAX);
REQUIRE(!result.show_depth);
}
TEST_CASE ("determine_depend_info_mode sorts", "[depend-info]")
{
ParsedArguments pa;
DependInfoSortMode expected = DependInfoSortMode::Topological;
SECTION ("topological default")
{
// intentionally empty
}
SECTION ("topological")
{
pa.settings.emplace("sort", "topological");
}
SECTION ("reverse topological")
{
pa.settings.emplace("sort", "reverse");
expected = DependInfoSortMode::ReverseTopological;
}
SECTION ("lexicographical")
{
pa.settings.emplace("sort", "lexicographical");
expected = DependInfoSortMode::Lexicographical;
}
auto result = determine_depend_info_mode(pa).value_or_exit(VCPKG_LINE_INFO);
REQUIRE(result.sort_mode == expected);
REQUIRE(result.format == DependInfoFormat::List);
REQUIRE(result.max_depth == INT_MAX);
REQUIRE(!result.show_depth);
}
TEST_CASE ("determine_depend_info_mode max_depth", "[depend-info]")
{
ParsedArguments pa;
int expected = INT_MAX;
SECTION ("default")
{
// intentionally empty
}
SECTION ("zero")
{
expected = 0;
pa.settings.emplace("max-recurse", "0");
}
SECTION ("negative one")
{
expected = INT_MAX;
pa.settings.emplace("max-recurse", "-1");
}
SECTION ("negative")
{
expected = INT_MAX;
pa.settings.emplace("max-recurse", "-10");
}
SECTION ("positive")
{
expected = 2;
pa.settings.emplace("max-recurse", "2");
}
auto result = determine_depend_info_mode(pa).value_or_exit(VCPKG_LINE_INFO);
REQUIRE(result.sort_mode == DependInfoSortMode::Topological);
REQUIRE(result.format == DependInfoFormat::List);
REQUIRE(result.max_depth == expected);
REQUIRE(!result.show_depth);
}
TEST_CASE ("determine_depend_info_mode show_depth", "[depend-info]")
{
ParsedArguments pa;
pa.switches.emplace("show-depth");
auto result = determine_depend_info_mode(pa).value_or_exit(VCPKG_LINE_INFO);
REQUIRE(result.sort_mode == DependInfoSortMode::Topological);
REQUIRE(result.format == DependInfoFormat::List);
REQUIRE(result.max_depth == INT_MAX);
REQUIRE(result.show_depth);
}
TEST_CASE ("determine_depend_info_mode errors", "[depend-info]")
{
ParsedArguments pa;
auto expected = LocalizedString::from_raw("error: ");
SECTION ("bad format")
{
pa.settings.emplace("format", "frobinate");
expected.append_raw(
"--format=frobinate is not a recognized format. --format must be one of `list`, `tree`, `dot`, or `dgml`.");
}
SECTION ("bad sort")
{
pa.settings.emplace("sort", "frobinate");
expected.append_raw("Value of --sort must be one of 'lexicographical', 'topological', 'reverse'.");
}
SECTION ("bad legacy switches")
{
pa.settings.emplace("format", "list");
expected.append_raw("Conflicting formats specified. Only one of --format, --dgml, or --dot are accepted.");
SECTION ("dot")
{
pa.switches.emplace("dot");
}
SECTION ("dgml")
{
pa.switches.emplace("dot");
}
}
SECTION ("bad format sort tree")
{
pa.settings.emplace("format", "list");
pa.settings.emplace("sort", "x-tree");
expected.append_raw("--sort=x-tree cannot be used with formats other than tree");
}
SECTION ("show depth with graphs")
{
pa.switches.emplace("show-depth");
expected.append_raw("--show-depth can only be used with `list` and `tree` formats.");
SECTION ("dot")
{
pa.settings.emplace("format", "dot");
}
SECTION ("dgml")
{
pa.settings.emplace("format", "dgml");
}
}
SECTION ("bad max depth non numeric")
{
pa.settings.emplace("max-recurse", "frobinate");
expected.append_raw("Value of --max-recurse must be an integer.");
}
SECTION ("bad max depth too low")
{
static_assert(-2147483648 == INT_MIN, "integer range assumption");
pa.settings.emplace("max-recurse", "-2147483649");
expected.append_raw("Value of --max-recurse must be an integer.");
}
SECTION ("bad max depth too high")
{
static_assert(2147483647 == INT_MAX, "integer range assumption");
pa.settings.emplace("max-recurse", "2147483648");
expected.append_raw("Value of --max-recurse must be an integer.");
}
REQUIRE(determine_depend_info_mode(pa).error() == expected);
}

Просмотреть файл

@ -13,6 +13,8 @@
#include <vcpkg/registries.h>
#include <vcpkg/vcpkgcmdarguments.h>
#include <limits.h>
#include <vector>
namespace vcpkg::Commands::DependInfo
@ -88,73 +90,19 @@ namespace vcpkg::Commands::DependInfo
constexpr StringLiteral OPTION_SHOW_DEPTH = "show-depth";
constexpr StringLiteral OPTION_MAX_RECURSE = "max-recurse";
constexpr StringLiteral OPTION_SORT = "sort";
constexpr StringLiteral OPTION_FORMAT = "format";
constexpr int NO_RECURSE_LIMIT_VALUE = -1;
constexpr std::array<CommandSwitch, 3> DEPEND_SWITCHES = {{
{OPTION_DOT, nullptr},
{OPTION_DGML, nullptr},
{OPTION_SHOW_DEPTH, []() { return msg::format(msgCmdDependInfoOptDepth); }},
}};
constexpr std::array<CommandSwitch, 3> DEPEND_SWITCHES = {
{{OPTION_DOT, []() { return msg::format(msgCmdDependInfoOptDot); }},
{OPTION_DGML, []() { return msg::format(msgCmdDependInfoOptDGML); }},
{OPTION_SHOW_DEPTH, []() { return msg::format(msgCmdDependInfoOptDepth); }}}};
constexpr std::array<CommandSetting, 2> DEPEND_SETTINGS = {
{{OPTION_MAX_RECURSE, []() { return msg::format(msgCmdDependInfoOptMaxRecurse); }},
{OPTION_SORT, []() { return msg::format(msgCmdDependInfoOptSort); }}}};
enum SortMode
{
Lexicographical = 0,
Topological,
ReverseTopological,
Treelogical,
Default = Topological
};
int get_max_depth(const ParsedArguments& options)
{
auto iter = options.settings.find(OPTION_MAX_RECURSE);
if (iter != options.settings.end())
{
std::string value = iter->second;
try
{
return std::max(std::stoi(value), NO_RECURSE_LIMIT_VALUE);
}
catch (std::exception&)
{
Checks::msg_exit_with_message(VCPKG_LINE_INFO, msgOptionMustBeInteger, msg::option = "max-depth");
}
}
// No --max-depth set, default to no limit.
return NO_RECURSE_LIMIT_VALUE;
}
SortMode get_sort_mode(const ParsedArguments& options)
{
constexpr StringLiteral OPTION_SORT_LEXICOGRAPHICAL = "lexicographical";
constexpr StringLiteral OPTION_SORT_TOPOLOGICAL = "topological";
constexpr StringLiteral OPTION_SORT_REVERSE = "reverse";
constexpr StringLiteral OPTION_SORT_TREE = "x-tree";
static const std::map<StringLiteral, SortMode, std::less<>> sortModesMap{
{OPTION_SORT_LEXICOGRAPHICAL, Lexicographical},
{OPTION_SORT_TOPOLOGICAL, Topological},
{OPTION_SORT_REVERSE, ReverseTopological},
{OPTION_SORT_TREE, Treelogical},
};
auto iter = options.settings.find(OPTION_SORT);
if (iter != options.settings.end())
{
const std::string value = Strings::ascii_to_lowercase(std::string{iter->second});
auto it = sortModesMap.find(value);
if (it != sortModesMap.end())
{
return it->second;
}
Checks::msg_exit_with_message(VCPKG_LINE_INFO, msgInvalidCommandArgSort);
}
return Default;
}
constexpr std::array<CommandSetting, 3> DEPEND_SETTINGS = {{
{OPTION_MAX_RECURSE, []() { return msg::format(msgCmdDependInfoOptMaxRecurse); }},
{OPTION_SORT, []() { return msg::format(msgCmdDependInfoOptSort); }},
{OPTION_FORMAT, [] { return msg::format(msgCmdDependInfoFormatHelp); }},
}};
std::string create_dot_as_string(const std::vector<PackageDependInfo>& depend_info)
{
@ -209,20 +157,6 @@ namespace vcpkg::Commands::DependInfo
return s;
}
std::string create_graph_as_string(const std::set<std::string, std::less<>>& switches,
const std::vector<PackageDependInfo>& depend_info)
{
if (Util::Sets::contains(switches, OPTION_DOT))
{
return create_dot_as_string(depend_info);
}
else if (Util::Sets::contains(switches, OPTION_DGML))
{
return create_dgml_as_string(depend_info);
}
return {};
}
void assign_depth_to_dependencies(const std::string& package,
const int depth,
const int max_depth,
@ -239,7 +173,7 @@ namespace vcpkg::Commands::DependInfo
if (depth > info.depth)
{
info.depth = depth;
if (depth < max_depth || max_depth == NO_RECURSE_LIMIT_VALUE)
if (depth < max_depth)
{
for (auto&& dependency : info.dependencies)
{
@ -278,7 +212,21 @@ namespace vcpkg::Commands::DependInfo
Util::erase_remove_if(out, [](auto&& info) { return info.depth < 0; });
return out;
}
}
// Try to emplace candiate into maybe_target. If that would be inconsistent, return true.
// An engaged maybe_target is consistent with candidate if the contained value equals candidate.
template<typename T>
bool emplace_inconsistent(Optional<T>& maybe_target, const T& candidate)
{
if (auto target = maybe_target.get())
{
return *target != candidate;
}
maybe_target.emplace(candidate);
return false;
}
} // unnamed namespace
const CommandStructure COMMAND_STRUCTURE = {
[] { return create_example_string("depend-info sqlite3"); },
@ -288,15 +236,144 @@ namespace vcpkg::Commands::DependInfo
nullptr,
};
ExpectedL<DependInfoStrategy> determine_depend_info_mode(const ParsedArguments& args)
{
static constexpr StringLiteral OPTION_FORMAT_LIST = "list";
static constexpr StringLiteral OPTION_FORMAT_TREE = "tree";
static constexpr StringLiteral OPTION_FORMAT_DOT = "dot";
static constexpr StringLiteral OPTION_FORMAT_DGML = "dgml";
auto& settings = args.settings;
Optional<DependInfoFormat> maybe_format;
{
auto it = settings.find(OPTION_FORMAT);
if (it != settings.end())
{
auto as_lower = Strings::ascii_to_lowercase(it->second);
if (as_lower == OPTION_FORMAT_LIST)
{
maybe_format.emplace(DependInfoFormat::List);
}
else if (as_lower == OPTION_FORMAT_TREE)
{
maybe_format.emplace(DependInfoFormat::Tree);
}
else if (as_lower == OPTION_FORMAT_DOT)
{
maybe_format.emplace(DependInfoFormat::Dot);
}
else if (as_lower == OPTION_FORMAT_DGML)
{
maybe_format.emplace(DependInfoFormat::Dgml);
}
else
{
return msg::format_error(msgCmdDependInfoFormatInvalid, msg::value = it->second);
}
}
}
if (Util::Sets::contains(args.switches, OPTION_DOT))
{
if (emplace_inconsistent(maybe_format, DependInfoFormat::Dot))
{
return msg::format_error(msgCmdDependInfoFormatConflict);
}
}
if (Util::Sets::contains(args.switches, OPTION_DGML))
{
if (emplace_inconsistent(maybe_format, DependInfoFormat::Dgml))
{
return msg::format_error(msgCmdDependInfoFormatConflict);
}
}
static constexpr StringLiteral OPTION_SORT_LEXICOGRAPHICAL = "lexicographical";
static constexpr StringLiteral OPTION_SORT_TOPOLOGICAL = "topological";
static constexpr StringLiteral OPTION_SORT_REVERSE = "reverse";
static constexpr StringLiteral OPTION_SORT_TREE = "x-tree";
Optional<DependInfoSortMode> maybe_sort_mode;
{
auto it = settings.find(OPTION_SORT);
if (it != settings.end())
{
auto as_lower = Strings::ascii_to_lowercase(it->second);
if (as_lower == OPTION_SORT_LEXICOGRAPHICAL)
{
maybe_sort_mode.emplace(DependInfoSortMode::Lexicographical);
}
else if (as_lower == OPTION_SORT_TOPOLOGICAL)
{
maybe_sort_mode.emplace(DependInfoSortMode::Topological);
}
else if (as_lower == OPTION_SORT_REVERSE)
{
maybe_sort_mode.emplace(DependInfoSortMode::ReverseTopological);
}
else if (as_lower == OPTION_SORT_TREE)
{
if (emplace_inconsistent(maybe_format, DependInfoFormat::Tree))
{
return msg::format_error(msgCmdDependInfoXtreeTree);
}
}
else
{
return msg::format_error(msgInvalidCommandArgSort);
}
}
}
DependInfoStrategy result{maybe_sort_mode.value_or(DependInfoSortMode::Topological),
maybe_format.value_or(DependInfoFormat::List),
INT_MAX,
Util::Sets::contains(args.switches, OPTION_SHOW_DEPTH)};
{
auto it = settings.find(OPTION_MAX_RECURSE);
if (it != settings.end())
{
auto maybe_parsed = Strings::strto<int>(it->second);
if (auto parsed = maybe_parsed.get())
{
if (*parsed >= 0)
{
result.max_depth = *parsed;
}
}
else
{
return msg::format_error(msgOptionMustBeInteger, msg::option = OPTION_MAX_RECURSE);
}
}
}
if (result.show_depth)
{
switch (result.format)
{
case DependInfoFormat::List:
case DependInfoFormat::Tree:
// ok
break;
case DependInfoFormat::Dot:
case DependInfoFormat::Dgml: return msg::format_error(msgCmdDependInfoShowDepthFormatMismatch);
default: Checks::unreachable(VCPKG_LINE_INFO);
}
}
return result;
}
void perform_and_exit(const VcpkgCmdArguments& args,
const VcpkgPaths& paths,
Triplet default_triplet,
Triplet host_triplet)
{
const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE);
const int max_depth = get_max_depth(options);
const SortMode sort_mode = get_sort_mode(options);
const bool show_depth = Util::Sets::contains(options.switches, OPTION_SHOW_DEPTH);
const auto strategy = determine_depend_info_mode(options).value_or_exit(VCPKG_LINE_INFO);
bool default_triplet_used = false;
const std::vector<FullPackageSpec> specs = Util::fmap(options.command_arguments, [&](auto&& arg) {
@ -331,26 +408,26 @@ namespace vcpkg::Commands::DependInfo
std::vector<const InstallPlanAction*> install_actions =
Util::fmap(action_plan.already_installed, [&](const auto& action) { return &action; });
for (auto&& action : action_plan.install_actions)
install_actions.push_back(&action);
std::vector<PackageDependInfo> depend_info = extract_depend_info(install_actions, max_depth);
if (Util::Sets::contains(options.switches, OPTION_DOT) || Util::Sets::contains(options.switches, OPTION_DGML))
{
const std::vector<const SourceControlFile*> source_control_files =
Util::fmap(install_actions, [](const InstallPlanAction* install_action) {
const SourceControlFileAndLocation& scfl =
install_action->source_control_file_and_location.value_or_exit(VCPKG_LINE_INFO);
return const_cast<const SourceControlFile*>(scfl.source_control_file.get());
});
install_actions.push_back(&action);
}
std::string graph_as_string = create_graph_as_string(options.switches, depend_info);
graph_as_string.push_back('\n');
msg::write_unlocalized_text_to_stdout(Color::none, graph_as_string);
std::vector<PackageDependInfo> depend_info = extract_depend_info(install_actions, strategy.max_depth);
if (strategy.format == DependInfoFormat::Dot)
{
msg::write_unlocalized_text_to_stdout(Color::none, create_dot_as_string(depend_info));
msg::write_unlocalized_text_to_stdout(Color::none, "\n");
Checks::exit_success(VCPKG_LINE_INFO);
}
if (strategy.format == DependInfoFormat::Dgml)
{
msg::write_unlocalized_text_to_stdout(Color::none, create_dgml_as_string(depend_info));
msg::write_unlocalized_text_to_stdout(Color::none, "\n");
Checks::exit_success(VCPKG_LINE_INFO);
}
// TODO: Improve this code
auto lex = [](const PackageDependInfo& lhs, const PackageDependInfo& rhs) -> bool {
return lhs.package < rhs.package;
};
@ -361,56 +438,64 @@ namespace vcpkg::Commands::DependInfo
return lhs.depth < rhs.depth;
};
switch (sort_mode)
{
case SortMode::Lexicographical: std::sort(std::begin(depend_info), std::end(depend_info), lex); break;
case SortMode::ReverseTopological:
case SortMode::Treelogical: std::sort(std::begin(depend_info), std::end(depend_info), reverse); break;
case SortMode::Topological: std::sort(std::begin(depend_info), std::end(depend_info), topo); break;
default: Checks::unreachable(VCPKG_LINE_INFO);
}
if (sort_mode == SortMode::Treelogical)
if (strategy.format == DependInfoFormat::Tree)
{
Util::sort(depend_info, reverse);
auto first = depend_info.begin();
std::string features = Strings::join(", ", first->features);
if (show_depth)
if (strategy.show_depth)
{
msg::write_unlocalized_text_to_stdout(Color::error, fmt::format("({})", first->depth));
}
msg::write_unlocalized_text_to_stdout(Color::success, first->package);
if (!features.empty())
{
msg::write_unlocalized_text_to_stdout(Color::warning, "[" + features + "]");
}
msg::write_unlocalized_text_to_stdout(Color::none, "\n");
std::set<std::string> printed;
std::string prefix_buf;
print_dep_tree(prefix_buf, first->package, depend_info, printed);
Checks::exit_success(VCPKG_LINE_INFO);
}
else
{
for (auto&& info : depend_info)
{
if (info.depth >= 0)
{
const std::string features = Strings::join(", ", info.features);
const std::string dependencies = Strings::join(", ", info.dependencies);
if (show_depth)
{
msg::write_unlocalized_text_to_stdout(Color::error, fmt::format("({})", info.depth));
}
msg::write_unlocalized_text_to_stdout(Color::success, info.package);
if (!features.empty())
{
msg::write_unlocalized_text_to_stdout(Color::warning, "[" + features + "]");
}
msg::write_unlocalized_text_to_stdout(Color::none, ": " + dependencies + "\n");
}
}
if (strategy.format != DependInfoFormat::List)
{
Checks::unreachable(VCPKG_LINE_INFO);
}
switch (strategy.sort_mode)
{
case DependInfoSortMode::Lexicographical: Util::sort(depend_info, lex); break;
case DependInfoSortMode::ReverseTopological: Util::sort(depend_info, reverse); break;
case DependInfoSortMode::Topological: Util::sort(depend_info, topo); break;
default: Checks::unreachable(VCPKG_LINE_INFO);
}
for (auto&& info : depend_info)
{
if (info.depth < 0)
{
continue;
}
if (strategy.show_depth)
{
msg::write_unlocalized_text_to_stdout(Color::error, fmt::format("({})", info.depth));
}
msg::write_unlocalized_text_to_stdout(Color::success, info.package);
if (!info.features.empty())
{
msg::write_unlocalized_text_to_stdout(Color::warning, "[" + Strings::join(", ", info.features) + "]");
}
msg::write_unlocalized_text_to_stdout(Color::none, ": " + Strings::join(", ", info.dependencies) + "\n");
}
Checks::exit_success(VCPKG_LINE_INFO);
}
}

Просмотреть файл

@ -3,10 +3,10 @@
"_UnrecognizedCommand$.comment": "\n'${p0}' (aka 'commandline.inputs[0]') is a parameter of type 'string'\n",
"Use$ToGetHelp": "Use ${p0} to get help",
"_Use$ToGetHelp.comment": "\n'${p0}' is a parameter of type 'string'\n",
"FatalTheRootFolder$CanNotBeCreated": "Fatal: The root folder '${p0}' can not be created",
"_FatalTheRootFolder$CanNotBeCreated.comment": "\n'${p0}' (aka 'this.homeFolder.fsPath') is a parameter of type 'string'\n",
"FatalTheGlobalConfigurationFile$CanNotBeCreated": "Fatal: The global configuration file '${p0}' can not be created",
"_FatalTheGlobalConfigurationFile$CanNotBeCreated.comment": "\n'${p0}' (aka 'this.globalConfig.fsPath') is a parameter of type 'string'\n",
"FatalTheRootFolder$CannotBeCreated": "Fatal: The root folder '${p0}' cannot be created",
"_FatalTheRootFolder$CannotBeCreated.comment": "\n'${p0}' (aka 'this.homeFolder.fsPath') is a parameter of type 'string'\n",
"FatalTheGlobalConfigurationFile$CannotBeCreated": "Fatal: The global configuration file '${p0}' cannot be created",
"_FatalTheGlobalConfigurationFile$CannotBeCreated.comment": "\n'${p0}' (aka 'this.globalConfig.fsPath') is a parameter of type 'string'\n",
"VCPKGCOMMANDWasNotSet": "VCPKG_COMMAND was not set",
"RunningVcpkgInternallyReturnedANonzeroExitCode$": "Running vcpkg internally returned a nonzero exit code: ${p0}",
"_RunningVcpkgInternallyReturnedANonzeroExitCode$.comment": "\n'${p0}' is a parameter of type 'number'\n",

Просмотреть файл

@ -55,7 +55,7 @@ const mergeConflictMarkerLength = 7;
* is 1 and the character offset of b is 3 since `𐐀` is represented using two code
* units in UTF-16.
*
* Positions are line end character agnostic. So you can not specify a position that
* Positions are line end character agnostic. So you cannot specify a position that
* denotes `\r|\n` or `\n|` where `|` represents the character offset.
*/
export interface Position {

Просмотреть файл

@ -162,7 +162,7 @@ export class Session {
this.channels.debug(error?.message);
}
// check if it got made, because at an absolute minimum, we need a folder, so failing this is catastrophic.
strict.ok(await this.fileSystem.isDirectory(this.homeFolder), i`Fatal: The root folder '${this.homeFolder.fsPath}' can not be created`);
strict.ok(await this.fileSystem.isDirectory(this.homeFolder), i`Fatal: The root folder '${this.homeFolder.fsPath}' cannot be created`);
}
if (!await this.fileSystem.isFile(this.globalConfig)) {
@ -172,7 +172,7 @@ export class Session {
// if this throws, let it
}
// check if it got made, because at an absolute minimum, we need the config file, so failing this is catastrophic.
strict.ok(await this.fileSystem.isFile(this.globalConfig), i`Fatal: The global configuration file '${this.globalConfig.fsPath}' can not be created`);
strict.ok(await this.fileSystem.isFile(this.globalConfig), i`Fatal: The global configuration file '${this.globalConfig.fsPath}' cannot be created`);
}
// got past the checks, let's load the configuration.