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

proposing new --format=<format> --out-file=<file.ext> feature #17507

Merged
merged 18 commits into from
Dec 30, 2024
7 changes: 6 additions & 1 deletion conan/api/output.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from colorama import Fore, Style

from conan.errors import ConanException
from conans.util.files import save

LEVEL_QUIET = 80 # -q
LEVEL_ERROR = 70 # Errors
Expand Down Expand Up @@ -285,10 +286,14 @@ def flush(self):
self.stream.flush()


def cli_out_write(data, fg=None, bg=None, endline="\n", indentation=0):
def cli_out_write(data, fg=None, bg=None, endline="\n", indentation=0, filename=None):
"""
Output to be used by formatters to dump information to stdout
"""
if filename is not None:
ConanOutput().info(f"Formatted output saved to '{filename}'")
save(filename, data)
Copy link
Member

Choose a reason for hiding this comment

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

There are a few commands whose formatter calls cli_out_write multiple times in a row.

Should we convert those to only call it once, or should this new functionality support appending?

Copy link
Member Author

Choose a reason for hiding this comment

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

Good catch. Not sure to be honest, I tend to think to re-write the formatter to include only 1 call, but there are some case that use colors and that would be a bit less elegant, but still doable

return
if (fg or bg) and _color_enabled(sys.stdout): # need color
data = f"{' ' * indentation}{fg or ''}{bg or ''}{data}{Style.RESET_ALL}{endline}"
sys.stdout.write(data)
Expand Down
11 changes: 10 additions & 1 deletion conan/cli/command.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import argparse
import inspect
import textwrap

from conan.api.output import ConanOutput
Expand Down Expand Up @@ -89,13 +90,21 @@ def _format(self, parser, info, *args):
except AttributeError:
formatarg = default_format

filename = None
if "." in formatarg:
filename = formatarg
_, formatarg = formatarg.rsplit(".", 1)

try:
formatter = self._formatters[formatarg]
except KeyError:
raise ConanException("{} is not a known format. Supported formatters are: {}".format(
formatarg, ", ".join(self._help_formatters)))

formatter(info)
if filename and "filename" in inspect.signature(formatter).parameters.keys():
formatter(info, filename=filename)
else:
formatter(info)

@staticmethod
def _dispatch_errors(info):
Expand Down
4 changes: 2 additions & 2 deletions conan/cli/formatters/graph/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,11 +138,11 @@ def format_graph_dot(result):
cli_out_write(_render_graph(graph, None, template, template_folder))


def format_graph_json(result):
def format_graph_json(result, filename=None):
graph = result["graph"]
field_filter = result.get("field_filter")
package_filter = result.get("package_filter")
serial = graph.serialize()
serial = filter_graph(serial, package_filter=package_filter, field_filter=field_filter)
json_result = json.dumps({"graph": serial}, indent=4)
cli_out_write(json_result)
cli_out_write(json_result, filename=filename)
9 changes: 9 additions & 0 deletions test/integration/command/info/info_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -435,3 +435,12 @@ def requirements(self):

c.run("graph info . -c tools.graph:vendor=build --build='lib*'")
c.assert_listed_binary({"lib/1.0": (NO_SETTINGS_PACKAGE_ID, "Build")})


def test_write_formatter_to_file():
c = TestClient(light=True)
c.save({"conanfile.py": GenConanfile("pkg", "0.1")})
c.run("graph info . --format=graph.json")
assert "Formatted output saved to 'graph.json'" in c.out
graph = json.loads(c.load("graph.json"))
assert len(graph["graph"]["nodes"]) == 1
Loading