Skip to content

Commit

Permalink
Add --format to depend-info. (#1080)
Browse files Browse the repository at this point in the history
* Add --format to depend-info.

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

Documentation update: microsoft/vcpkg-docs#89

* xtree => x-tree, can not => cannot
  • Loading branch information
BillyONeal authored May 30, 2023
1 parent 2e31d67 commit 528fe75
Show file tree
Hide file tree
Showing 8 changed files with 541 additions and 151 deletions.
33 changes: 24 additions & 9 deletions include/vcpkg/base/message-data.inc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
(),
"",
"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,
(),
"",
"Set sort order for the list of dependencies, accepted values are: lexicographical, topological "
"(default), x-tree, "
"reverse")
"--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}")
Expand Down Expand Up @@ -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),
Expand Down
27 changes: 27 additions & 0 deletions include/vcpkg/commands.dependinfo.h
Original file line number Diff line number Diff line change
@@ -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>
Expand All @@ -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,
Expand Down
26 changes: 16 additions & 10 deletions locales/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -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}",
Expand Down Expand Up @@ -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.",
Expand Down Expand Up @@ -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",
Expand Down
257 changes: 257 additions & 0 deletions src/vcpkg-test/commands.dependinfo.cpp
Original file line number Diff line number Diff line change
@@ -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);
}
Loading

0 comments on commit 528fe75

Please sign in to comment.