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

Draft
wants to merge 10 commits into
base: develop2
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions 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 @@ -83,19 +84,19 @@ def doc(self):
def _format(self, parser, info, *args):
parser_args, _ = parser.parse_known_args(*args)

default_format = "text"
try:
formatarg = parser_args.format or default_format
except AttributeError:
formatarg = default_format
formatarg = getattr(parser_args, "format", "text")
out_file = getattr(parser_args, "out_file", None)

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 out_file and "out_file" in inspect.signature(formatter).parameters.keys():
formatter(info, out_file=out_file)
else:
formatter(info)

@staticmethod
def _dispatch_errors(info):
Expand Down
5 changes: 4 additions & 1 deletion conan/cli/commands/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from conan.api.output import ConanOutput, cli_out_write, Color
from conan.cli import make_abs_path
from conan.cli.args import common_graph_args, validate_common_graph_args
from conan.cli.command import conan_command, conan_subcommand
from conan.cli.command import conan_command, conan_subcommand, OnceArgument
from conan.cli.commands.list import prepare_pkglist_compact, print_serial
from conan.cli.formatters.graph import format_graph_html, format_graph_json, format_graph_dot
from conan.cli.formatters.graph.build_order_html import format_build_order_html
Expand Down Expand Up @@ -192,6 +192,9 @@ def graph_info(conan_api, parser, subparser, *args):
help="Deployer output folder, base build folder by default if not set")
subparser.add_argument("--build-require", action='store_true', default=False,
help='Whether the provided reference is a build-require')
subparser.add_argument("--out-file", action=OnceArgument,
Copy link
Member Author

Choose a reason for hiding this comment

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

This should be injected automatically and conditionally to the existence of formatters together with the definition of the --format argument. There cannot be a --out-file without a --format definition.

Copy link
Contributor

@czoido czoido Dec 20, 2024

Choose a reason for hiding this comment

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

Finally, my proposal is to add the --out-file always, to enable users do for example
conan config home --out-file=file.ext
and it uses the text formatter that is the one by default. Because in the end, there's always a formatter there that is the text one even if it does not show in the --help, but let's discuss about this with the team.

EDIT: Looks like this works in the test suite but not in my CLI, I'm leaving the PR in draft until I understand why.

help="Filename of the file to save the output of the formatter.")

args = parser.parse_args(*args)

# parameter validation
Expand Down
8 changes: 6 additions & 2 deletions conan/cli/formatters/graph/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
BINARY_DOWNLOAD, BINARY_BUILD, BINARY_MISSING, BINARY_UPDATE
from conans.client.graph.graph_error import GraphConflictError
from conans.client.installer import build_id
from conans.util.files import load
from conans.util.files import load, save


# FIXME: Check all this code when format_graph_[html/dot] use serialized graph
Expand Down Expand Up @@ -138,11 +138,15 @@ 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, out_file=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)
if out_file is not None:
ConanOutput().info(f"Formatted output saved to '{out_file}'")
save(out_file, json_result)
return
cli_out_write(json_result)
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=json --out-file=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