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

gscan: Added stop and release menu items #2232

Merged
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions bin/cylc-gscan
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ import gtk
import warnings
warnings.filterwarnings('ignore', 'use the new', Warning)

gtk.settings_get_default().set_long_property(
"gtk-button-images", True, "main")
gtk.settings_get_default().set_long_property(
"gtk-menu-images", True, "main")

from cylc.gui.gscan import ScanApp
from cylc.option_parsers import CylcOptionParser as COP
from cylc.owner import USER
Expand Down
32 changes: 27 additions & 5 deletions lib/cylc/gui/gscan.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,14 +251,36 @@ def _on_button_press_event(self, treeview, event):
path = pth[0]

iter_ = treemodel.get_iter(path)

host, owner, suite = treemodel.get(
iter_, self.HOST_COLUMN, self.OWNER_COLUMN, self.SUITE_COLUMN)
if suite is None:
if suite is not None:
suite_keys.append((host, owner, suite))

elif suite is None:
# On an expanded cycle point row, so get from parent.
host, owner, suite = treemodel.get(
treemodel.iter_parent(iter_),
self.HOST_COLUMN, self.OWNER_COLUMN, self.SUITE_COLUMN)
suite_keys.append((host, owner, suite))
try:
host, owner, suite = treemodel.get(
treemodel.iter_parent(iter_),
self.HOST_COLUMN, self.OWNER_COLUMN, self.SUITE_COLUMN)
suite_keys.append((host, owner, suite))

except:
# Now iterate over the children instead.
# We need to iterate over the children as there can be more
# than one suite in a group of suites.
# Get a TreeIter pointing to the first child of parent iter
suite_iter = treemodel.iter_children(iter_)

# Iterate over the children until you get to end
while suite_iter is not None:
host, owner, suite = treemodel.get(suite_iter,
self.HOST_COLUMN,
self.OWNER_COLUMN,
self.SUITE_COLUMN)
suite_keys.append((host, owner, suite))
# Advance to the next pointer in the treemodel
suite_iter = treemodel.iter_next(suite_iter)

if event.type == gtk.gdk._2BUTTON_PRESS:
if suite_keys:
Expand Down
125 changes: 116 additions & 9 deletions lib/cylc/gui/scanutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ def get_scan_menu(suite_keys,
for host, owner, suite in suite_keys:
gcylc_item = gtk.ImageMenuItem("Launch gcylc: %s - %s@%s" % (
suite.replace('_', '__'), owner, host))
img = gtk.image_new_from_stock("gcylc", gtk.ICON_SIZE_MENU)
gcylc_item.set_image(img)
img_gcylc = gtk.image_new_from_stock("gcylc", gtk.ICON_SIZE_MENU)
gcylc_item.set_image(img_gcylc)
gcylc_item._connect_args = (host, owner, suite)
gcylc_item.connect(
"button-press-event",
Expand All @@ -107,6 +107,59 @@ def get_scan_menu(suite_keys,
sep_item.show()
menu.append(sep_item)

# Construct a cylc stop item to stop a suite
if len(suite_keys) > 1:
stoptask_item = gtk.ImageMenuItem('Stop all')
else:
stoptask_item = gtk.ImageMenuItem('Stop')

img_stop = gtk.image_new_from_stock(gtk.STOCK_MEDIA_STOP,
gtk.ICON_SIZE_MENU)
stoptask_item.set_image(img_stop)
stoptask_item._connect_args = suite_keys, 'stop'
stoptask_item.connect("button-press-event",
lambda b, e: call_cylc_command(b._connect_args[0],
b._connect_args[1]))
stoptask_item.show()
menu.append(stoptask_item)

# Construct a cylc hold item to hold (pause) a suite
if len(suite_keys) > 1:
holdtask_item = gtk.ImageMenuItem('Hold all')
else:
holdtask_item = gtk.ImageMenuItem('Hold')

img_hold = gtk.image_new_from_stock(gtk.STOCK_MEDIA_PAUSE,
gtk.ICON_SIZE_MENU)
holdtask_item.set_image(img_hold)
holdtask_item._connect_args = suite_keys, 'hold'
holdtask_item.connect("button-press-event",
lambda b, e: call_cylc_command(b._connect_args[0],
b._connect_args[1]))
menu.append(holdtask_item)
holdtask_item.show()

# Construct a cylc release item to release a paused/stopped suite
if len(suite_keys) > 1:
unstoptask_item = gtk.ImageMenuItem('Release all')
else:
unstoptask_item = gtk.ImageMenuItem('Release')

img_release = gtk.image_new_from_stock(gtk.STOCK_MEDIA_PLAY,
gtk.ICON_SIZE_MENU)
unstoptask_item.set_image(img_release)
unstoptask_item._connect_args = suite_keys, 'release'
unstoptask_item.connect("button-press-event",
lambda b, e: call_cylc_command(b._connect_args[0],
b._connect_args[1]))
unstoptask_item.show()
menu.append(unstoptask_item)

# Add another separator
sep_item = gtk.SeparatorMenuItem()
sep_item.show()
menu.append(sep_item)

# Construct theme chooser items (same as cylc.gui.app_main).
theme_item = gtk.ImageMenuItem('Theme')
img = gtk.image_new_from_stock(gtk.STOCK_SELECT_COLOR, gtk.ICON_SIZE_MENU)
Expand Down Expand Up @@ -249,12 +302,8 @@ def _launch_hosts_dialog(existing_hosts, change_hosts_func):
dialog.destroy()


def launch_gcylc(key):
"""Launch gcylc for a given suite and host."""
host, owner, suite = key
args = ["--host=" + host, "--user=" + owner, suite]

# Get version of suite
def get_suite_version(args):
"""Gets the suite version given the host, owner, and suite arguments"""
f_null = open(os.devnull, "w")
if cylc.flags.debug:
stderr = sys.stderr
Expand All @@ -266,6 +315,18 @@ def launch_gcylc(key):
suite_version = proc.communicate()[0].strip()
proc.wait()

return suite_version


def launch_gcylc(key):
"""Launch gcylc for a given suite and host."""
host, owner, suite = key
args = ["--host=" + host, "--user=" + owner, suite]

# Get version of suite - now separate method get_suite_version()
f_null = open(os.devnull, "w")
suite_version = get_suite_version(args)

# Run correct version of "cylc gui", provided that "admin/cylc-wrapper" is
# installed.
env = None
Expand All @@ -283,6 +344,52 @@ def launch_gcylc(key):
Popen(["nohup"] + command, env=env, stdout=stdout, stderr=stderr)


def call_cylc_command(keys, command_id):
"""Calls one of the Cylc commands (such as 'stop', 'hold', etc...).

Will accept either a single tuple for a key, or a list of keys.
See the examples below. If you pass it a list of keys, it will
iterate and call the command_id on each suite (key) it is given.

Args:
keys (tuple): The key containing host, owner, and suite
command_id (str): A string giving the Cylc command.

Example:
call_cylc_command(keys, "stop")
call_cylc_command((host, owner, suite), "hold")
call_cylc_command([(host, owner, suite),
(host, owner, suite),
(host, owner, suite)], "hold")
"""

if not isinstance(keys, list):
keys = [keys]

for key in keys:
host, owner, suite = key
args = ["--host=" + host, "--user=" + owner, suite]

# Get version of suite
f_null = open(os.devnull, "w")
suite_version = get_suite_version(args)

env = None
if suite_version != CYLC_VERSION:
env = dict(os.environ)
env["CYLC_VERSION"] = suite_version
command = ["cylc", command_id] + args

if cylc.flags.debug:
stdout = sys.stdout
stderr = sys.stderr
Popen(command, env=env, stdout=stdout, stderr=stderr)
else:
stdout = f_null
stderr = stdout
Popen(["nohup"] + command, env=env, stdout=stdout, stderr=stderr)


def update_suites_info(
hosts=None, timeout=None, owner_pattern=None, name_pattern=None,
prev_results=None):
Expand All @@ -299,7 +406,7 @@ def update_suites_info(
where each "suite_info" is a dict with keys:
KEY_GROUP - group name of suite
KEY_OWNER - suite owner name
KEY_PORT - suite port, for runninig suites only
KEY_PORT - suite port, for running suites only
KEY_STATES - suite state
KEY_STATES:cycle - states by cycle
KEY_TASKS_BY_STATE - tasks by state
Expand Down