Skip to content

Commit

Permalink
Handle .tar.gz in pkg url (#3640)
Browse files Browse the repository at this point in the history
  • Loading branch information
Hind-M authored Dec 6, 2024
1 parent 8ea3103 commit 6141540
Show file tree
Hide file tree
Showing 6 changed files with 503 additions and 22 deletions.
3 changes: 2 additions & 1 deletion libmamba/include/mamba/specs/archive.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ namespace mamba::specs
{
inline static constexpr auto ARCHIVE_EXTENSIONS = std::array{ std::string_view(".tar.bz2"),
std::string_view(".conda"),
std::string_view(".whl") };
std::string_view(".whl"),
std::string_view(".tar.gz") };

/** Detect if the package path has one of the known archive extension. */
template <typename Str, std::enable_if_t<std::is_convertible_v<Str, std::string_view>, bool> = true>
Expand Down
1 change: 1 addition & 0 deletions libmamba/include/mamba/specs/package_info.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ namespace mamba::specs
Unknown,
Conda,
Wheel,
TarGz,
};

class PackageInfo
Expand Down
125 changes: 105 additions & 20 deletions libmamba/src/specs/package_info.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ namespace mamba::specs
{
return PackageType::Wheel;
}
else if (util::ends_with(spec, ".tar.gz"))
{
return PackageType::TarGz;
}
return PackageType::Conda;
}

Expand All @@ -40,7 +44,6 @@ namespace mamba::specs
return make_unexpected_parse("Missing filename extension.");
}


auto out = PackageInfo();
// TODO decide on the best way to group filename/channel/subdir/package_url all at once
out.package_url = util::path_or_url_to_url(spec);
Expand All @@ -58,37 +61,119 @@ namespace mamba::specs
out.filename = url.package();
url.clear_package();

// The filename format depends on the package_type:
out.package_type = parse_extension(spec);
// PackageType::Conda (.tar.bz2 or .conda):
// {pkg name}-{version}-{build string}.{tar.bz2, conda}
if (out.package_type == PackageType::Conda)
{
out.platform = url.platform_name();
url.clear_platform();
out.channel = util::rstrip(url.str(), '/');
}

// Build string
auto [head, tail] = util::rsplit_once(strip_archive_extension(out.filename), '-');
out.build_string = tail;
// Note that we use `rsplit...` instead of `split...`
// because the package name may contain '-'.
// Build string
auto [head, tail] = util::rsplit_once(strip_archive_extension(out.filename), '-');
out.build_string = tail;
if (!head.has_value())
{
return make_unexpected_parse(
fmt::format(R"(Missing name and version in filename "{}".)", out.filename)
);
}

if (!head.has_value())
{
return make_unexpected_parse(
fmt::format(R"(Missing name and version in filename "{}".)", out.filename)
);
}
// Version
std::tie(head, tail) = util::rsplit_once(head.value(), '-');
out.version = tail;
if (!head.has_value())
{
return make_unexpected_parse(
fmt::format(R"(Missing name in filename "{}".)", out.filename)
);
}

// Version
std::tie(head, tail) = util::rsplit_once(head.value(), '-');
out.version = tail;
if (!head.has_value())
// Name
out.name = head.value(); // There may be '-' in the name
}
// PackageType::Wheel (.whl):
// {pkg name}-{version}-{build tag (optional)}-{python tag}-{abi tag}-{platform tag}.whl
// cf.
// https://packaging.python.org/en/latest/specifications/platform-compatibility-tags/
else if (out.package_type == PackageType::Wheel)
{
return make_unexpected_parse(
fmt::format(R"(Missing name in filename "{}".)", out.filename)
);
// Platform tag
auto [head, tail] = util::rsplit_once(strip_archive_extension(out.filename), '-');
if (!head.has_value())
{
return make_unexpected_parse(
fmt::format(R"(Missing tags in filename "{}".)", out.filename)
);
}
// Abi tag
std::tie(head, tail) = util::rsplit_once(head.value(), '-');
if (!head.has_value())
{
return make_unexpected_parse(
fmt::format(R"(Missing tags in filename "{}".)", out.filename)
);
}
// Python tag
std::tie(head, tail) = util::rsplit_once(head.value(), '-');
if (!head.has_value())
{
return make_unexpected_parse(
fmt::format(R"(Missing tags in filename "{}".)", out.filename)
);
}
// Build tag or version
std::tie(head, tail) = util::rsplit_once(head.value(), '-');
if (!head.has_value())
{
return make_unexpected_parse(
fmt::format(R"(Missing tags in filename "{}".)", out.filename)
);
}
if (util::contains(tail, '.'))
{
// The tail is the version
out.version = tail;
// The head is the name
out.name = head.value(); // There may be '-' in the name
}
else
{
// The previous tail is the optional build tag
std::tie(head, tail) = util::rsplit_once(head.value(), '-');
// The tail is the version
out.version = tail;
if (!head.has_value())
{
return make_unexpected_parse(
fmt::format(R"(Missing name in filename "{}".)", out.filename)
);
}

// Name
out.name = head.value(); // There may be '-' in the name
}
}
// PackageType::TarGz (.tar.gz): {pkg name}-{version}.tar.gz
else if (out.package_type == PackageType::TarGz)
{
// Version
auto [head, tail] = util::rsplit_once(strip_archive_extension(out.filename), '-');
out.version = tail;
if (!head.has_value())
{
return make_unexpected_parse(
fmt::format(R"(Missing name in filename "{}".)", out.filename)
);
}

// Name
out.name = head.value(); // There may be '-' in the name
// Name
out.name = head.value(); // There may be '-' in the name
}

return out;
}
Expand Down
2 changes: 1 addition & 1 deletion libmambapy/tests/test_specs.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def test_ParseError():


def test_archive_extension():
assert libmambapy.specs.archive_extensions() == [".tar.bz2", ".conda", ".whl"]
assert libmambapy.specs.archive_extensions() == [".tar.bz2", ".conda", ".whl", ".tar.gz"]

assert libmambapy.specs.has_archive_extension("pkg.conda")
assert not libmambapy.specs.has_archive_extension("conda.pkg")
Expand Down
Loading

0 comments on commit 6141540

Please sign in to comment.