Skip to content

Commit 064451d

Browse files
committed
fixed: simdjson ondemand parsing order incorrect, leading to not readingthe info field in json properly
1 parent b2d741f commit 064451d

File tree

1 file changed

+52
-13
lines changed

1 file changed

+52
-13
lines changed

libmamba/src/solver/libsolv/helpers.cpp

Lines changed: 52 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -550,35 +550,74 @@ namespace mamba::solver::libsolv
550550
LOG_INFO << "Reading repodata.json file " << filename << " for repo " << repo.name()
551551
<< " using mamba";
552552

553+
// WARNING:
554+
// We use below SimdJson's "on demand" parser, which does not tolerate
555+
// reading the same value more than once. This means we need to make
556+
// sure that the objects and their fields are read once and kept around
557+
// until being used if necessary. This is why the code belows tries hard
558+
// to pre-read the general data in a way that prevents jumping up and down
559+
// the hierarchy of json objects. When this rule is not followed, the parsing
560+
// might end earlier than expected or might skip data that are read when they
561+
// shouldnt be, leading to *runtime issues* that might not be visible at first.
562+
// Because of these reasons, be careful when modifingy the following parsing
563+
// code.
564+
553565
auto parser = simdjson::ondemand::parser();
554566
const auto lock = LockFile(filename);
555567
const auto json_content = simdjson::padded_string::load(filename.string()); // must be kept alive while reading json
556568
auto repodata_doc = parser.iterate(json_content);
557569

570+
const auto repodata_version = [&] {
571+
if (auto version = repodata_doc["repodata_version"].get_int64(); !version.error())
572+
{
573+
return version.value();
574+
}
575+
else
576+
{
577+
return std::int64_t{ 1 };
578+
}
579+
}();
580+
581+
582+
auto info = [&]{
583+
if(auto value = repodata_doc["info"]; !value.error())
584+
{
585+
if (auto object = value.get_object(); !object.error())
586+
{
587+
return std::make_optional(object);
588+
}
589+
}
590+
return decltype(std::make_optional(repodata_doc["info"].get_object())){};
591+
592+
}();
558593

559594
// An override for missing package subdir is found at the top level
560-
auto default_subdir = std::string();
561-
if (auto subdir = repodata_doc["/info/subdir"]; !subdir.error())
562-
{
563-
default_subdir = std::string(subdir.get_string().value_unsafe());
564-
}
595+
const auto default_subdir = [&]{
596+
if (info)
597+
{
598+
if (auto subdir = info.value()["subdir"]; !subdir.error())
599+
{
600+
return std::string(subdir.get_string().value_unsafe());
601+
}
602+
}
603+
604+
return std::string{};
605+
}();
565606

566607

567608
// Get `base_url` in case 'repodata_version': 2
568609
// cf. https://github.com/conda-incubator/ceps/blob/main/cep-15.md
569-
auto base_url = repo_url;
570-
if (auto repodata_version = repodata_doc["repodata_version"].get_int64();
571-
!repodata_version.error())
572-
{
573-
if (repodata_version.value_unsafe() == 2)
610+
const auto base_url = [&] {
611+
if (repodata_version == 2 && info)
574612
{
575-
if (auto url = repodata_doc["/info/base_url"]; !url.error())
613+
if (auto url = info.value()["base_url"]; !url.error())
576614
{
577-
base_url = std::string(url.get_string().value_unsafe());
615+
return std::string(url.get_string().value_unsafe());
578616
}
579617
}
580-
}
581618

619+
return repo_url;
620+
}();
582621

583622
const auto parsed_url = specs::CondaURL::parse(base_url)
584623
.or_else([](specs::ParseError&& err) { throw std::move(err); })

0 commit comments

Comments
 (0)