edouard@3501: #!/usr/bin/env python edouard@3501: # -*- coding: utf-8 -*- edouard@3501: edouard@3501: import os edouard@3501: import sys edouard@3501: from functools import wraps edouard@3619: from threading import Timer edouard@3619: from datetime import datetime edouard@3501: edouard@3501: import click edouard@3501: edouard@3501: import fake_wx edouard@3501: edouard@3501: from ProjectController import ProjectController edouard@3501: from LocalRuntimeMixin import LocalRuntimeMixin edouard@3619: from runtime.loglevels import LogLevelsCount, LogLevels edouard@3619: edouard@3501: edouard@3501: class Log: edouard@3501: edouard@3501: def __init__(self): edouard@3501: self.crlfpending = False edouard@3501: edouard@3501: def write(self, s): edouard@3501: if s: edouard@3501: if self.crlfpending: edouard@3501: sys.stdout.write("\n") edouard@3501: sys.stdout.write(s) edouard@3548: sys.stdout.flush() edouard@3501: self.crlfpending = 0 edouard@3501: edouard@3501: def write_error(self, s): edouard@3501: if s: edouard@3501: self.write("Error: "+s) edouard@3501: edouard@3501: def write_warning(self, s): edouard@3501: if s: edouard@3501: self.write("Warning: "+s) edouard@3501: edouard@3501: def flush(self): edouard@3501: sys.stdout.flush() edouard@3501: edouard@3501: def isatty(self): edouard@3501: return False edouard@3501: edouard@3501: def progress(self, s): edouard@3501: if s: edouard@3501: sys.stdout.write(s+"\r") edouard@3501: self.crlfpending = True edouard@3501: edouard@3501: edouard@3501: def with_project_loaded(func): edouard@3501: @wraps(func) edouard@3501: def func_wrapper(self, *args, **kwargs): edouard@3501: if not self.HasOpenedProject(): edouard@3501: if self.check_and_load_project(): edouard@3501: return 1 edouard@3501: self.apply_config() edouard@3501: return func(self, *args, **kwargs) edouard@3501: edouard@3501: return func_wrapper edouard@3501: edouard@3501: def connected(func): edouard@3501: @wraps(func) edouard@3501: def func_wrapper(self, *args, **kwargs): edouard@3501: if self._connector is None: edouard@3501: if self.session.uri: edouard@3501: self.BeremizRoot.setURI_location(self.session.uri) edouard@3501: if not self._Connect(): edouard@3501: return 1 edouard@3501: return func(self, *args, **kwargs) edouard@3501: edouard@3501: return func_wrapper edouard@3501: edouard@3501: class CLIController(LocalRuntimeMixin, ProjectController): edouard@3501: def __init__(self, session): edouard@3501: self.session = session edouard@3501: log = Log() edouard@3539: LocalRuntimeMixin.__init__(self, log, use_gui=False) edouard@3501: ProjectController.__init__(self, None, log) edouard@3619: self.CLIStatusTimer = None edouard@3619: self.KillCLIStatusTimer = False edouard@3619: edouard@3619: edouard@3619: def StartCLIStatusTimer(self): edouard@3619: if self.CLIStatusTimer is not None: edouard@3619: return edouard@3619: self.CLIStatusTimer = Timer(0.5, self.CLIStatusTimerProc) edouard@3619: self.KillCLIStatusTimer = False edouard@3619: self.CLIStatusTimer.start() edouard@3619: edouard@3619: def StopCLIStatusTimer(self): edouard@3619: if self.CLIStatusTimer is None: edouard@3619: return edouard@3619: self.KillCLIStatusTimer = True edouard@3619: self.CLIStatusTimer.cancel() edouard@3619: self.CLIStatusTimer = None edouard@3619: edouard@3619: def CLIStatusTimerProc(self): edouard@3619: self.CLIStatusTimer = None edouard@3619: if not self.KillCLIStatusTimer: edouard@3619: self.PullPLCStatusProc(None) edouard@3619: self.StartCLIStatusTimer() edouard@3619: edouard@3619: def _SetConnector(self, connector, update_status=True): edouard@3619: self._connector = connector edouard@3619: self.previous_log_count = [None]*LogLevelsCount edouard@3619: if connector is not None: edouard@3619: self.StartCLIStatusTimer() edouard@3619: else: edouard@3619: self.StopCLIStatusTimer() edouard@3619: if update_status: edouard@3619: self.UpdateMethodsFromPLCStatus() edouard@3619: edouard@3619: def UpdatePLCLog(self, log_count): edouard@3619: connector = self._connector edouard@3619: new_messages = [] edouard@3619: if connector: edouard@3619: for level, count, prev in zip( edouard@3619: xrange(LogLevelsCount), log_count, self.previous_log_count): edouard@3619: if count is not None and prev != count: edouard@3619: if prev is None: edouard@3619: dump_end = max(-1, count - 10) edouard@3619: else: edouard@3619: dump_end = prev - 1 edouard@3619: for msgidx in range(count-1, dump_end, -1): edouard@3619: message = connector.GetLogMessage(level, msgidx) edouard@3619: if message is not None: edouard@3619: msg, _tick, tv_sec, tv_nsec = message edouard@3619: date = datetime.utcfromtimestamp(tv_sec + tv_nsec * 1e-9) edouard@3619: txt = "%s at %s: %s\n" % (LogLevels[level], date.isoformat(' '), msg) edouard@3619: new_messages.append((date,txt)) edouard@3619: else: edouard@3619: break edouard@3619: self.previous_log_count[level] = count edouard@3619: new_messages.sort() edouard@3619: for date, txt in new_messages: edouard@3619: self.logger.write(txt) edouard@3501: edouard@3501: def check_and_load_project(self): edouard@3501: if not os.path.isdir(self.session.project_home): edouard@3501: self.logger.write_error( edouard@3501: _("\"%s\" is not a valid Beremiz project\n") % self.session.project_home) edouard@3501: return True edouard@3501: edouard@3501: errmsg, error = self.LoadProject(self.session.project_home, self.session.buildpath) edouard@3501: if error: edouard@3501: self.logger.write_error(errmsg) edouard@3501: return True edouard@3501: edouard@3501: def apply_config(self): edouard@3501: for k,v in self.session.config: edouard@3501: self.SetParamsAttribute("BeremizRoot."+k, v) edouard@3501: edouard@3501: @with_project_loaded edouard@3501: def build_project(self, target): edouard@3501: edouard@3501: if target: edouard@3501: self.SetParamsAttribute("BeremizRoot.TargetType", target) edouard@3501: edouard@3501: return 0 if self._Build() else 1 edouard@3501: edouard@3501: @with_project_loaded edouard@3501: @connected edouard@3501: def transfer_project(self): edouard@3501: edouard@3501: return 0 if self._Transfer() else 1 edouard@3501: edouard@3501: @with_project_loaded edouard@3501: @connected edouard@3501: def run_project(self): edouard@3501: edouard@3501: return 0 if self._Run() else 1 edouard@3501: edouard@3501: edouard@3501: def finish(self): edouard@3501: edouard@3501: self._Disconnect() edouard@3501: edouard@3501: if not self.session.keep: edouard@3501: self.KillLocalRuntime() edouard@3501: edouard@3501: