Skip to content

Commit

Permalink
refactor: move ScannerUI outside of core.ui
Browse files Browse the repository at this point in the history
This fixes import loop errors when trying to import Commit.
  • Loading branch information
agateau-gg committed Feb 4, 2025
1 parent ddd988f commit b6469b6
Show file tree
Hide file tree
Showing 17 changed files with 56 additions and 58 deletions.
3 changes: 2 additions & 1 deletion ggshield/cmd/secret/scan/archive.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from ggshield.core.errors import UnexpectedError
from ggshield.core.scan import ScanContext, ScanMode
from ggshield.core.scan.file import create_files_from_paths
from ggshield.core.scanner_ui import create_scanner_ui
from ggshield.utils.archive import safe_unpack
from ggshield.utils.click import RealPath
from ggshield.utils.files import ListFilesMode
Expand Down Expand Up @@ -54,7 +55,7 @@ def archive_cmd(
print_file_list(files, binary_paths)
ui.display_heading("Starting scan")

with ui.create_scanner_ui(len(files)) as scanner_ui:
with create_scanner_ui(len(files)) as scanner_ui:
scan_context = ScanContext(
scan_mode=ScanMode.ARCHIVE,
command_path=ctx.command_path,
Expand Down
3 changes: 2 additions & 1 deletion ggshield/cmd/secret/scan/docset.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from ggshield.core import ui
from ggshield.core.client import create_client_from_config
from ggshield.core.scan import ScanContext, ScanMode, Scannable, StringScannable
from ggshield.core.scanner_ui import create_message_only_scanner_ui
from ggshield.core.ui.ggshield_ui import GGShieldProgress
from ggshield.verticals.secret import SecretScanCollection, SecretScanner

Expand All @@ -34,7 +35,7 @@ def create_scans_from_docset_files(
ui.display_verbose(f"- {click.format_filename(input_file.name)}")

files = generate_files_from_docsets(input_file)
with ui.create_message_only_scanner_ui() as scanner_ui:
with create_message_only_scanner_ui() as scanner_ui:

Check warning on line 38 in ggshield/cmd/secret/scan/docset.py

View check run for this annotation

Codecov / codecov/patch

ggshield/cmd/secret/scan/docset.py#L38

Added line #L38 was not covered by tests
results = scanner.scan(files, scanner_ui=scanner_ui)
scans.append(
SecretScanCollection(id=input_file.name, type="docset", results=results)
Expand Down
3 changes: 2 additions & 1 deletion ggshield/cmd/secret/scan/path.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from ggshield.core.client import create_client_from_config
from ggshield.core.scan import ScanContext, ScanMode, Scannable
from ggshield.core.scan.file import create_files_from_paths
from ggshield.core.scanner_ui import create_scanner_ui
from ggshield.utils.click import RealPath
from ggshield.utils.files import ListFilesMode
from ggshield.verticals.secret import SecretScanCollection, SecretScanner
Expand Down Expand Up @@ -71,7 +72,7 @@ def path_cmd(
ui.display_heading("Starting scan")
target = paths[0] if len(paths) == 1 else Path.cwd()
target_path = target if target.is_dir() else target.parent
with ui.create_scanner_ui(len(files)) as scanner_ui:
with create_scanner_ui(len(files)) as scanner_ui:
scan_context = ScanContext(
scan_mode=ScanMode.PATH,
command_path=ctx.command_path,
Expand Down
3 changes: 2 additions & 1 deletion ggshield/cmd/secret/scan/precommit.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from ggshield.core import ui
from ggshield.core.client import create_client_from_config
from ggshield.core.scan import Commit, ScanContext, ScanMode
from ggshield.core.scanner_ui import create_scanner_ui
from ggshield.utils.git_shell import check_git_dir, git
from ggshield.verticals.secret import SecretScanCollection, SecretScanner
from ggshield.verticals.secret.output import SecretTextOutputHandler
Expand Down Expand Up @@ -95,7 +96,7 @@ def precommit_cmd(
scan_context=scan_context,
secret_config=config.user_config.secret,
)
with ui.create_scanner_ui(len(commit.urls)) as scanner_ui:
with create_scanner_ui(len(commit.urls)) as scanner_ui:
results = scanner.scan(commit.get_files(), scanner_ui)

return_code = output_handler.process_scan(
Expand Down
3 changes: 2 additions & 1 deletion ggshield/cmd/secret/scan/pypi.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from ggshield.core.errors import UnexpectedError
from ggshield.core.scan import ScanContext, ScanMode, Scannable
from ggshield.core.scan.file import create_files_from_paths
from ggshield.core.scanner_ui import create_scanner_ui
from ggshield.utils.archive import safe_unpack
from ggshield.utils.files import ListFilesMode
from ggshield.verticals.secret import SecretScanCollection, SecretScanner
Expand Down Expand Up @@ -113,7 +114,7 @@ def pypi_cmd(
print_file_list(files, binary_paths)
ui.display_heading("Starting scan")

with ui.create_scanner_ui(len(files)) as scanner_ui:
with create_scanner_ui(len(files)) as scanner_ui:
scan_context = ScanContext(
scan_mode=ScanMode.PYPI,
command_path=ctx.command_path,
Expand Down
33 changes: 33 additions & 0 deletions ggshield/core/scanner_ui/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from ggshield.core.scanner_ui.plain_text_scanner_ui import PlainTextScannerUI
from ggshield.core.scanner_ui.rich_scanner_ui import (
RichMessageOnlyScannerUI,
RichProgressScannerUI,
)
from ggshield.core.ui import get_ui
from ggshield.core.ui.rich import RichGGShieldUI

from .scanner_ui import ScannerUI


def create_scanner_ui(total: int) -> ScannerUI:
"""
Creates a ScannerUI instance. This is used to show progress on scanning
Scannables.
"""
if isinstance(get_ui(), RichGGShieldUI):
return RichProgressScannerUI(get_ui(), total)

Check warning on line 18 in ggshield/core/scanner_ui/__init__.py

View check run for this annotation

Codecov / codecov/patch

ggshield/core/scanner_ui/__init__.py#L18

Added line #L18 was not covered by tests
else:
return PlainTextScannerUI()


def create_message_only_scanner_ui():
"""
Creates a ScannerUI instance without a progress bar. This is used when the scan
itself is part of a larger scan. For example when scanning a commit range, each
commit gets a message-only ScannerUI. Progress of the commit range scan is
represented by a progress bar created using `create_progress()`.
"""
if isinstance(get_ui(), RichGGShieldUI):
return RichMessageOnlyScannerUI(get_ui())

Check warning on line 31 in ggshield/core/scanner_ui/__init__.py

View check run for this annotation

Codecov / codecov/patch

ggshield/core/scanner_ui/__init__.py#L31

Added line #L31 was not covered by tests
else:
return PlainTextScannerUI()
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from ggshield.core import ui
from ggshield.core.scan import Scannable
from ggshield.core.ui.scanner_ui import ScannerUI
from ggshield.core.scanner_ui.scanner_ui import ScannerUI


class PlainTextScannerUI(ScannerUI):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
from typing_extensions import Self

from ggshield.core.scan import Scannable
from ggshield.core.scanner_ui.scanner_ui import ScannerUI
from ggshield.core.ui.ggshield_ui import GGShieldUI
from ggshield.core.ui.scanner_ui import ScannerUI


class RichMessageOnlyScannerUI(ScannerUI):
Expand Down
File renamed without changes.
13 changes: 4 additions & 9 deletions ggshield/core/ui/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@

from .ggshield_ui import GGShieldProgress, GGShieldUI, Level
from .plain_text import PlainTextGGShieldUI
from .scanner_ui import ScannerUI


# GGShieldUI instance to which top-level functions forward their output.
Expand Down Expand Up @@ -49,6 +48,10 @@ def set_ui(ui: GGShieldUI) -> None:
_ui = ui


def get_ui() -> GGShieldUI:
return _ui


def display_debug(message: str) -> None:
_ui.display_debug(message)

Expand Down Expand Up @@ -81,14 +84,6 @@ def create_progress(total: int) -> GGShieldProgress:
return _ui.create_progress(total)


def create_scanner_ui(total: int) -> ScannerUI:
return _ui.create_scanner_ui(total)


def create_message_only_scanner_ui() -> ScannerUI:
return _ui.create_message_only_scanner_ui()


def _reset_ui():
"""Reset the module to its startup state. Used by reset.reset()."""
global _ui
Expand Down
20 changes: 0 additions & 20 deletions ggshield/core/ui/ggshield_ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@

from typing_extensions import Self

from .scanner_ui import ScannerUI


class Level(IntEnum):
ERROR = auto()
Expand Down Expand Up @@ -56,24 +54,6 @@ class GGShieldUI(ABC):
def __init__(self):
self.level = Level.INFO

@abstractmethod
def create_scanner_ui(self, total: int) -> ScannerUI:
"""
Creates a ScannerUI instance. This is used to show progress on scanning
Scannables.
"""
...

@abstractmethod
def create_message_only_scanner_ui(self) -> ScannerUI:
"""
Creates a ScannerUI instance without a progress bar. This is used when the scan
itself is part of a larger scan. For example when scanning a commit range, each
commit gets a message-only ScannerUI. Progress of the commit range scan is
represented by a progress bar created using `create_progress()`.
"""
...

@abstractmethod
def create_progress(self, total: int) -> GGShieldProgress:
"""
Expand Down
8 changes: 0 additions & 8 deletions ggshield/core/ui/plain_text/plain_text_ggshield_ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
GGShieldUI,
Level,
)
from ggshield.core.ui.plain_text.plain_text_scanner_ui import PlainTextScannerUI
from ggshield.core.ui.scanner_ui import ScannerUI


class PlainTextGGShieldProgress(GGShieldProgress):
Expand Down Expand Up @@ -59,12 +57,6 @@ def log(self, record: logging.LogRecord) -> None:
self.display_warning(f"Unsupported log level {level}")
self.display_error(msg)

def create_scanner_ui(self, total: int) -> ScannerUI:
return PlainTextScannerUI()

def create_message_only_scanner_ui(self) -> ScannerUI:
return PlainTextScannerUI()

def create_progress(self, total: int) -> GGShieldProgress:
return PlainTextGGShieldProgress()

Expand Down
9 changes: 0 additions & 9 deletions ggshield/core/ui/rich/rich_ggshield_ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@
from rich.progress import BarColumn, Progress, TaskProgressColumn, TextColumn
from typing_extensions import Self

from ggshield.core.ui.scanner_ui import ScannerUI

from ..ggshield_ui import NAME_BY_LEVEL, DebugInfo, GGShieldProgress, GGShieldUI, Level
from .rich_scanner_ui import RichMessageOnlyScannerUI, RichProgressScannerUI


COLOR_BY_LEVEL = {
Expand Down Expand Up @@ -63,12 +60,6 @@ def __init__(self):
self.console = Console(file=sys.stderr)
self._previous_timestamp = ""

def create_scanner_ui(self, total: int) -> ScannerUI:
return RichProgressScannerUI(self, total)

def create_message_only_scanner_ui(self) -> ScannerUI:
return RichMessageOnlyScannerUI(self)

def create_progress(self, total: int) -> GGShieldProgress:
return RichGGShieldProgress(self.console, total)

Expand Down
5 changes: 3 additions & 2 deletions ggshield/verticals/secret/docker.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from ggshield.core.errors import UnexpectedError
from ggshield.core.scan import ScanContext, Scannable, StringScannable
from ggshield.core.scan.id_cache import IDCache
from ggshield.core.scanner_ui import create_scanner_ui
from ggshield.utils.files import is_path_binary

from .secret_scan_collection import SecretScanCollection
Expand Down Expand Up @@ -340,7 +341,7 @@ def docker_scan_archive(

with DockerImage.open(archive_path) as docker_image:
ui.display_heading("Scanning Docker config")
with ui.create_scanner_ui(1) as scanner_ui:
with create_scanner_ui(1) as scanner_ui:
results = scanner.scan(
[docker_image.config_scannable], scanner_ui=scanner_ui
)
Expand All @@ -356,7 +357,7 @@ def docker_scan_archive(
ui.display_heading(f"Skipping layer {layer_id}: already scanned")
else:
ui.display_heading(f"Scanning layer {info.diff_id}")
with ui.create_scanner_ui(file_count) as scanner_ui:
with create_scanner_ui(file_count) as scanner_ui:
layer_results = scanner.scan(files, scanner_ui=scanner_ui)
if not layer_results.has_secrets:
layer_id_cache.add(layer_id)
Expand Down
3 changes: 2 additions & 1 deletion ggshield/verticals/secret/repo.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from ggshield.core.constants import MAX_WORKERS
from ggshield.core.errors import ExitCode, QuotaLimitReachedError, handle_exception
from ggshield.core.scan import Commit, ScanContext
from ggshield.core.scanner_ui import create_message_only_scanner_ui
from ggshield.core.text_utils import STYLE, format_text
from ggshield.utils.git_shell import get_list_commit_SHA, is_git_dir
from ggshield.utils.os import cd
Expand Down Expand Up @@ -78,7 +79,7 @@ def scan_commits_content(
check_api_key=False, # Key has been checked in `scan_commit_range()`
secret_config=secret_config,
)
with ui.create_message_only_scanner_ui() as scanner_ui:
with create_message_only_scanner_ui() as scanner_ui:
results = scanner.scan(
commit_files, scan_threads=SCAN_THREADS, scanner_ui=scanner_ui
)
Expand Down
2 changes: 1 addition & 1 deletion ggshield/verticals/secret/secret_scanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
from ggshield.core.constants import MAX_WORKERS
from ggshield.core.errors import MissingScopesError, UnexpectedError, handle_api_error
from ggshield.core.scan import DecodeError, ScanContext, Scannable
from ggshield.core.scanner_ui.scanner_ui import ScannerUI
from ggshield.core.text_utils import pluralize
from ggshield.core.ui.scanner_ui import ScannerUI

from .secret_scan_collection import Error, Result, Results

Expand Down
2 changes: 1 addition & 1 deletion tests/unit/verticals/secret/test_secret_scanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
Scannable,
StringScannable,
)
from ggshield.core.ui.scanner_ui import ScannerUI
from ggshield.core.scanner_ui.scanner_ui import ScannerUI
from ggshield.utils.git_shell import Filemode
from ggshield.utils.os import get_os_info
from ggshield.verticals.secret import SecretScanner
Expand Down

0 comments on commit b6469b6

Please sign in to comment.