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

feat: add entry-points for tools #467

Merged
merged 1 commit into from
Oct 8, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
9 changes: 9 additions & 0 deletions grizzly/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,16 @@


def main(args: Namespace) -> int:
"""CLI for `grizzly`.
Arguments:
args: Result from `GrizzlyArgs.parse_args`.
Returns:
Exit.SUCCESS (0) for success otherwise a different Exit code is returned.
"""
configure_logging(args.log_level)

LOG.info("Starting Grizzly (%d)", getpid())
LOG.debug("grizzly-framework version: %s", package_version("grizzly-framework"))

Expand Down
3 changes: 1 addition & 2 deletions grizzly/reduce/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,5 @@
"""Grizzly reducer CLI.
"""
from . import ReduceManager
from .args import ReduceArgs

raise SystemExit(ReduceManager.main(ReduceArgs().parse_args()))
raise SystemExit(ReduceManager.main())
22 changes: 17 additions & 5 deletions grizzly/reduce/bucket.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from ..replay.bucket import bucket_main
from .args import ReduceFuzzManagerIDQualityArgs
from .crash import main as crash_main

if __name__ == "__main__":
from ..replay.bucket import bucket_main
from .args import ReduceFuzzManagerIDQualityArgs
from .crash import main

raise SystemExit(bucket_main(ReduceFuzzManagerIDQualityArgs().parse_args(), main))
def main() -> int:
"""Wrapper for bucket_main() which is the CLI for `grizzly.reduce.bucket`.

Arguments:
None

Returns:
Exit.SUCCESS (0) for success otherwise a different Exit code is returned.
"""
return bucket_main(ReduceFuzzManagerIDQualityArgs().parse_args(), crash_main)


if __name__ == "__main__":
raise SystemExit(main())
6 changes: 4 additions & 2 deletions grizzly/reduce/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
)
from ..replay import ReplayManager, ReplayResult
from ..target import AssetManager, Target, TargetLaunchError, TargetLaunchTimeout
from .args import ReduceArgs
from .exceptions import GrizzlyReduceBaseException, NotReproducible
from .strategies import STRATEGIES

Expand Down Expand Up @@ -752,16 +753,17 @@ def report(
self._status.last_reports = new_reports

@classmethod
def main(cls, args: Namespace) -> int:
def main(cls, args: Namespace | None = None) -> int:
"""CLI for `grizzly.reduce`.

Arguments:
args: Result from `ReduceArgs.parse_args`.

Returns:
0 for success. non-0 indicates a problem.
Exit.SUCCESS (0) for success otherwise a different Exit code is returned.
"""
# pylint: disable=too-many-return-statements
args = args or ReduceArgs().parse_args()
configure_logging(args.log_level)
setlocale(LC_ALL, "")

Expand Down
14 changes: 10 additions & 4 deletions grizzly/reduce/crash.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from argparse import Namespace
from __future__ import annotations

from logging import getLogger
from typing import TYPE_CHECKING

from ..common.fuzzmanager import load_fm_data
from ..common.reporter import Quality
Expand All @@ -11,18 +13,22 @@
from .args import ReduceFuzzManagerIDArgs
from .core import ReduceManager

if TYPE_CHECKING:
from argparse import Namespace

LOG = getLogger(__name__)


def main(args: Namespace) -> int:
def main(args: Namespace | None = None) -> int:
"""CLI for `grizzly.reduce.crash`.

Arguments:
args: Result from `ReduceArgs.parse_args`.

Returns:
0 for success. non-0 indicates a problem.
Exit.SUCCESS (0) for success otherwise a different Exit code is returned.
"""
args = args or ReduceFuzzManagerIDArgs().parse_args()
configure_logging(args.log_level)
with load_fm_data(args.input, load_bucket=not args.sig) as (crash, bucket):
LOG.info(
Expand Down Expand Up @@ -61,4 +67,4 @@ def main(args: Namespace) -> int:


if __name__ == "__main__":
raise SystemExit(main(ReduceFuzzManagerIDArgs().parse_args()))
raise SystemExit(main())
8 changes: 8 additions & 0 deletions grizzly/reduce/test_main_fm.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

from ..common.reporter import Quality
from ..common.utils import Exit
from .bucket import main as main_wrapper
from .crash import main as crash_main

pytestmark = mark.usefixtures("tmp_path_status_db_reduce")
Expand Down Expand Up @@ -44,3 +45,10 @@ def test_crash_main_quality(mocker, exit_code, pre_quality, post_quality):
# verify testcase quality was updated
assert crash.testcase_quality == post_quality
assert reduce_main.call_args[0][0].sig is None


def test_bucket_main_wrapper_coverage(mocker):
"""test is for coverage of the wrapper function"""
mocker.patch("grizzly.reduce.bucket.bucket_main", return_value=0)
mocker.patch("grizzly.reduce.bucket.ReduceFuzzManagerIDQualityArgs")
assert main_wrapper() == 0
3 changes: 1 addition & 2 deletions grizzly/replay/__main__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from .args import ReplayArgs
from .replay import ReplayManager

raise SystemExit(ReplayManager.main(ReplayArgs().parse_args()))
raise SystemExit(ReplayManager.main())
26 changes: 20 additions & 6 deletions grizzly/replay/bucket.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from argparse import Namespace
from __future__ import annotations

from logging import getLogger
from typing import Callable
from typing import TYPE_CHECKING, Callable

from ..common.fuzzmanager import Bucket
from ..common.utils import Exit, configure_logging
from .args import ReplayFuzzManagerIDQualityArgs
from .crash import main as crash_main

if TYPE_CHECKING:
from argparse import Namespace

LOG = getLogger(__name__)


Expand All @@ -21,7 +25,7 @@ def bucket_main(args: Namespace, tool_main: Callable[[Namespace], int]) -> int:
tool_main: Main function from a supported Grizzly tool.

Returns:
0 for success. non-0 indicates a problem.
Exit.SUCCESS (0) for success otherwise a different Exit code is returned.
"""
assert callable(tool_main)
configure_logging(args.log_level)
Expand Down Expand Up @@ -49,7 +53,17 @@ def bucket_main(args: Namespace, tool_main: Callable[[Namespace], int]) -> int:
return result


def main() -> int:
"""Wrapper for bucket_main() which is the CLI for `grizzly.replay.bucket`.

Arguments:
None

Returns:
Exit.SUCCESS (0) for success otherwise a different Exit code is returned.
"""
return bucket_main(ReplayFuzzManagerIDQualityArgs().parse_args(), crash_main)


if __name__ == "__main__":
raise SystemExit(
bucket_main(ReplayFuzzManagerIDQualityArgs().parse_args(), crash_main)
)
raise SystemExit(main())
20 changes: 13 additions & 7 deletions grizzly/replay/bugzilla.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,37 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from argparse import Namespace
from __future__ import annotations

from logging import getLogger
from typing import TYPE_CHECKING

from ..common.bugzilla import BugzillaBug
from ..common.utils import configure_logging
from ..common.utils import Exit, configure_logging
from .args import ReplayFuzzBugzillaArgs
from .replay import ReplayManager

if TYPE_CHECKING:
from argparse import Namespace

LOG = getLogger(__name__)


def main(args: Namespace) -> int:
def main(args: Namespace | None = None) -> int:
"""CLI for `grizzly.replay.bugzilla`.

Arguments:
args: Result from `ReplayArgs.parse_args`.

Returns:
0 for success. non-0 indicates a problem.
Exit.SUCCESS (0) for success otherwise a different Exit code is returned.
"""
args = args or ReplayFuzzBugzillaArgs().parse_args()
configure_logging(args.log_level)
bug = BugzillaBug.load(args.input)
if bug is None:
LOG.info("Failed to load Bug %d from Bugzilla", args.input)
return 1
return Exit.ERROR
LOG.info("Loaded Bug %d from Bugzilla", args.input)
with bug:
args.asset.extend(
Expand All @@ -35,10 +41,10 @@ def main(args: Namespace) -> int:
testcases = bug.testcases()
if not testcases:
LOG.error("No test case data attached to bug %d", args.input)
return 1
return Exit.ERROR
args.input = testcases
return ReplayManager.main(args)


if __name__ == "__main__":
raise SystemExit(main(ReplayFuzzBugzillaArgs().parse_args()))
raise SystemExit(main())
11 changes: 6 additions & 5 deletions grizzly/replay/crash.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,16 @@
LOG = getLogger(__name__)


def main(args: Namespace) -> int:
def main(args: Namespace | None = None) -> int:
"""CLI for `grizzly.replay.crash`.

Arguments:
args: Result from `ReplayArgs.parse_args`.
args: Result from `ReplayFuzzManagerIDArgs.parse_args`.

Returns:
0 for success. non-0 indicates a problem.
Exit.SUCCESS (0) for success otherwise a different Exit code is returned.
"""
args = args or ReplayFuzzManagerIDArgs().parse_args()
configure_logging(args.log_level)
with load_fm_data(args.input, load_bucket=not args.sig) as (crash, bucket):
LOG.info("Loaded crash %d from FuzzManager", crash.crash_id)
Expand All @@ -38,7 +39,7 @@ def modify_args(args: Namespace, crash: CrashEntry, bucket: Bucket | None) -> Na
"""

Arguments:
args: Result from `ReplayArgs.parse_args`.
args: Result from `ReplayFuzzManagerIDArgs.parse_args`.
crash: Crash entry to process.
bucket: Bucket that contains crash.

Expand Down Expand Up @@ -77,4 +78,4 @@ def modify_args(args: Namespace, crash: CrashEntry, bucket: Bucket | None) -> Na


if __name__ == "__main__":
raise SystemExit(main(ReplayFuzzManagerIDArgs().parse_args()))
raise SystemExit(main())
13 changes: 12 additions & 1 deletion grizzly/replay/replay.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
TargetLaunchError,
TargetLaunchTimeout,
)
from .args import ReplayArgs

if TYPE_CHECKING:
from argparse import Namespace
Expand Down Expand Up @@ -600,8 +601,18 @@ def harness_fn(_: str) -> bytes: # pragma: no cover
result.report.cleanup()

@classmethod
def main(cls, args: Namespace) -> int:
def main(cls, args: Namespace | None = None) -> int:
"""CLI for `grizzly.reduce`.

Arguments:
args: Result from `ReplayArgs.parse_args`.

Returns:
Exit.SUCCESS (0) for success otherwise a different Exit code is returned.
"""
args = args or ReplayArgs().parse_args()
configure_logging(args.log_level)

LOG.info("Starting Grizzly Replay")
LOG.debug("grizzly-framework version: %s", package_version("grizzly-framework"))

Expand Down
8 changes: 8 additions & 0 deletions grizzly/replay/test_main_fm.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from ..common.fuzzmanager import Bucket, CrashEntry
from ..common.utils import Exit
from .bucket import bucket_main
from .bucket import main as main_wrapper
from .crash import main as crash_main
from .crash import modify_args

Expand Down Expand Up @@ -133,3 +134,10 @@ def copy_args(args):
assert call_args[idx].sig == arg_sig
else:
assert call_args[idx].sig == "test_sig.json"


def test_bucket_main_wrapper_coverage(mocker):
"""test is for coverage of the wrapper function"""
mocker.patch("grizzly.replay.bucket.bucket_main", return_value=0)
mocker.patch("grizzly.replay.bucket.ReplayFuzzManagerIDQualityArgs")
assert main_wrapper() == 0
6 changes: 1 addition & 5 deletions grizzly/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
"""test Grizzly main"""
from pathlib import Path
from platform import system

from pytest import mark, skip
Expand Down Expand Up @@ -86,7 +85,7 @@ def test_main_02(mocker, session_setup, exit_code, to_raise):
session_obj.run.side_effect = TargetLaunchError("test", mocker.Mock())
else:
session_obj.run.side_effect = to_raise()
args = mocker.MagicMock(adapter="fake", binary=Path("bin"), time_limit=1, timeout=1)
args = mocker.MagicMock(adapter="fake", time_limit=1, timeout=1)
assert main(args) == exit_code
assert target_cls.return_value.cleanup.call_count == 1

Expand All @@ -111,7 +110,6 @@ def test_main_03(mocker, session_setup, test_limit, timeout):
# no_harness=False for code coverage
args = mocker.MagicMock(
adapter="fake",
binary=Path("bin"),
no_harness=False,
time_limit=test_limit,
timeout=timeout,
Expand Down Expand Up @@ -142,7 +140,6 @@ def test_main_04(
assert sum((pernosco, rr, valgrind)) < 2, "test broken!"
args = mocker.MagicMock(
adapter="fake",
binary=Path("bin"),
pernosco=pernosco,
rr=rr,
time_limit=1,
Expand All @@ -162,7 +159,6 @@ def test_main_05(mocker, session_setup):
target_cls.return_value.https.return_value = False
args = mocker.MagicMock(
adapter="fake",
binary=Path("bin"),
use_http=False,
time_limit=1,
timeout=1,
Expand Down
10 changes: 9 additions & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,15 @@ zip_safe = False

[options.entry_points]
console_scripts =
grizzly.status = grizzly.common.status_reporter:main
grizzly = grizzly:__main__
grizzly-reduce = grizzly.reduce:__main__
grizzly-reduce-bucket = grizzly.reduce.bucket:main
grizzly-reduce-crash = grizzly.reduce.crash:main
grizzly-replay = grizzly.replay:__main__
grizzly-replay-bucket = grizzly.replay.bucket:main
grizzly-replay-bugzilla = grizzly.replay.bugzilla:main
grizzly-replay-crash = grizzly.replay.crash:main
grizzly-status = grizzly.common.status_reporter:main
grizzly_adapters =
no-op = grizzly.adapter.no_op_adapter:NoOpAdapter
grizzly_targets =
Expand Down
Loading