def start_backend(self): retval = True if self.is_local_hsdev: Logging.log('Starting local \'hsdev\' server', Logging.LOG_INFO) use_log_level = (self.version >= [0, 2, 3, 2]) log_config = Settings.PLUGIN.hsdev_log_config log_level = Settings.PLUGIN.hsdev_log_level cmd = self.concat_args([(True, ["hsdev"]), (True, ["run"]), (self.port, ["--port", str(self.port)]), (self.cache, ["--cache", self.cache]), (self.log_file, ["--log", self.log_file]), (not use_log_level and log_config, ["--log-config", log_config]), (use_log_level, ["--log-level", log_level])]) hsdev_proc = ProcHelper.exec_with_wrapper(self.exec_with, self.install_dir, cmd) if hsdev_proc.process is not None: # Use TextIOWrapper here because it combines decoding with newline handling, # which means less to maintain. hsdev_proc.process.stdout = io.TextIOWrapper(hsdev_proc.process.stdout, 'utf-8') hsdev_proc.process.stderr = io.TextIOWrapper(hsdev_proc.process.stderr, 'utf-8') # Read and wait for hsdev's startup messge. 15 seconds should be enough time for the message to appear. # Otherwise, kill the thread because we don't want to get stuck waiting forever. startup_reader = HsDevStartupReader(hsdev_proc.process.stdout) startup_reader.start() startup_reader.wait_startup(15.0) if startup_reader.successful(): port = startup_reader.port() if port != self.port: Logging.log('hsdev: server port changed, was {0}, now {1}'.format(self.port, port), Logging.LOG_WARNING) self.port = port self.drain_stdout = OutputCollector.DescriptorDrain('hsdev stdout', hsdev_proc.process.stdout) self.drain_stderr = OutputCollector.DescriptorDrain('hsdev stderr', hsdev_proc.process.stderr) self.drain_stdout.start() self.drain_stderr.start() self.hsdev_process = hsdev_proc Logging.log('Local \'hsdev\' server started successfully.', Logging.LOG_INFO) else: # This is a bit of a "Hail Mary!" because readline() could just hang forever. Just to make sure, # kill the process too! startup_reader.stop() hsdev_proc.process.kill() if hsdev_proc.process_err is not None: Logging.log('Possible reason for timeout: {0}'.format(hsdev_proc.process_err)) self.hsdev_process = None retval = False sublime.error_message('Timed out waiting for \'hsdev\' to start up.') else: errmsg = 'Could not start local \'hsdev\' server because:\n\n' + hsdev_proc.process_err sublime.error_message(errmsg) self.hsdev_process = None retval = False return retval
def run(self): cmd = concat_args([(True, ["hsdev", "run"]), (self.port, ["--port", str(self.port)]), (self.cache, ["--cache", self.cache]), (self.log_file, ["--log", self.log_file]), (self.log_config, ["--log-config", self.log_config])]) Logging.log('hsdev command: {0}'.format(cmd), Logging.LOG_DEBUG) while True: self.create_event.wait() self.create_event.clear() while not self.stop_event.is_set(): Logging.log('Starting hsdev server', Logging.LOG_INFO) hsdev_proc = ProcHelper.ProcHelper(cmd) if hsdev_proc.process is None: Logging.log('Failed to create hsdev process', Logging.LOG_ERROR) return None # Use TextIOWrapper here because it combines decoding with newline handling, # which means less to maintain. hsdev_proc.process.stdout = io.TextIOWrapper(hsdev_proc.process.stdout, 'utf-8') hsdev_proc.process.stderr = io.TextIOWrapper(hsdev_proc.process.stderr, 'utf-8') while True: srvout = hsdev_proc.process.stdout.readline().strip() Logging.log('hsdev initial output: {0}'.format(srvout), Logging.LOG_DEBUG) start_confirm = re.match(r'^.*?hsdev> Server started at port (?P<port>\d+)$', srvout) if start_confirm: Logging.log('hsdev server started at port {0}'.format(start_confirm.group('port'))) break self.process = hsdev_proc.process self.drain_stdout = OutputCollector.DescriptorDrain('hsdev stdout', self.process.stdout) self.drain_stderr = OutputCollector.DescriptorDrain('hsdev stderr', self.process.stderr) self.drain_stdout.start() self.drain_stderr.start() HsCallback.call_callback(self.on_start, name='HsDevProcess.on_start') self.process.wait() self.drain_stdout.stop() self.drain_stderr.stop() HsCallback.call_callback(self.on_exit, name='HsDevProcess.on_exit') self.stop_event.clear()
def __init__(self, project, project_dir, opt_args): if debug_any(): print('Starting \'ghc-mod\' for project {0}'.format(project)) self.ghcmod = None self.action_lock = None self.stderr_drain = None self.cmd = [] self.diag_prefix = 'ghc-mod: project ' + project win = sublime.active_window() msg = 'Error and diagnostic output from ' + self.diag_prefix banner = '~' * len(msg) self.output_panel = Common.output_panel( win, panel_name=self.diag_prefix, text='\n'.join([banner, msg, banner, '', ''])) panel_settings = self.output_panel.settings() panel_settings.set("auto_indent", False) panel_settings.set("smart_indent", False) # if self.exec_with is not None: # if self.exec_with == 'cabal': # cmd += ['cabal'] # elif self.exec_with == 'stack': # cmd += ['stack'] self.cmd += ['ghc-mod'] # if self.exec_with is not None: # cmd += ['--'] self.cmd += [ '-b', '\\n', '--line-prefix', self.GHCMOD_OUTPUT_MARKER + ',' + self.GHCMOD_ERROR_MARKER ] self.cmd += opt_args self.cmd += ['legacy-interactive'] if debug_any(): print('ghc-mod command: {0}'.format(self.cmd)) self.ghcmod = ProcHelper.ProcHelper(self.cmd, cwd=project_dir) if self.ghcmod.process is not None: self.ghcmod.process.stdin = io.TextIOWrapper( self.ghcmod.process.stdin, 'utf-8') self.ghcmod.process.stdout = io.TextIOWrapper( self.ghcmod.process.stdout, 'utf-8') self.action_lock = threading.Lock() self.stderr_drain = OutputCollector.DescriptorDrain( self.diag_prefix, self.ghcmod.process.stderr) self.stderr_drain.start() else: Logging.log('Did not start ghc-mod ({0}) successfully.'.format( self.diag_prefix))
def admin(cmds, wait=False, **popen_kwargs): if not Settings.PLUGIN.enable_hdevtools: return None hdevtools_socket = Settings.PLUGIN.hdevtools_socket if hdevtools_socket: cmds.append('--socket={0}'.format(hdevtools_socket)) command = ["hdevtools", "admin"] + cmds try: if wait: exit_code, stdout, stderr = ProcHelper.ProcHelper.run_process( command, **popen_kwargs) return stdout if exit_code == 0 else 'error running {0}: {1}'.format( command, stderr) else: proc = ProcHelper.ProcHelper(command, **popen_kwargs) OutputCollector.DescriptorDrain('hdevtools stdout', proc.process.stdout).start() OutputCollector.DescriptorDrain('hdevtools stderr', proc.process.stderr).start() return '' except OSError as os_exc: if os_exc.errno == errno.ENOENT: show_hdevtools_error_and_disable() Settings.PLUGIN.enable_hdevtools = False return None except Exception: Logging.log( 'hdevtools.admin failed with exception, see console window traceback' ) traceback.print_exc() return None
def __init__(self, project, project_dir, opt_args): Logging.log('Starting \'ghc-mod\' for project {0}'.format(project), Logging.LOG_INFO) self.ghcmod = None self.action_lock = None self.stderr_drain = None self.cmd = [] self.diag_prefix = 'ghc-mod ' + project # if self.exec_with is not None: # if self.exec_with == 'cabal': # cmd += ['cabal'] # elif self.exec_with == 'stack': # cmd += ['stack'] self.cmd += ['ghc-mod'] # if self.exec_with is not None: # cmd += ['--'] self.cmd += [ '-b', '\\n', '--line-prefix', self.GHCMOD_OUTPUT_MARKER + ',' + self.GHCMOD_ERROR_MARKER ] self.cmd += opt_args self.cmd += ['legacy-interactive'] Logging.log('ghc-mod command: {0}'.format(self.cmd), Logging.LOG_DEBUG) self.ghcmod = ProcHelper.ProcHelper(self.cmd, cwd=project_dir) if self.ghcmod.process is not None: self.ghcmod.process.stdin = io.TextIOWrapper( self.ghcmod.process.stdin, 'utf-8') self.ghcmod.process.stdout = io.TextIOWrapper( self.ghcmod.process.stdout, 'utf-8') self.action_lock = threading.Lock() self.stderr_drain = OutputCollector.DescriptorDrain( self.diag_prefix, self.ghcmod.process.stderr) self.stderr_drain.start() else: Logging.log('Did not start ghc-mod successfully.')
def run(self): new_simple_log = patch_simple_log(self.version) cmd = concat_args([ (True, ["hsdev", "run"]), (self.port, ["--port", str(self.port)]), (self.cache, ["--cache", self.cache]), (self.log_file, ["--log", self.log_file]), # HACK! HACK! HACK! Alexandr changed simple-log's command line API. # # "--log-config" only applies to earlier hsdev versions that support 'log politics' (and for those # of us old enough to remember the Soviet era, 'log politics' is an incredibly Soviet notion that # makes us smile! :-) # # Versions 0.2.3.0 and later: Simplified argument -- just the log level, and only one log level, # Yvgeny! (With apologies to "The Hunt for Red October".) (not new_simple_log and self.log_config, ["--log-config", self.log_config]), (new_simple_log and self.log_config, ["--log-level", self.log_config]) ]) Logging.log('hsdev command: {0}'.format(cmd), Logging.LOG_DEBUG) while True: self.create_event.wait() self.create_event.clear() while not self.stop_event.is_set(): Logging.log('Starting hsdev server', Logging.LOG_INFO) hsdev_proc = ProcHelper.ProcHelper(cmd) if hsdev_proc.process is None: Logging.log('Failed to create hsdev process', Logging.LOG_ERROR) return # Use TextIOWrapper here because it combines decoding with newline handling, # which means less to maintain. hsdev_proc.process.stdout = io.TextIOWrapper( hsdev_proc.process.stdout, 'utf-8') hsdev_proc.process.stderr = io.TextIOWrapper( hsdev_proc.process.stderr, 'utf-8') while True: srvout = hsdev_proc.process.stdout.readline().strip() if srvout != '': Logging.log('hsdev initial output: {0}'.format(srvout), Logging.LOG_DEBUG) start_confirm = re.search( r'[Ss]erver started at port (?P<port>\d+)$', srvout) if start_confirm: Logging.log( 'hsdev server started at port {0}'.format( start_confirm.group('port'))) break else: Logging.log( 'hsdev initial output: Got EOF. Server not started successfully.' ) return self.process = hsdev_proc.process self.drain_stdout = OutputCollector.DescriptorDrain( 'hsdev stdout', self.process.stdout) self.drain_stderr = OutputCollector.DescriptorDrain( 'hsdev stderr', self.process.stderr) self.drain_stdout.start() self.drain_stderr.start() HsCallback.call_callback(self.on_start, name='HsDevProcess.on_start') self.process.wait() self.drain_stdout.stop() self.drain_stderr.stop() HsCallback.call_callback(self.on_exit, name='HsDevProcess.on_exit') self.stop_event.clear()