Skip to content

Commit

Permalink
Output levels + logger output + Replaced tracer (#11522)
Browse files Browse the repository at this point in the history
* POC output levels

* Only 1 arg

* Remove cmake from this PR

* strict output level

* Logger in log format, tracer converted to log traces

* Test logger output

* Removed import

* Simplified tracer and better ui for messages

* Computing graph title

* Update conans/client/installer.py

Co-authored-by: James <james@conan.io>

* Api interface to control the output

* N review

Co-authored-by: James <james@conan.io>
  • Loading branch information
lasote and memsharded authored Jun 27, 2022
1 parent d872efa commit 1d1a973
Show file tree
Hide file tree
Showing 19 changed files with 427 additions and 147 deletions.
7 changes: 7 additions & 0 deletions conan/api/conan_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,10 @@ def __init__(self, cache_folder=None):


ConanAPI = ConanAPIV2


def set_conan_output_level(level, activate_logger=False):
from conans.cli import output
output.conan_output_level = level
output.conan_output_logger_format = activate_logger

3 changes: 3 additions & 0 deletions conan/api/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ def __str__(self):
return "{}: {} [Verify SSL: {}, Enabled: {}]".format(self.name, self.url, self.verify_ssl,
not self.disabled)

def __repr__(self):
return str(self)


class _RecipeUploadData:
def __init__(self, ref, prefs=None):
Expand Down
4 changes: 2 additions & 2 deletions conan/api/subapi/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import functools
import os

from conans.util.tracer import log_command
from conans.util.tracer import log_conan_api_call


def api_method(f):
Expand All @@ -17,7 +17,7 @@ def wrapper(subapi, *args, **kwargs):
try:
# FIXME: Fix this hack if we want to keep the action recorder
subapi_name = str(subapi.__class__.__name__).replace("API", "").lower()
log_command("{}.{}".format(subapi_name, f.__name__), kwargs)
log_conan_api_call("{}.{}".format(subapi_name, f.__name__), kwargs)
return f(subapi, *args, **kwargs)
finally:
if old_curdir:
Expand Down
24 changes: 21 additions & 3 deletions conans/cli/command.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import argparse
import textwrap

from conans.cli.commands import add_log_level_args, process_log_level_args
from conans.cli.output import cli_out_write
from conans.errors import ConanException

Expand Down Expand Up @@ -89,6 +90,9 @@ def __init__(self, method, formatters=None):
"commands should provide a documentation string explaining "
"its use briefly.".format(self._name))

def _init_log_levels(self):
add_log_level_args(self._parser)

def _init_formatters(self):
if self._formatters:
help_message = "Select the output format: {}".format(", ".join(list(self._formatters)))
Expand Down Expand Up @@ -133,17 +137,29 @@ def _format(self, parser, info, *args):
cli_out_write(result, endline="")


class ConanArgumentParser(argparse.ArgumentParser):

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

def parse_args(self, args=None, namespace=None):
args = super().parse_args(args)
process_log_level_args(args)
return args


class ConanCommand(BaseConanCommand):
def __init__(self, method, group=None, formatters=None):
super().__init__(method, formatters=formatters)
self._subcommands = {}
self._subcommand_parser = None
self._group = group or COMMAND_GROUPS['misc']
self._name = method.__name__.replace("_", "-")
self._parser = argparse.ArgumentParser(description=self._doc,
prog="conan {}".format(self._name),
formatter_class=SmartFormatter)
self._parser = ConanArgumentParser(description=self._doc,
prog="conan {}".format(self._name),
formatter_class=SmartFormatter)
self._init_formatters()
self._init_log_levels()

def add_subcommand(self, subcommand):
if not self._subcommand_parser:
Expand All @@ -155,6 +171,7 @@ def add_subcommand(self, subcommand):

def run(self, conan_api, parser, *args):
info = self._method(conan_api, parser, *args)

if not self._subcommands:
self._format(self._parser, info, *args)
else:
Expand Down Expand Up @@ -185,6 +202,7 @@ def set_parser(self, parent_parser, subcommand_parser):
self._parser = subcommand_parser.add_parser(self._name, help=self._doc)
self._parent_parser = parent_parser
self._init_formatters()
self._init_log_levels()


def conan_command(group=None, formatters=None):
Expand Down
35 changes: 35 additions & 0 deletions conans/cli/commands/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from json import JSONEncoder

from conan.api.model import Remote
from conans.errors import ConanException
from conans.model.package_ref import PkgReference
from conans.model.recipe_ref import RecipeReference

Expand Down Expand Up @@ -32,3 +33,37 @@ def default(self, o):
def json_formatter(data):
myjson = json.dumps(data, indent=4, cls=ConanJSONEncoder)
return myjson


def add_log_level_args(subparser):
subparser.add_argument("-v", default="status", nargs='?',
help="Level of detail of the output. Valid options from less verbose "
"to more verbose: -vquiet, -verror, -vwarning, -vnotice, -vstatus, "
"-v or -vverbose, -vv or -vdebug, -vvv or -vtrace")
subparser.add_argument("--logger", action="store_true",
help="Show the output with log format, with time, type and message.")


def process_log_level_args(args):
from conans.cli import output
from conans.cli.output import LEVEL_QUIET, LEVEL_ERROR, LEVEL_WARNING, LEVEL_NOTICE, \
LEVEL_STATUS, LEVEL_VERBOSE, LEVEL_DEBUG, LEVEL_TRACE

levels = {"quiet": LEVEL_QUIET, # -vquiet 80
"error": LEVEL_ERROR, # -verror 70
"warning": LEVEL_WARNING, # -vwaring 60
"notice": LEVEL_NOTICE, # -vnotice 50
"status": LEVEL_STATUS, # -vstatus 40
"verbose": LEVEL_VERBOSE, # -vverbose 30
None: LEVEL_VERBOSE, # -v 30
"debug": LEVEL_DEBUG, # -vdebug 20
"v": LEVEL_DEBUG, # -vv 20
"trace": LEVEL_TRACE, # -vtrace 10
"vv": LEVEL_TRACE, # -vvv 10
}

level = levels.get(args.v)
if not level:
raise ConanException(f"Invalid argument '-v{args.v}'")
output.conan_output_level = level
output.conan_output_logger_format = args.logger
4 changes: 2 additions & 2 deletions conans/cli/commands/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ def build(conan_api, parser, *args):
deps_graph, lockfile = graph_compute(args, conan_api, partial=args.lockfile_partial)

out = ConanOutput()
out.highlight("\n-------- Installing packages ----------")
out.title("Installing packages")
conan_api.install.install_binaries(deps_graph=deps_graph, remotes=remote, update=args.update)

source_folder = folder
output_folder = make_abs_path(args.output_folder, cwd) if args.output_folder else None
out.highlight("\n-------- Finalizing install (deploy, generators) ----------")
out.title("Finalizing install (deploy, generators)")
conan_api.install.install_consumer(deps_graph=deps_graph, source_folder=source_folder,
output_folder=output_folder)

Expand Down
16 changes: 8 additions & 8 deletions conans/cli/commands/create.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def create(conan_api, parser, *args):
profile_host, profile_build = get_profiles_from_args(conan_api, args)

out = ConanOutput()
out.highlight("-------- Exporting the recipe ----------")
out.highlight("Exporting the recipe")
ref = conan_api.export.export(path=path,
name=args.name, version=args.version,
user=args.user, channel=args.channel,
Expand All @@ -54,7 +54,7 @@ def create(conan_api, parser, *args):
# FIXME: We need to update build_requires too, not only ``requires``
lockfile.add(requires=[ref])

out.highlight("\n-------- Input profiles ----------")
out.title("Input profiles")
out.info("Profile host:")
out.info(profile_host.dumps())
out.info("Profile build:")
Expand All @@ -80,7 +80,7 @@ def create(conan_api, parser, *args):
tool_requires=tool_requires,
profile_host=profile_host)

out.highlight("-------- Computing dependency graph ----------")
out.title("Computing dependency graph")
check_updates = args.check_updates if "check_updates" in args else False
deps_graph = conan_api.graph.load_graph(root_node, profile_host=profile_host,
profile_build=profile_build,
Expand All @@ -89,7 +89,7 @@ def create(conan_api, parser, *args):
update=args.update,
check_update=check_updates)
print_graph_basic(deps_graph)
out.highlight("\n-------- Computing necessary packages ----------")
out.title("Computing necessary packages")
if args.build is None: # Not specified, force build the tested library
build_modes = [ref.repr_notime()]
else:
Expand All @@ -99,7 +99,7 @@ def create(conan_api, parser, *args):
lockfile=lockfile)
print_graph_packages(deps_graph)

out.highlight("\n-------- Installing packages ----------")
out.title("Installing packages")
conan_api.install.install_binaries(deps_graph=deps_graph, remotes=remotes, update=args.update)

save_lockfile_out(args, deps_graph, lockfile, cwd)
Expand All @@ -126,7 +126,7 @@ def _check_tested_reference_matches(deps_graph, tested_ref, out):

def test_package(conan_api, deps_graph, test_conanfile_path):
out = ConanOutput()
out.highlight("\n-------- Testing the package ----------")
out.title("Testing the package")
if len(deps_graph.nodes) == 1:
raise ConanException("The conanfile at '{}' doesn't declare any requirement, "
"use `self.tested_reference_str` to require the "
Expand All @@ -141,12 +141,12 @@ def test_package(conan_api, deps_graph, test_conanfile_path):
source_folder=conanfile_folder,
output_folder=output_folder)

out.highlight("\n-------- Testing the package: Building ----------")
out.title("Testing the package: Building")
app = ConanApp(conan_api.cache_folder)
conanfile.folders.set_base_package(conanfile.folders.base_build)
run_build_method(conanfile, app.hook_manager)

out.highlight("\n-------- Testing the package: Running test() ----------")
out.title("Testing the package: Running test()")
conanfile.output.highlight("Running test()")
with conanfile_exception_formatter(conanfile, "test"):
with chdir(conanfile.build_folder):
Expand Down
2 changes: 1 addition & 1 deletion conans/cli/commands/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def graph_build_order(conan_api, parser, subparser, *args):
deps_graph, lockfile = graph_compute(args, conan_api, partial=args.lockfile_partial)

out = ConanOutput()
out.highlight("-------- Computing the build order ----------")
out.highlight("Computing the build order")
install_graph = InstallGraph(deps_graph)
install_order_serialized = install_graph.install_build_order()
cli_build_order(install_order_serialized)
Expand Down
10 changes: 5 additions & 5 deletions conans/cli/commands/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def graph_compute(args, conan_api, partial=False, allow_error=False):
profile_host, profile_build = get_profiles_from_args(conan_api, args)

out = ConanOutput()
out.highlight("-------- Input profiles ----------")
out.title("Input profiles")
out.info("Profile host:")
out.info(profile_host.dumps())
out.info("Profile build:")
Expand All @@ -85,7 +85,7 @@ def graph_compute(args, conan_api, partial=False, allow_error=False):
tool_requires=tool_requires,
profile_host=profile_host)

out.highlight("-------- Computing dependency graph ----------")
out.title("Computing dependency graph")
check_updates = args.check_updates if "check_updates" in args else False
deps_graph = conan_api.graph.load_graph(root_node, profile_host=profile_host,
profile_build=profile_build,
Expand All @@ -94,7 +94,7 @@ def graph_compute(args, conan_api, partial=False, allow_error=False):
update=args.update,
check_update=check_updates)
print_graph_basic(deps_graph)
out.highlight("\n-------- Computing necessary packages ----------")
out.title("Computing necessary packages")
if deps_graph.error:
if allow_error:
return deps_graph, lockfile
Expand Down Expand Up @@ -166,10 +166,10 @@ def install(conan_api, parser, *args):
deps_graph, lockfile = graph_compute(args, conan_api, partial=args.lockfile_partial)

out = ConanOutput()
out.highlight("\n-------- Installing packages ----------")
out.title("Installing packages")
conan_api.install.install_binaries(deps_graph=deps_graph, remotes=remote, update=args.update)

out.highlight("\n-------- Finalizing install (deploy, generators) ----------")
out.title("Finalizing install (deploy, generators)")
conan_api.install.install_consumer(deps_graph=deps_graph,
generators=args.generator,
output_folder=output_folder,
Expand Down
2 changes: 0 additions & 2 deletions conans/cli/commands/list.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import json
from collections import OrderedDict
from json import JSONEncoder

from conans.cli.command import conan_command, conan_subcommand, Extender, COMMAND_GROUPS
from conans.cli.commands import json_formatter
Expand Down Expand Up @@ -106,7 +105,6 @@ def _add_remotes_and_cache_options(subparser):
help="Remote names. Accepts wildcards")
subparser.add_argument("-c", "--cache", action='store_true', help="Search in the local cache")


def _selected_cache_remotes(conan_api, args):
# If neither remote nor cache are defined, show results only from cache
remotes = []
Expand Down
8 changes: 4 additions & 4 deletions conans/cli/commands/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def test(conan_api, parser, *args):
profile_host, profile_build = get_profiles_from_args(conan_api, args)

out = ConanOutput()
out.highlight("\n-------- Input profiles ----------")
out.title("Input profiles")
out.info("Profile host:")
out.info(profile_host.dumps())
out.info("Profile build:")
Expand All @@ -44,7 +44,7 @@ def test(conan_api, parser, *args):
update=args.update,
lockfile=lockfile)

out.highlight("-------- Computing dependency graph ----------")
out.title("Computing dependency graph")
check_updates = args.check_updates if "check_updates" in args else False
deps_graph = conan_api.graph.load_graph(root_node, profile_host=profile_host,
profile_build=profile_build,
Expand All @@ -53,13 +53,13 @@ def test(conan_api, parser, *args):
update=args.update,
check_update=check_updates)
print_graph_basic(deps_graph)
out.highlight("\n-------- Computing necessary packages ----------")
out.title("Computing necessary packages")
deps_graph.report_graph_error()
conan_api.graph.analyze_binaries(deps_graph, remotes=remotes, update=args.update,
lockfile=lockfile)
print_graph_packages(deps_graph)

out.highlight("\n-------- Installing packages ----------")
out.title("Installing packages")
conan_api.install.install_binaries(deps_graph=deps_graph, remotes=remotes, update=args.update)

save_lockfile_out(args, deps_graph, lockfile, cwd)
Expand Down
2 changes: 1 addition & 1 deletion conans/cli/formatters/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ def print_graph_info(deps_graph, field_filter, package_filter):
Used for 'graph info' command
"""
out = ConanOutput()
out.highlight("\n-------- Basic graph information ----------")
out.title("Basic graph information")
serial = deps_graph.serialize()
for n in serial["nodes"]:
if package_filter is not None:
Expand Down
Loading

0 comments on commit 1d1a973

Please sign in to comment.