Skip to content

Commit

Permalink
Billy CRs for version parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
strega-nil committed Mar 15, 2022
1 parent e11e4da commit e05d570
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 30 deletions.
3 changes: 3 additions & 0 deletions include/vcpkg/tools.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <vcpkg/fwd/vcpkgpaths.h>

#include <vcpkg/base/stringliteral.h>
#include <vcpkg/base/optional.h>

#include <string>
#include <utility>
Expand Down Expand Up @@ -44,5 +45,7 @@ namespace vcpkg
virtual const std::string& get_tool_version(const VcpkgPaths& paths, StringView tool) const = 0;
};

Optional<std::array<int, 3>> parse_tool_version_string(StringView string_version);

std::unique_ptr<ToolCache> get_tool_cache(RequireExactVersions abiToolVersionHandling);
}
43 changes: 43 additions & 0 deletions src/vcpkg-test/tools.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#include <catch2/catch.hpp>

#include <vcpkg/tools.h>

#include <array>

using namespace vcpkg;

TEST_CASE("parse_tool_version_string", "[tools]")
{
auto result = parse_tool_version_string("1.2.3");
REQUIRE(result.has_value());
CHECK(*result.get() == std::array<int, 3>{1, 2, 3});

result = parse_tool_version_string("3.22.3");
REQUIRE(result.has_value());
CHECK(*result.get() == std::array<int, 3>{3, 22, 3});

result = parse_tool_version_string("4.65");
REQUIRE(result.has_value());
CHECK(*result.get() == std::array<int, 3>{4, 65, 0});

result = parse_tool_version_string(R"(cmake version 3.22.2
CMake suite maintained and supported by Kitware (kitware.com/cmake).)");
REQUIRE(result.has_value());
CHECK(*result.get() == std::array<int, 3>{3, 22, 2});

result = parse_tool_version_string(R"(aria2 version 1.35.0
Copyright (C) 2006, 2019 Tatsuhiro Tsujikawa)");
REQUIRE(result.has_value());
CHECK(*result.get() == std::array<int, 3>{1, 35, 0});

result = parse_tool_version_string(R"(git version 2.17.1.windows.2)");
REQUIRE(result.has_value());
CHECK(*result.get() == std::array<int, 3>{2, 17, 1});

result = parse_tool_version_string(R"(git version 2.17.windows.2)");
REQUIRE(result.has_value());
CHECK(*result.get() == std::array<int, 3>{2, 17, 0});

result = parse_tool_version_string("4");
CHECK_FALSE(result.has_value());
}
31 changes: 12 additions & 19 deletions src/vcpkg/tools.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,39 +26,32 @@ namespace vcpkg
};

// /\d+\.\d+(\.\d+)?/
static Optional<std::array<int, 3>> parse_version_string(StringView string_version)
Optional<std::array<int, 3>> parse_tool_version_string(StringView string_version)
{
using P = Parse::ParserBase;

// first, find the beginning of the version
auto first = string_version.begin();
auto last = string_version.end();
const auto last = string_version.end();

// we're looking for the first instance of `<digits>.<digits>`
ParsedExternalVersion parsed_version{};
for (;;)
{
first = std::find_if(first, last, P::is_ascii_digit);
auto end_of_field = std::find_if_not(first, last, P::is_ascii_digit);
if (end_of_field == last)
if (first == last)
{
break;
return nullopt;
}
if (*end_of_field == '.')

if (try_parse_external_dot_version(parsed_version, StringView{first, last}) && !parsed_version.minor.empty())
{
++end_of_field;
if (end_of_field != last && P::is_ascii_digit(*end_of_field))
{
break;
}
break;
}
first = end_of_field;
}

ParsedExternalVersion parsed_version;
if (!try_parse_external_dot_version(parsed_version, StringView{first, last}))
{
return {};
first = std::find_if_not(first, last, P::is_ascii_digit);
}

parsed_version.normalize();

std::string buffer;
Expand Down Expand Up @@ -144,7 +137,7 @@ namespace vcpkg
const std::string sha512 = Strings::find_exactly_one_enclosed(tool_data, "<sha512>", "</sha512>").to_string();
auto archive_name = Strings::find_at_most_one_enclosed(tool_data, "<archiveName>", "</archiveName>");

const Optional<std::array<int, 3>> version = parse_version_string(version_as_string);
const Optional<std::array<int, 3>> version = parse_tool_version_string(version_as_string);
Checks::check_exit(VCPKG_LINE_INFO,
version.has_value(),
"Could not parse version for tool %s. Version string was: %s",
Expand Down Expand Up @@ -197,7 +190,7 @@ namespace vcpkg
auto maybe_version = tool_provider.get_version(paths, candidate);
const auto version = maybe_version.get();
if (!version) continue;
const auto parsed_version = parse_version_string(*version);
const auto parsed_version = parse_tool_version_string(*version);
if (!parsed_version) continue;
auto& actual_version = *parsed_version.get();
if (!accept_version(actual_version)) continue;
Expand Down
13 changes: 2 additions & 11 deletions src/vcpkg/versions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -469,8 +469,6 @@ namespace vcpkg

out.major = out.minor = out.patch = StringView{};

if (first == last) return false;
if (*first == 'v') ++first;
if (first == last) return false;

auto major_last = std::find_if_not(first, last, P::is_ascii_digit);
Expand All @@ -485,22 +483,15 @@ namespace vcpkg
}

auto minor_last = std::find_if_not(major_last + 1, last, P::is_ascii_digit);
if (minor_last == major_last + 1)
{
return false;
}
out.minor = StringView{major_last + 1, minor_last};
if (minor_last == last || *minor_last != '.')
if (minor_last == last || minor_last == major_last + 1 || *minor_last != '.')
{
return true;
}

auto patch_last = std::find_if_not(minor_last + 1, last, P::is_ascii_digit);
if (minor_last == major_last + 1)
{
return false;
}
out.patch = StringView{minor_last + 1, patch_last};

return true;
}
}

0 comments on commit e05d570

Please sign in to comment.