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

feat: tagfiles generation for cross-referencing in doxygen format #670

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from

Conversation

fpelliccioni
Copy link
Collaborator

@fpelliccioni fpelliccioni commented Sep 12, 2024

Fixed #650

@fpelliccioni fpelliccioni force-pushed the feat/tagfiles-doxygen-generation branch 2 times, most recently from dd39c17 to 30d3333 Compare September 12, 2024 10:57
Copy link
Collaborator

@alandefreitas alandefreitas left a comment

Choose a reason for hiding this comment

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

The logic for the Writer looks great. I think the only issue is where it would be called from.

include/mrdocs/Corpus.hpp Outdated Show resolved Hide resolved
include/mrdocs/Generator.hpp Outdated Show resolved Hide resolved
@fpelliccioni fpelliccioni force-pushed the feat/tagfiles-doxygen-generation branch 3 times, most recently from 669e5ee to 518dfe5 Compare October 4, 2024 14:49
@alandefreitas
Copy link
Collaborator

The problem CI has been fixed. Could you rebase this?

@alandefreitas
Copy link
Collaborator

However, we will still have a problem with the USR from Krystian's commit blocking CI.

I want to start by comparing the XML in the artifacts. Do you have the result for Boost.URL multipage? That's the one we can't risk breaking because it's already in production. It has to be compatible with the existing one.

@alandefreitas alandefreitas force-pushed the feat/tagfiles-doxygen-generation branch 2 times, most recently from 5728d41 to 4ea091f Compare October 7, 2024 16:40
@cppalliance-bot
Copy link

An automated preview of the documentation is available at https://670.mrdocs.prtest2.cppalliance.org/index.html

@fpelliccioni fpelliccioni force-pushed the feat/tagfiles-doxygen-generation branch from 4ea091f to 10d6cca Compare October 17, 2024 11:36
@cppalliance-bot
Copy link

An automated preview of the documentation is available at https://670.mrdocs.prtest2.cppalliance.org/index.html

@fpelliccioni fpelliccioni force-pushed the feat/tagfiles-doxygen-generation branch from 10d6cca to 08cbc26 Compare October 17, 2024 12:10
@cppalliance-bot
Copy link

An automated preview of the documentation is available at https://670.mrdocs.prtest2.cppalliance.org/index.html

@alandefreitas alandefreitas force-pushed the feat/tagfiles-doxygen-generation branch from 08cbc26 to 120b717 Compare October 17, 2024 15:43
@cppalliance-bot
Copy link

An automated preview of the documentation is available at https://670.mrdocs.prtest2.cppalliance.org/index.html

Copy link
Collaborator

@alandefreitas alandefreitas left a comment

Choose a reason for hiding this comment

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

It fails with

assertion failed: n <= indent_.size() on line 203 in src/lib/Gen/xml/XMLTags.cpp

@fpelliccioni fpelliccioni force-pushed the feat/tagfiles-doxygen-generation branch from 120b717 to e469482 Compare October 19, 2024 11:46
@cppalliance-bot
Copy link

An automated preview of the documentation is available at https://670.mrdocs.prtest2.cppalliance.org/index.html

@alandefreitas alandefreitas force-pushed the feat/tagfiles-doxygen-generation branch from e469482 to 7b9455e Compare October 22, 2024 22:48
@cppalliance-bot
Copy link

An automated preview of the documentation is available at https://670.mrdocs.prtest2.cppalliance.org/index.html

@alandefreitas
Copy link
Collaborator

The implementation of the tagfile write is excellent.

CI failed after I rebased. That was a good thing because it helped me catch a bug.

So, the reason CI is failing is trivial. The TestRunner calls if(auto err = gen_->buildOneString(generatedDocs, **corpus)), which calls Generator::buildOneString, where you changed the call to buildOne to buildOne(ss, corpus, "");. We could fix CI by just adapting AdocGenerator::buildOne to not generate the tagfile when this string is empty. However, this doesn't address the deeper issue here.

The real issue causing all of that is the API design. Your new fileName parameter in Generator::buildOne is breaking the contract of this abstract class.

  1. First of all, the new parameter is documented as @param fileName The file name to use for the output., but that's not what the implementation is doing. The filename is the filename for the tagfile, which is unrelated to the filename of the output. The parameter isn't even used in the XMLGenerator. It's even more confusing because fileName is not the filename of the tagfile but the basename to which "tag.xml" will be appended to form the tagfile filename.
  2. Most importantly, the contract of Generator::buildOne is that it renders the documentation to any output stream regardless of the filename because (i) there's not even a filename for most output types and (ii) if there were a file for each stream, the stream would become redundant. For instance, tests use buildOneString, which outputs the result to a string.

This bug was already there, but CI only made it evident. It worked before rebasing because Generator::buildOneString wasn't being covered with the AdocGenerator.

Because of how Generator expects the output to be decoupled from any filename and buildOne is based on streaming only that result to the output, the Generator should have received new virtual functions to buildTagfile(std::ostream& os, Corpus const& corpus) or something instead of buildOne trying to fill this role.

If this is hard to achieve because we can't decouple the logic of buildOne and buildTagfile, a second-best would be buildOne(std::ostream& os, Corpus const& corpus, std::ostream& tagFileOs) instead of buildOne(std::ostream& os, Corpus const& corpus, std::string_view fileName) and a new overload in Generator without std::ostream& tagFileOs which would call buildOne with a noop std::ostream for the tagFileOs.

This fixes the underlying problem and the original issue with buildOneString that's breaking CI.

@fpelliccioni fpelliccioni force-pushed the feat/tagfiles-doxygen-generation branch from 7b9455e to f04184a Compare October 29, 2024 17:32
@fpelliccioni
Copy link
Collaborator Author

The implementation of the tagfile write is excellent.

CI failed after I rebased. That was a good thing because it helped me catch a bug.

So, the reason CI is failing is trivial. The TestRunner calls if(auto err = gen_->buildOneString(generatedDocs, **corpus)), which calls Generator::buildOneString, where you changed the call to buildOne to buildOne(ss, corpus, "");. We could fix CI by just adapting AdocGenerator::buildOne to not generate the tagfile when this string is empty. However, this doesn't address the deeper issue here.

The real issue causing all of that is the API design. Your new fileName parameter in Generator::buildOne is breaking the contract of this abstract class.

  1. First of all, the new parameter is documented as @param fileName The file name to use for the output., but that's not what the implementation is doing. The filename is the filename for the tagfile, which is unrelated to the filename of the output. The parameter isn't even used in the XMLGenerator. It's even more confusing because fileName is not the filename of the tagfile but the basename to which "tag.xml" will be appended to form the tagfile filename.
  2. Most importantly, the contract of Generator::buildOne is that it renders the documentation to any output stream regardless of the filename because (i) there's not even a filename for most output types and (ii) if there were a file for each stream, the stream would become redundant. For instance, tests use buildOneString, which outputs the result to a string.

This bug was already there, but CI only made it evident. It worked before rebasing because Generator::buildOneString wasn't being covered with the AdocGenerator.

Because of how Generator expects the output to be decoupled from any filename and buildOne is based on streaming only that result to the output, the Generator should have received new virtual functions to buildTagfile(std::ostream& os, Corpus const& corpus) or something instead of buildOne trying to fill this role.

If this is hard to achieve because we can't decouple the logic of buildOne and buildTagfile, a second-best would be buildOne(std::ostream& os, Corpus const& corpus, std::ostream& tagFileOs) instead of buildOne(std::ostream& os, Corpus const& corpus, std::string_view fileName) and a new overload in Generator without std::ostream& tagFileOs which would call buildOne with a noop std::ostream for the tagFileOs.

This fixes the underlying problem and the original issue with buildOneString that's breaking CI.

This issue is addressed. I’ll let you know once CI passes so you can review, and if it’s good to go, feel free to merge.

@cppalliance-bot
Copy link

An automated preview of the documentation is available at https://670.mrdocs.prtest2.cppalliance.org/index.html

@fpelliccioni fpelliccioni force-pushed the feat/tagfiles-doxygen-generation branch from f04184a to 9b74877 Compare October 29, 2024 17:57
@fpelliccioni fpelliccioni changed the title feat: tagfiles generation for cross-referencing in doxygen format [WIP] feat: tagfiles generation for cross-referencing in doxygen format Oct 29, 2024
@cppalliance-bot
Copy link

An automated preview of the documentation is available at https://670.mrdocs.prtest2.cppalliance.org/index.html

@fpelliccioni fpelliccioni force-pushed the feat/tagfiles-doxygen-generation branch from 9b74877 to 4452a6b Compare October 29, 2024 21:30
@cppalliance-bot
Copy link

An automated preview of the documentation is available at https://670.mrdocs.prtest2.cppalliance.org/index.html

@fpelliccioni fpelliccioni changed the title [WIP] feat: tagfiles generation for cross-referencing in doxygen format feat: tagfiles generation for cross-referencing in doxygen format Oct 29, 2024
@fpelliccioni
Copy link
Collaborator Author

@alandefreitas done

Copy link
Collaborator

@alandefreitas alandefreitas left a comment

Choose a reason for hiding this comment

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

This solution is still not quite there yet.

*/
template <InfoParent T, class Pred, class F, class... Args>
void
traverseIf(
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do we need this function? Can't the caller use traverse as usual, evaluate the predicate in the callable f, and do nothing if the predicate is false? It seems like less cognitive bandwidth—one less function to remember and maintain.

buildOne(
std::ostream& os,
Corpus const& corpus,
GenerationContext const& context) const = 0;
Copy link
Collaborator

Choose a reason for hiding this comment

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

My impression is that this solution expands the problem rather than solves it. Now, not only we expect a std::string tagFileName; (which breaks the contract of the class) but we expect a redundant std::ostream& tagFileOs; that needs to be handled and maintained.

I don't know if you're familiar with SOLID, but maybe have a look at https://medium.com/@oleksandra_shershen/solid-principles-implementation-and-examples-in-c-99f0d7e3e868.

The original problem is that expecting std::string tagFileName as a parameter breaks the contract of the parent class because the single responsibility of buildOne should be streaming the documentation results to any output. In other words, ideally, the parent Generator class shouldn't mention anything related to tagfiles because being able to generate tagfiles is not a property of all generators. If only some generators have this functionality, ideally, there should be an intermediary class (say GeneratorThatAlsoGeneratesTagfiles to avoid bikeshedding for now) between Generator and the generators that so have tagfiles functionality (AdocGenerator and HTMLGenerator). "GeneratorThatAlsoGeneratesTagfiles" would inherit from Generator and define the common API for generating tagfiles (which might have many similarities for all generators). AdocGenerator and HTMLGenerator would then inherit from "GeneratorThatAlsoGeneratesTagfiles" and only implement whatever is different for Adoc and HTML, which I don't expect to be much because only the file extension of the filenames should be different.

The solution I proposed is a buildTagfile(std::ostream& os, Corpus const& corpus), ideally in this new intermediary base class with the common logic for tagfiles. If we really don't want an intermediary class for "convenience", then this buildTagfile(std::ostream& os, Corpus const& corpus) function could go directly in the generator and do nothing when the Generator cannot generate tagfiles.

If the logic for tag files can't be decoupled from the logic for buildOne, maybe we could consider more complex solutions because it's impossible to implement its single responsibility. But it's clear that tagfiles can be implemented separately because they're basically an XML generator with a different schema.

@@ -69,10 +76,35 @@ build(
if(! ex)
return ex.error();

MultiPageVisitor visitor(*ex, outputPath, corpus);
std::string path = files::appendPath(outputPath, "reference.tag.xml");
Copy link
Collaborator

Choose a reason for hiding this comment

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

We need an option here, such as:

https://www.doxygen.nl/manual/config.html#cfg_generate_tagfile

Its default value can be "reference.tag.xml" or whatever and tagfiles won't be generated when it's empty.

}

RawOstream raw_os(os);
auto tagfileWriter = TagfileWriter(raw_os, corpus);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Completely independent behavior. It's not even using the domCorpus that includes the reference file names. It shouldn't be made dependent on build for "convenience".

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.

Tagfiles
3 participants