these are scripts accessing modules remote secnodes as in frappy cli includes a fix in frappy.client.interactive to be able to specify the name space Change-Id: Icaed2b24fa331584a33f0ef276917c894bae9e23
124 lines
4.3 KiB
Python
124 lines
4.3 KiB
Python
# *****************************************************************************
|
|
# This program is free software; you can redistribute it and/or modify it under
|
|
# the terms of the GNU General Public License as published by the Free Software
|
|
# Foundation; either version 2 of the License, or (at your option) any later
|
|
# version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
# details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License along with
|
|
# this program; if not, write to the Free Software Foundation, Inc.,
|
|
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
#
|
|
# Module authors:
|
|
# Markus Zolliker <markus.zolliker@psi.ch>
|
|
# *****************************************************************************
|
|
|
|
import threading
|
|
from pathlib import Path
|
|
from frappy.core import Drivable, Property, Parameter, Command, StringType, \
|
|
IDLE, BUSY, WARN, ERROR
|
|
from frappy.errors import IsBusyError
|
|
from frappy.client.interactive import run_script, ClientEnvironment
|
|
from frappy.lib import formatExtendedTraceback
|
|
|
|
|
|
class ScriptThread(threading.Thread):
|
|
exc = None
|
|
|
|
def __init__(self, completer, *args):
|
|
super().__init__()
|
|
self.completer = completer
|
|
self.args = args
|
|
self.clenv = ClientEnvironment()
|
|
self.clenv.init()
|
|
|
|
def run(self):
|
|
try:
|
|
run_script(*self.args, clenv=self.clenv)
|
|
except BaseException as e:
|
|
# print(formatExtendedTraceback())
|
|
print(e)
|
|
self.exc = e
|
|
finally:
|
|
self.completer()
|
|
|
|
def stop(self):
|
|
self.clenv.trigger.shutdown()
|
|
|
|
|
|
class Scripts(Drivable):
|
|
scriptdir = Property('directory of scripts used as commands', StringType())
|
|
secnodes = Parameter('remote nodes, space separated', StringType(), readonly=False, default='')
|
|
target = Parameter('script to start', StringType(), readonly=False, default='')
|
|
value = Parameter(datatype=StringType(), default='')
|
|
_status = IDLE, ''
|
|
_thread = None
|
|
_script = ''
|
|
|
|
def __new__(cls, modname, logger, cfgdict, dispatcher):
|
|
scriptdir = cfgdict['scriptdir']['value']
|
|
scripts = Path(scriptdir).expanduser().glob('*.py')
|
|
attrs = {}
|
|
for script in scripts:
|
|
name = script.stem
|
|
print(name, script)
|
|
|
|
def cmdwrapper(self, target=name):
|
|
self.write_target(target)
|
|
|
|
attrs[name] = Command(description=f'script {name}')(cmdwrapper)
|
|
return super().__new__(type(f'Script_{modname}', (cls,), attrs))
|
|
|
|
def _start_script(self, script):
|
|
if self.isBusy():
|
|
raise IsBusyError('can not start a script while running')
|
|
self._script = script
|
|
self._thread = ScriptThread(self.read_status, str(script), *self.secnodes.split())
|
|
self._thread.start()
|
|
|
|
def read_status(self):
|
|
if self._thread is None:
|
|
return IDLE, ''
|
|
if self._thread.is_alive():
|
|
if self._stopping:
|
|
return BUSY, f'stopping {self.target}'
|
|
self.value = f'{self.target} running'
|
|
return BUSY, self.value
|
|
if self._stopping:
|
|
self.value = f'{self.target} stopped'
|
|
return WARN, self.value
|
|
if self._thread.exc is None:
|
|
self.value = f'{self.target} finished'
|
|
return IDLE, self.value
|
|
return ERROR, f'raised in {self.target}: {self._thread.exc!r}'
|
|
|
|
def write_target(self, script):
|
|
"""start script given as target"""
|
|
self._start_script(Path(self.scriptdir).expanduser() / f'{script}.py')
|
|
self._stopping = False
|
|
self.value = f'{script} started'
|
|
self.status = BUSY, self.value
|
|
self.setFastPoll(True)
|
|
|
|
@Command()
|
|
def stop(self):
|
|
"""interrupt script
|
|
|
|
a script can only be stopped during setting a parameter,
|
|
when starting a command or when waiting
|
|
"""
|
|
if self._thread:
|
|
self._stopping = True
|
|
self._thread.stop()
|
|
self.read_status()
|
|
|
|
@Command()
|
|
def reset(self):
|
|
"""clear error status"""
|
|
self._thread = None
|
|
self._stopping = False
|
|
self.read_status() |