Skip to content

Commit 56f53ee

Browse files
authored
Merge pull request #971 from GitGuardian/agateau/ui-refactor
Refactor how we print progress
2 parents c135c97 + d27cbf3 commit 56f53ee

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+623
-355
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
### Fixed
2+
3+
- When using the `--debug` option, the log output no longer overlaps with the progress bars.

ggshield/__main__.py

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,14 @@
2222
from ggshield.cmd.status import status_cmd
2323
from ggshield.cmd.utils.common_options import add_common_options
2424
from ggshield.cmd.utils.context_obj import ContextObj
25-
from ggshield.cmd.utils.debug_logs import disable_logs, setup_debug_logs
26-
from ggshield.core import check_updates
25+
from ggshield.cmd.utils.debug import setup_debug_mode
26+
from ggshield.core import check_updates, ui
2727
from ggshield.core.cache import Cache
2828
from ggshield.core.config import Config
2929
from ggshield.core.env_utils import load_dot_env
3030
from ggshield.core.errors import ExitCode
31-
from ggshield.core.text_utils import display_warning
32-
from ggshield.core.ui.plain_text.plain_text_ggshield_ui import PlainTextGGShieldUI
33-
from ggshield.core.ui.rich.rich_ggshield_ui import RichGGShieldUI
31+
from ggshield.core.ui import log_utils
32+
from ggshield.core.ui.rich import RichGGShieldUI
3433
from ggshield.utils.click import RealPath
3534
from ggshield.utils.os import getenv_bool
3635

@@ -66,10 +65,6 @@ def config_path_callback(
6665
if not ctx.obj:
6766
ctx.obj = ContextObj()
6867
ctx.obj.cache = Cache()
69-
if sys.stderr.isatty():
70-
ctx.obj.ui = RichGGShieldUI()
71-
else:
72-
ctx.obj.ui = PlainTextGGShieldUI()
7368

7469
ctx.obj.config = Config(value)
7570
return value
@@ -112,8 +107,8 @@ def cli(
112107
_set_color(ctx)
113108

114109
if config.user_config.debug:
115-
# if `debug` is set in the configuration file, then setup logs now.
116-
setup_debug_logs(filename=None)
110+
# if `debug` is set in the configuration file, then setup debug mode now.
111+
setup_debug_mode()
117112

118113

119114
def _set_color(ctx: click.Context):
@@ -144,7 +139,7 @@ def _set_color(ctx: click.Context):
144139

145140
def _display_deprecation_message(cfg: Config) -> None:
146141
for message in cfg.user_config.deprecation_messages:
147-
display_warning(message)
142+
ui.display_warning(message)
148143

149144

150145
def _check_for_updates(check_for_updates: bool) -> None:
@@ -154,7 +149,7 @@ def _check_for_updates(check_for_updates: bool) -> None:
154149
if check_for_updates and "PYTEST_CURRENT_TEST" not in os.environ:
155150
latest_version = check_updates.check_for_updates()
156151
if latest_version:
157-
display_warning(
152+
ui.display_warning(
158153
f"A new version of ggshield (v{latest_version}) has been released "
159154
f"(https://github.com/GitGuardian/ggshield)."
160155
)
@@ -185,7 +180,10 @@ def main(args: Optional[List[str]] = None) -> Any:
185180
# See https://pyinstaller.org/en/latest/common-issues-and-pitfalls.html#multi-processing
186181
multiprocessing.freeze_support()
187182

188-
disable_logs()
183+
log_utils.disable_logs()
184+
if sys.stderr.isatty():
185+
ui.set_ui(RichGGShieldUI())
186+
189187
show_crash_log = getenv_bool("GITGUARDIAN_CRASH_LOG")
190188
return cli.main(args, prog_name="ggshield", standalone_mode=not show_crash_log)
191189

ggshield/cmd/hmsl/check.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
json_option,
1616
text_json_format_option,
1717
)
18-
from ggshield.core.text_utils import display_info
18+
from ggshield.core import ui
1919
from ggshield.verticals.hmsl.collection import (
2020
InputType,
2121
NamingStrategy,
@@ -51,13 +51,13 @@ def check_cmd(
5151
"""
5252

5353
# Collect secrets
54-
display_info("Collecting secrets...")
54+
ui.display_info("Collecting secrets...")
5555
input = cast(TextIO, click.open_file(path, "r"))
5656
secrets = list(collect(input, input_type))
5757
# full_hashes is True because we need the hashes to decrypt the secrets.
5858
# They will correctly be truncated by our client later.
5959
prepared_data = prepare(secrets, naming_strategy, full_hashes=True)
60-
display_info(f"Collected {len(prepared_data.payload)} secrets.")
60+
ui.display_info(f"Collected {len(prepared_data.payload)} secrets.")
6161

6262
check_secrets(
6363
ctx=ctx,

ggshield/cmd/hmsl/check_secret_manager/hashicorp_vault.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@
1414
text_json_format_option,
1515
)
1616
from ggshield.cmd.utils.context_obj import ContextObj
17+
from ggshield.core import ui
1718
from ggshield.core.errors import UnexpectedError
18-
from ggshield.core.text_utils import display_error, display_info, pluralize
19+
from ggshield.core.text_utils import pluralize
1920
from ggshield.verticals.hmsl.collection import NamingStrategy, collect_list, prepare
2021
from ggshield.verticals.hmsl.secret_manager.hashicorp_vault.api_client import (
2122
VaultAPIClient,
@@ -140,7 +141,7 @@ def check_hashicorp_vault_cmd(
140141
"that your token has access to it."
141142
)
142143

143-
display_info("Fetching secrets from Vault...")
144+
ui.display_info("Fetching secrets from Vault...")
144145
try:
145146
result = vault_client.get_secrets(mount, secret_path, recursive)
146147
# catch this error here if the path provided is a file that we don't have access to
@@ -151,16 +152,16 @@ def check_hashicorp_vault_cmd(
151152
)
152153

153154
if len(result.not_fetched_paths) > 0:
154-
display_error(
155+
ui.display_error(
155156
f"Could not fetch {len(result.not_fetched_paths)} paths. "
156157
"Make sure your token has access to all the secrets in your vault."
157158
)
158159
config = ContextObj.get(ctx).config
159160
if config.user_config.verbose:
160-
display_error("> The following paths could not be fetched:")
161+
ui.display_error("> The following paths could not be fetched:")
161162
for path in result.not_fetched_paths:
162-
display_error(f"- {path}")
163-
display_info(
163+
ui.display_error(f"- {path}")
164+
ui.display_info(
164165
f"Got {len(result.secrets)} {pluralize('secret', len(result.secrets))}."
165166
)
166167

ggshield/cmd/hmsl/fingerprint.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
naming_strategy_option,
1010
)
1111
from ggshield.cmd.utils.common_options import add_common_options
12-
from ggshield.core.text_utils import display_info
12+
from ggshield.core import ui
1313
from ggshield.verticals.hmsl.collection import (
1414
InputType,
1515
NamingStrategy,
@@ -62,5 +62,5 @@ def fingerprint_cmd(
6262
result = prepare(secrets, naming_strategy, full_hashes=full_hashes)
6363
write_outputs(result, prefix)
6464

65-
display_info(f"Prepared {len(secrets)} secrets.")
65+
ui.display_info(f"Prepared {len(secrets)} secrets.")
6666
return 0

ggshield/cmd/hmsl/hmsl_utils.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44
from requests import HTTPError
55

66
from ggshield.cmd.utils.context_obj import ContextObj
7+
from ggshield.core import ui
78
from ggshield.core.errors import UnexpectedError
8-
from ggshield.core.text_utils import display_info, pluralize
9+
from ggshield.core.text_utils import pluralize
910
from ggshield.verticals.hmsl import Secret, get_client
1011
from ggshield.verticals.hmsl.collection import PreparedSecrets
1112
from ggshield.verticals.hmsl.output import show_results
@@ -20,7 +21,7 @@ def check_secrets(
2021
Common code to check secrets and display results for check commands.
2122
"""
2223
# Query the API
23-
display_info("Querying HasMySecretLeaked...")
24+
ui.display_info("Querying HasMySecretLeaked...")
2425
ctx_obj = ContextObj.get(ctx)
2526
client = get_client(ctx_obj.config, hmsl_command_path=ctx.command_path)
2627
found: Iterable[Secret] = []
@@ -29,7 +30,7 @@ def check_secrets(
2930
found = list(client.check(prepared_secrets.payload, full_hashes=full_hashes))
3031
except (ValueError, HTTPError) as exception:
3132
error = exception
32-
display_info(
33+
ui.display_info(
3334
f"{client.quota.remaining} {pluralize('credit', client.quota.remaining)} left for today."
3435
)
3536

ggshield/cmd/hmsl/query.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@
99
from ggshield.cmd.hmsl.hmsl_common_options import input_arg
1010
from ggshield.cmd.utils.common_options import add_common_options
1111
from ggshield.cmd.utils.context_obj import ContextObj
12+
from ggshield.core import ui
1213
from ggshield.core.errors import ParseError, UnexpectedError
13-
from ggshield.core.text_utils import display_info, pluralize
14+
from ggshield.core.text_utils import pluralize
1415
from ggshield.verticals.hmsl import HASH_REGEX, PREFIX_REGEX, get_client
1516

1617

@@ -50,10 +51,10 @@ def query_cmd(
5051
except (ValueError, HTTPError) as error:
5152
raise UnexpectedError(str(error))
5253

53-
display_info(
54+
ui.display_info(
5455
f"{client.quota.remaining} {pluralize('credit', client.quota.remaining)} left for today."
5556
)
56-
display_info(f"Queried {len(payload)} {pluralize('secret', len(payload))}.")
57+
ui.display_info(f"Queried {len(payload)} {pluralize('secret', len(payload))}.")
5758
return 0
5859

5960

ggshield/cmd/honeytoken/create.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ def create_cmd(
7474
if not name:
7575
name = generate_random_honeytoken_name()
7676
ctx_obj = ContextObj.get(ctx)
77-
client = create_client_from_config(ctx_obj.config, ctx_obj.ui)
77+
client = create_client_from_config(ctx_obj.config)
7878

7979
response = client.create_honeytoken(name, type_, description)
8080
if not isinstance(response, (Detail, HoneytokenResponse)):

ggshield/cmd/honeytoken/create_with_context.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ def create_with_context_cmd(
9999
if not name:
100100
name = generate_random_honeytoken_name()
101101
ctx_obj = ContextObj.get(ctx)
102-
client = create_client_from_config(ctx_obj.config, ctx_obj.ui)
102+
client = create_client_from_config(ctx_obj.config)
103103

104104
response = client.create_honeytoken_with_context(
105105
name=name,

ggshield/cmd/iac/scan/__init__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
from ggshield.cmd.iac.scan.prereceive import scan_pre_receive_cmd
1212
from ggshield.cmd.utils.common_options import directory_argument
1313
from ggshield.cmd.utils.context_obj import ContextObj
14+
from ggshield.core import ui
1415
from ggshield.core.client import create_client_from_config
15-
from ggshield.core.text_utils import display_warning
1616
from ggshield.utils.click import DefaultCommandGroup
1717

1818

@@ -47,7 +47,7 @@ def iac_scan_group(
4747
@click.pass_context
4848
def default_command(ctx: click.Context, **kwargs: Any) -> int:
4949
"""Deprecated. Use `ggshield iac scan all` instead"""
50-
display_warning("Deprecated. Please use 'ggshield iac scan all' instead")
50+
ui.display_warning("Deprecated. Please use 'ggshield iac scan all' instead")
5151
result: int = scan_all_cmd.invoke(ctx)
5252
return result
5353

@@ -59,6 +59,6 @@ def scan_group_impl(ctx: click.Context) -> int:
5959
scan_all_cmd.invoke(ctx)
6060

6161
ctx_obj = ContextObj.get(ctx)
62-
ctx_obj.client = create_client_from_config(ctx_obj.config, ctx_obj.ui)
62+
ctx_obj.client = create_client_from_config(ctx_obj.config)
6363

6464
return 0

0 commit comments

Comments
 (0)