Skip to content

Commit 83a3a0a

Browse files
Add timeout to process codebase and plugin steps
Signed-off-by: Ayan Sinha Mahapatra <asmahapatra@aboutcode.org>
1 parent 4e8d711 commit 83a3a0a

2 files changed

Lines changed: 30 additions & 2 deletions

File tree

src/scancode/cli.py

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ class WindowsError(Exception):
6868
from scancode.help import epilog_text
6969
from scancode.help import examples_text
7070
from scancode.interrupt import DEFAULT_TIMEOUT
71+
from scancode.interrupt import DEFAULT_PLUGIN_TIMEOUT
7172
from scancode.interrupt import fake_interruptible
7273
from scancode.interrupt import interruptible
7374
from scancode.pool import ScanCodeTimeoutError
@@ -253,6 +254,14 @@ def default_processes():
253254
f'[default: {DEFAULT_TIMEOUT} seconds]',
254255
help_group=cliutils.CORE_GROUP, sort_order=10, cls=PluggableCommandLineOption)
255256

257+
@click.option('--timeout-plugins',
258+
type=float,
259+
default=DEFAULT_PLUGIN_TIMEOUT,
260+
metavar='<seconds>',
261+
help='Stop an unfinished codebase processing or post-scan plugin after'
262+
f' a timeout in seconds. [default: {DEFAULT_TIMEOUT} seconds]',
263+
help_group=cliutils.CORE_GROUP, sort_order=10, cls=PluggableCommandLineOption)
264+
256265
@click.option('-q', '--quiet',
257266
is_flag=True,
258267
default=False,
@@ -399,6 +408,7 @@ def scancode(
399408
full_root,
400409
processes,
401410
timeout,
411+
timeout_plugins,
402412
quiet,
403413
verbose,
404414
max_depth,
@@ -510,6 +520,7 @@ def scancode(
510520
full_root=full_root,
511521
processes=processes,
512522
timeout=timeout,
523+
timeout_plugins=timeout_plugins,
513524
quiet=quiet,
514525
verbose=verbose,
515526
max_depth=max_depth,
@@ -551,7 +562,8 @@ def run_scan(
551562
full_root=False,
552563
max_in_memory=10000,
553564
processes=1,
554-
timeout=120,
565+
timeout=DEFAULT_TIMEOUT,
566+
timeout_plugins=DEFAULT_PLUGIN_TIMEOUT,
555567
quiet=True,
556568
verbose=False,
557569
max_depth=0,
@@ -659,6 +671,7 @@ def echo_func(*_args, **_kwargs):
659671
full_root=full_root,
660672
processes=processes,
661673
timeout=timeout,
674+
timeout_plugins=timeout_plugins,
662675
quiet=quiet,
663676
verbose=verbose,
664677
from_json=from_json,
@@ -947,6 +960,7 @@ def echo_func(*_args, **_kwargs):
947960
stage='pre-scan',
948961
plugins=pre_scan_plugins,
949962
codebase=codebase,
963+
timeout=timeout_plugins,
950964
stage_msg='Run %(stage)ss...',
951965
plugin_msg=' Run %(stage)s: %(name)s...',
952966
quiet=quiet,
@@ -966,6 +980,7 @@ def echo_func(*_args, **_kwargs):
966980
codebase=codebase,
967981
processes=processes,
968982
timeout=timeout,
983+
timeout_plugins=timeout_plugins,
969984
timing=timeout,
970985
quiet=quiet,
971986
verbose=verbose,
@@ -983,6 +998,7 @@ def echo_func(*_args, **_kwargs):
983998
stage='post-scan',
984999
plugins=post_scan_plugins,
9851000
codebase=codebase,
1001+
timeout=timeout_plugins,
9861002
stage_msg='Run %(stage)ss...',
9871003
plugin_msg=' Run %(stage)s: %(name)s...',
9881004
quiet=quiet,
@@ -1001,6 +1017,7 @@ def echo_func(*_args, **_kwargs):
10011017
stage='output-filter',
10021018
plugins=output_filter_plugins,
10031019
codebase=codebase,
1020+
timeout=timeout_plugins,
10041021
stage_msg='Apply %(stage)ss...',
10051022
plugin_msg=' Apply %(stage)s: %(name)s...',
10061023
quiet=quiet,
@@ -1035,6 +1052,7 @@ def echo_func(*_args, **_kwargs):
10351052
stage='output',
10361053
plugins=output_plugins,
10371054
codebase=codebase,
1055+
timeout=timeout_plugins,
10381056
stage_msg='Save scan results...',
10391057
plugin_msg=' Save scan results as: %(name)s...',
10401058
quiet=quiet,
@@ -1095,6 +1113,7 @@ def run_codebase_plugins(
10951113
stage,
10961114
plugins,
10971115
codebase,
1116+
timeout,
10981117
stage_msg='',
10991118
plugin_msg='',
11001119
quiet=False,
@@ -1119,6 +1138,7 @@ def run_codebase_plugins(
11191138
# Sort plugins by run_order, from low to high
11201139
sorted_plugins = sorted(plugins, key=lambda x: x.run_order)
11211140

1141+
scan_errors = []
11221142
success = True
11231143
# TODO: add progress indicator
11241144
for plugin in sorted_plugins:
@@ -1135,7 +1155,11 @@ def run_codebase_plugins(
11351155
logger_debug(pformat(sorted(kwargs.items())))
11361156
logger_debug()
11371157

1138-
plugin.process_codebase(codebase, **kwargs)
1158+
process_codebase_func = partial(plugin.process_codebase, codebase, **kwargs)
1159+
error, _value = interruptible(process_codebase_func, timeout=timeout)
1160+
if error:
1161+
msg = 'ERROR: for scanner: ' + plugin.name + ':\n' + error
1162+
codebase.errors.append(msg)
11391163

11401164
except Exception as _e:
11411165
msg = 'ERROR: failed to run %(stage)s plugin: %(name)s:' % locals()
@@ -1158,6 +1182,7 @@ def run_scanners(
11581182
codebase,
11591183
processes,
11601184
timeout,
1185+
timeout_plugins,
11611186
timing,
11621187
quiet=False,
11631188
verbose=False,
@@ -1208,8 +1233,10 @@ def run_scanners(
12081233

12091234
# TODO: add progress indicator
12101235
# run the process codebase of each scan plugin (most often a no-op)
1236+
use_threading = processes >= 0
12111237
scan_process_codebase_success = run_codebase_plugins(
12121238
stage, plugins, codebase,
1239+
timeout=timeout_plugins,
12131240
stage_msg='Filter %(stage)ss...',
12141241
plugin_msg=' Filter %(stage)s: %(name)s...',
12151242
quiet=quiet, verbose=verbose, kwargs=kwargs,

src/scancode/interrupt.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ class TimeoutError(Exception): # NOQA
4545

4646

4747
DEFAULT_TIMEOUT = 120 # seconds
48+
DEFAULT_PLUGIN_TIMEOUT = 2400 # seconds
4849

4950
TIMEOUT_MSG = 'ERROR: Processing interrupted: timeout after %(timeout)d seconds.'
5051
ERROR_MSG = 'ERROR: Unknown error:\n'

0 commit comments

Comments
 (0)