Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make registries distinguish between 'baseline is broken' and 'baseline missing'. #1203

Merged
merged 7 commits into from
Oct 6, 2023

Conversation

BillyONeal
Copy link
Member

Next in the series containing #1153

@BillyONeal BillyONeal reopened this Sep 19, 2023
include/vcpkg/paragraphs.h Outdated Show resolved Hide resolved
include/vcpkg/paragraphs.h Show resolved Hide resolved
include/vcpkg/registries.h Outdated Show resolved Hide resolved
src/vcpkg/sourceparagraph.cpp Outdated Show resolved Hide resolved
include/vcpkg/sourceparagraph.h Outdated Show resolved Hide resolved
include/vcpkg/paragraphparser.h Outdated Show resolved Hide resolved
include/vcpkg/sourceparagraph.h Outdated Show resolved Hide resolved
src/vcpkg/paragraphs.cpp Show resolved Hide resolved
Comment on lines 409 to 416
ExpectedL<std::vector<Paragraph>> pghs = parse_paragraphs(StringView{text}, origin);
if (auto vector_pghs = pghs.get())
{
return SourceControlFile::parse_control_file(origin, std::move(*vector_pghs));
return map_parse_expected_to_localized_string(
SourceControlFile::parse_control_file(origin, std::move(*vector_pghs)));
}

return ParseControlErrorInfo::from_error(origin, std::move(pghs).error());
return std::move(pghs).error();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion:

return parse_paragraphs(StringView{text}, origin)
  .then([origin] (std::vector<Paragraph>&& p)
    {
      return map_parse_expected_to_localized_string(
        SourceControlFile::parse_control_file(origin, std::move(p)));
    });

See also my comment at the top about a more "functional" approach to map_parse_expected_to_localized_string, which would result in:

return parse_paragraphs(StringView{text}, origin)
  .then([origin] (std::vector<Paragraph>&& p)
    {
      return SourceControlFile::parse_control_file(origin, std::move(p))
        .map_error(ToLocalizedString);
    });

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmmm I'm not a huge fan of nested transforms like that (map_error inside then) but this one might work.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did the map_error but I'm opposed to replacing 1 if with double nested lambdas.

@@ -49,11 +49,11 @@ namespace vcpkg
using ParseExpected = vcpkg::ExpectedT<std::unique_ptr<P>, std::unique_ptr<ParseControlErrorInfo>>;

template<class P>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion:

static constexpr struct ToLocalizedString_t
{
    LocalizedString operator()(std::unique_ptr<ParseControlErrorInfo> p) const;
} ToLocalizedString;

Then, call sites can use this as

return maybe_parse_thing().map_error(ToLocalizedString);

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

return ParseControlErrorInfo::from_error(port_name, std::move(formatted));
return msg::format_error(msgFailedToParseManifest, msg::path = manifest_path)
.append_raw("\n")
.append(format_filesystem_call_error(ec, "read_contents", {manifest_path}));
}

if (fs.exists(control_path, IgnoreErrors{}))
{
ExpectedL<std::vector<Paragraph>> pghs = get_paragraphs(fs, control_path);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to other suggestions, this could be:

return get_paragraphs(fs, control_path)
  .then([&control_path] (std::vector<Paragraph>&& p)
    {
      return SourceControlFile::parse_control_file(control_path, std::move(p))
        .map_error(ToLocalizedString);
    });

src/vcpkg/paragraphs.cpp Outdated Show resolved Hide resolved
src/vcpkg/portfileprovider.cpp Outdated Show resolved Hide resolved
auto version = maybe_version->get();
if (!version)
{
return msg::format_error(msgPortNotInBaseline, msg::package_name = port_name);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this also record the registry used for the lookup?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked at doing this but I'm not sure what we would print; registries don't have names and we don't currently have a way in console output to refer to a particular one. I think it would be good to emit the error attributed to the JSON document declaring the registry someday but I think that's outside the scope of this PR.


private:
const ReadOnlyFilesystem& m_fs;

Path m_path;
std::string m_baseline_identifier;
DelayedInit<Baseline> m_baseline;
DelayedInit<ExpectedL<Optional<Baseline>>> m_baseline;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be just ExpectedL<Baseline>?

src/vcpkg/registries.cpp Outdated Show resolved Hide resolved
auto b = load_baseline_versions(m_paths.get_filesystem(), *maybe_path.get()).value_or_exit(VCPKG_LINE_INFO);
if (auto p = b.get())

auto maybe_maybe_baseline = load_baseline_versions(m_paths.get_filesystem(), *path);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there any users that care about the ExpectedL<>(nullopt) case? This seems ripe for simplification to just ExpectedL<Baseline>.

I think consumers like BuiltinGitRegistry should be adding their context information (m_baseline_identifier) always -- why should "file not found" be special compared to "parse error"?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ExpectedL<>(nullopt) means 'that port is not in the baseline': https://github.com/microsoft/vcpkg-tool/pull/1203/files/38f738d8100a9119d08bf640fca4d5dceaef15ee#diff-9439a305925c63597b93bb0d49db1794b5b6120f7ca5456d3e99b403c862dbf5R93-R96

For instance, load_all_control_files ignores ports not in the baseline, but emits an error if there are errors:

https://github.com/microsoft/vcpkg-tool/pull/1203/files/38f738d8100a9119d08bf640fca4d5dceaef15ee#diff-d4fe92b1ebc56fd05568a18c509672434c578cf4e147b2d5aad36226c026ff00R547-R549

Both 'file not found' and 'parse failure' are errors. But 'parse success and the port you asked for is not in there' is not an error.

Copy link
Contributor

@ras0219-msft ras0219-msft Oct 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

edit: I realized that my comment is in a poor location -- I'm talking about load_baseline_versions (called on this line), not get_baseline_version (the encapsulating function).


By my reading, this call is not "Get the baseline for a port" -- this is "Load the baseline file".

ExpectedT<Optional<Baseline>> load_baseline_versions(fs, path);

Agreed that for ExpectedT<Optional<Version>>, nullopt means "not in baseline". But for this function (load_baseline_versions), as far as I can tell nullopt means "The baseline.json didn't exist at all" -- which seems the same as a parse error.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I see. Thanks GH for making a totally reasonable comment opaque.

It looks like this was here because some callers emitted different error messages for not exist vs. parse error. I think, in general, sometimes this can make sense; I certainly used it for load_git_versions_file in x-ci-verify-versions to do something different for 'the versions file is corrupted' vs. 'this port does not have a versions file yet'.

However, I can't think of obvious reasons that would want to happen for baseline things, so I've ripped this one out.

@BillyONeal BillyONeal merged commit 0d3da08 into microsoft:main Oct 6, 2023
5 checks passed
@BillyONeal BillyONeal deleted the clarify-no-baseline-vs-error branch October 6, 2023 03:22
Comment on lines +415 to +421
auto pghs = parse_paragraphs(StringView{text}, origin);
if (auto vector_pghs = pghs.get())
{
return SourceControlFile::parse_control_file(origin, std::move(*vector_pghs));
return SourceControlFile::parse_control_file(origin, std::move(*vector_pghs)).map_error(ToLocalizedString);
}

return ParseControlErrorInfo::from_error(origin, std::move(pghs).error());
return std::move(pghs).error();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
auto pghs = parse_paragraphs(StringView{text}, origin);
if (auto vector_pghs = pghs.get())
{
return SourceControlFile::parse_control_file(origin, std::move(*vector_pghs));
return SourceControlFile::parse_control_file(origin, std::move(*vector_pghs)).map_error(ToLocalizedString);
}
return ParseControlErrorInfo::from_error(origin, std::move(pghs).error());
return std::move(pghs).error();
return parse_paragraphs(text, origin).then([origin] (auto&& p) {
return SourceControlFile::parse_control_file(origin, std::move(p)).map_error(ToLocalizedString);
});

.map_error([&](LocalizedString&& error) {
return std::move(error).append(msgWhileCheckingOutBaseline,
msg::commit_sha = m_baseline_identifier);
});
});

auto baseline = maybe_baseline.get();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Below this line, in return maybe_baseline.error();, we should probably add at least some context of "while looking up port ". That at least will let users figure out the problematic registry themselves by matching patterns.


return Optional<Version>();
return Optional<Version>();
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
});
}).map_error([port_name](LocalizedString&& err) {
return std::move(err).append("while finding a baseline for port {port_name}", port_name);
});

(approximately; I think reversing might be better)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think map/then is clearer when processing needs to happen to 'both arms'. I did extract a common function though rather than repeating.

@ras0219-msft
Copy link
Contributor

(Still happy with the merge of this PR, these three were just nits that I had queued up)

BillyONeal added a commit to BillyONeal/vcpkg-tool that referenced this pull request Oct 10, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants