Skip to content

Commit

Permalink
Provide support for links to tool and its version in HTML tables
Browse files Browse the repository at this point in the history
The tool-info module can now provide URLs that table-generator
will use to linkify the tool name and the version number
in the benchmark-setup table.

Fixes sosy-lab#937.
  • Loading branch information
PhilippWendler committed Nov 3, 2023
1 parent 3809c22 commit 060f886
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 7 deletions.
9 changes: 8 additions & 1 deletion benchexec/tablegenerator/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -404,12 +404,19 @@ def collect_data(self, correct_only):
"""
self.results = []

tool = load_tool(self)
if tool:
self.attributes["project_url"] = [tool.project_url()]

versions = self.attributes["version"]
if len(versions) == 1 and versions[0]:
self.attributes["version_url"] = [tool.url_for_version(versions[0])]

def get_value_from_logfile(lines, identifier):
"""
This method searches for values in lines of the content.
It uses a tool-specific method to so.
"""
tool = load_tool(self)
if not tool:
return None
output = tooladapter.CURRENT_BASETOOL.RunOutput(lines)
Expand Down
2 changes: 1 addition & 1 deletion benchexec/tablegenerator/htmltable.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ def format_string_cell(attributes, format_string, onlyIf=None, default="Unknown"
return formatStr.format_map(collections.defaultdict(str, attributes))

def tool_data_cell(attributes):
keys = ["tool", "version"]
keys = ["tool", "version", "project_url", "version_url"]
return {k: str(attributes[k]) for k in keys if attributes.get(k)}

def get_row(
Expand Down
2 changes: 1 addition & 1 deletion benchexec/tablegenerator/react-table/build/main.min.js

Large diffs are not rendered by default.

21 changes: 19 additions & 2 deletions benchexec/tablegenerator/react-table/src/components/Summary.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,27 @@ const Summary = (props) => {
));
};

const renderToolNameAndVersion = ({ tool, version }) => {
const externalLink = (url, text) => {
if (url) {
return (
<a href={url} target="_blank" rel="noopener noreferrer">
{text}
</a>
);
} else {
return text;
}
};

const renderToolNameAndVersion = ({
tool,
version,
project_url,
version_url,
}) => {
return (
<>
{tool} {version}
{externalLink(project_url, tool)} {externalLink(version_url, version)}
</>
);
};
Expand Down
11 changes: 10 additions & 1 deletion benchexec/test_tool_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ def print_value(description, value, extra_line=False):
)


def print_optional_value(description, value, *args, **kwargs):
if value:
print_value(description, value, *args, **kwargs)


def print_list(description, value):
print_value(description, list(value), extra_line=True)

Expand Down Expand Up @@ -103,6 +108,7 @@ def print_tool_info(tool, tool_locator):
print_multiline_text("Documentation of tool module", inspect.getdoc(tool))

print_value("Name of tool", tool.name())
print_optional_value("Webpage", tool.project_url())

executable = tool.executable(tool_locator)
print_value("Executable", executable)
Expand All @@ -126,9 +132,12 @@ def print_tool_info(tool, tool_locator):
logging.warning("Executable is not within specified tool directory.")

try:
print_value("Version", tool.version(executable))
version = tool.version(executable)
except BaseException:
logging.warning("Determining version failed:", exc_info=1)
if version:
print_value("Version", tool.version(executable))
print_optional_value("URL for version", tool.url_for_version(version))

working_directory = tool.working_directory(executable)
print_value("Working directory", working_directory)
Expand Down
6 changes: 6 additions & 0 deletions benchexec/tooladapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,12 @@ def determine_result(self, run):
def get_value_from_output(self, output, identifier):
return self._wrapped.get_value_from_output(output._lines, identifier)

def project_url(self):
return None

def url_for_version(self, version):
return None

def close(self):
pass

Expand Down
29 changes: 29 additions & 0 deletions benchexec/tools/template.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,14 @@ def name(self):
"""
raise NotImplementedError()

def project_url(self):
"""
OPTIONAL, return the URL of the tool's webpage, if available.
@return None or a string with a URL in valid syntax for links on webpages
"""
return None # noqa: R501

@abstractmethod
def executable(self, tool_locator):
"""
Expand Down Expand Up @@ -179,6 +187,27 @@ def _version_from_tool(
output = next(matches, "")
return output

def url_for_version(self, version):
"""
OPTIONAL, return a link to the specific version of the tool.
This could be for example a link to a specific release page or even a revision
in the project's repository if the version is fine-granular enough.
BenchExec will use this link to make version numbers of the tool clickable.
Note that this method may be called without any of the other methods
being called before.
The string that is passed as a parameter is guaranteed to have been returned
by the version() method at some point, but not necessarily in the current
execution of BenchExec and possibly by a previous implementation of this
tool-info module.
If no URL can be produced, the method may simply return None.
@param version: a version string as returned by the version() method in the past
@return None or a string with a URL in valid syntax for links on webpages
"""
return None # noqa: R501

def environment(self, executable):
"""
OPTIONAL, this method is only necessary for tools
Expand Down
4 changes: 3 additions & 1 deletion doc/tool-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,12 @@ the method `determine_result` needs to be overwritten.
It is recommended to also overwrite the function `version` if the tool has a version
that can be automatically extracted.
A Python doc string ([example](https://github.com/sosy-lab/benchexec/blob/92f10942b884e3ea85ffb66027d98672894796c6/benchexec/tools/template.py#L27-L36))
should be added to the `Tool` class with the full name and URL of the tool.
should be added to the `Tool` class with some short description of the tool.
In this doc string there should also be any additional information about the tool-info module,
such as its supported features
or whether it adds or requires certain command-line parameter of the tool.
It is also recommended to overwrite the function `project_url`
if the tool has a webpage.

Overwrite the functions `cmdline` and `working_directory`, and `environment`
to adjust the respective values, e.g., to add the name of a given property file
Expand Down

0 comments on commit 060f886

Please sign in to comment.