diff --git a/CHANGES.md b/CHANGES.md index 7ab7ec89ca6..e9de89df924 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -71,6 +71,13 @@ from multi-line `script` items in task definitions, for cleaner job scripts. ### Fixes +[#2666](https://github.com/cylc/cylc/pull/2666) - `cylc scan`: fix default +behavior to only obtain suite information from the `~/cylc-run/` of the current +user. This is consistent with `cylc gscan`. However, the `--name=PATTERN` +(`-n PATTERN`) option has also been modified to be consistent with +`cylc gscan`, so `cylc scan --name=bar` will only match the suite `bar` but not +the suites `foobar` and `barbaz`. + [#2593](https://github.com/cylc/cylc/pull/2593) - fix polling after job execution timeout (configured pre-poll delays were being ignored). diff --git a/bin/cylc-scan b/bin/cylc-scan index 5fa2d98ccd2..1c654f838b1 100755 --- a/bin/cylc-scan +++ b/bin/cylc-scan @@ -50,8 +50,8 @@ import re import json from cylc.cfgspec.glbl_cfg import glbl_cfg -from cylc.hostuserutil import get_user -from cylc.network.port_scan import scan_many, get_scan_items_from_fs +from cylc.network.port_scan import ( + get_scan_items_from_fs, re_compile_filters, scan_many) from cylc.option_parsers import CylcOptionParser as COP from cylc.suite_status import ( KEY_DESCRIPTION, KEY_META, KEY_NAME, KEY_OWNER, KEY_STATES, @@ -200,28 +200,18 @@ def main(): else: # Any suite name. patterns_name = ['.*'] + patterns_owner = None if options.patterns_owner: patterns_owner = options.patterns_owner - else: - # Just the user's suites. - patterns_owner = [get_user()] # Compile and check "name" and "owner" regular expressions - cres = {} - for key, patterns in [ - ('name', patterns_name), ('suite-owner', patterns_owner)]: - try: - cres[key] = re.compile(r'(' + r')|('.join(patterns) + r')') - except re.error: - for pattern in patterns: - try: - re.compile(pattern) - except re.error: - parser.error( - '--%s=%s: bad regular expression' % (key, pattern)) + try: + cre_owner, cre_name = re_compile_filters(patterns_owner, patterns_name) + except ValueError as exc: + parser.error(str(exc)) if options.all_ports: args.extend(glbl_cfg().get(["suite host scanning", "hosts"])) if not args: - args = get_scan_items_from_fs(cres['suite-owner']) + args = get_scan_items_from_fs(cre_owner) if not args: return @@ -231,9 +221,9 @@ def main(): name = suite_identity[KEY_NAME] owner = suite_identity[KEY_OWNER] - if not cres['name'].match(name): + if cre_name and not cre_name.match(name): continue - if not cres['suite-owner'].match(owner): + if cre_owner and not cre_owner.match(owner): continue if options.json_format: json_filter.append([host, port, suite_identity]) diff --git a/lib/cylc/daemonize.py b/lib/cylc/daemonize.py index 279798b44b4..b2418a54328 100644 --- a/lib/cylc/daemonize.py +++ b/lib/cylc/daemonize.py @@ -30,7 +30,7 @@ $ cylc get-suite-contact %(suite)s Other ways to see if the suite is still running: - $ cylc scan -n '\b%(suite)s\b' %(host)s + $ cylc scan -n '%(suite)s' %(host)s $ cylc ping -v --host=%(host)s %(suite)s $ ps %(ps_opts)s %(pid)s # on %(host)s diff --git a/lib/cylc/gui/gscan.py b/lib/cylc/gui/gscan.py index 7e651ed514e..5f0076e66de 100644 --- a/lib/cylc/gui/gscan.py +++ b/lib/cylc/gui/gscan.py @@ -35,6 +35,7 @@ KEY_PORT, get_scan_menu, launch_gcylc, update_suites_info, launch_hosts_dialog, launch_about_dialog) from cylc.gui.util import get_icon, setup_icons, set_exception_hook_dialog +from cylc.network.port_scan import re_compile_filters from cylc.suite_status import ( KEY_GROUP, KEY_META, KEY_STATES, KEY_TASKS_BY_STATE, KEY_TITLE, KEY_UPDATE_TIME) @@ -169,21 +170,11 @@ def __init__( self.treeview.connect("button-press-event", self._on_button_press_event) - patterns = {"name": None, "owner": None} - for label, items in [ - ("owner", patterns_owner), ("name", patterns_name)]: - if items: - patterns[label] = r"\A(?:" + r")|(?:".join(items) + r")\Z" - try: - patterns[label] = re.compile(patterns[label]) - except re.error: - raise ValueError("Invalid %s pattern: %s" % (label, items)) + cre_owner, cre_name = re_compile_filters(patterns_owner, patterns_name) self.updater = ScanAppUpdater( self.window, hosts, suite_treemodel, self.treeview, - comms_timeout=comms_timeout, interval=interval, - group_column_id=self.GROUP_COLUMN, - name_pattern=patterns["name"], owner_pattern=patterns["owner"]) + comms_timeout, interval, self.GROUP_COLUMN, cre_owner, cre_name) self.updater.start() @@ -759,7 +750,7 @@ class ScanAppUpdater(threading.Thread): def __init__(self, window, hosts, suite_treemodel, suite_treeview, comms_timeout=None, interval=None, group_column_id=0, - name_pattern=None, owner_pattern=None): + owner_pattern=None, name_pattern=None): self.window = window if hosts: self.hosts = hosts @@ -779,8 +770,8 @@ def __init__(self, window, hosts, suite_treemodel, suite_treeview, self.group_column_id = group_column_id self.tasks_by_state = {} self.warning_times = {} - self.name_pattern = name_pattern self.owner_pattern = owner_pattern + self.name_pattern = name_pattern super(ScanAppUpdater, self).__init__() @staticmethod diff --git a/lib/cylc/network/port_scan.py b/lib/cylc/network/port_scan.py index 3bf66053e7a..733b959b975 100644 --- a/lib/cylc/network/port_scan.py +++ b/lib/cylc/network/port_scan.py @@ -20,6 +20,7 @@ from multiprocessing import cpu_count, Process, Pipe import os from pwd import getpwall +import re import sys from time import sleep, time import traceback @@ -232,6 +233,28 @@ def scan_many(items, timeout=None, updater=None): return results +def re_compile_filters(patterns_owner=None, patterns_name=None): + """Compile regexp for suite owner and suite name scan filters. + + Arguments: + patterns_owner (list): List of suite owner patterns + patterns_name (list): List of suite name patterns + + Returns (tuple): + A 2-element tuple in the form (cre_owner, cre_name). Either or both + element can be None to allow for the default scan behaviour. + """ + cres = {'owner': None, 'name': None} + for label, items in [('owner', patterns_owner), ('name', patterns_name)]: + if items: + cres[label] = r'\A(?:' + r')|(?:'.join(items) + r')\Z' + try: + cres[label] = re.compile(cres[label]) + except re.error: + raise ValueError(r'%s=%s: bad regexp' % (label, items)) + return (cres['owner'], cres['name']) + + def get_scan_items_from_fs(owner_pattern=None, updater=None): """Get list of host:port available to scan using the file system.