diff --git a/src/commands/base_indexer.py b/src/commands/base_indexer.py index 5dbdfa3..e319c54 100644 --- a/src/commands/base_indexer.py +++ b/src/commands/base_indexer.py @@ -1,4 +1,6 @@ import os +import re +from typing import List, Tuple import sublime from sublime import Window from ..settings import PyRockSettings @@ -33,28 +35,67 @@ def _get_indexer_script_path(self): def _is_indexing_needed(self) -> bool: file_path = os.path.join(PyRockConstants.INDEX_CACHE_DIRECTORY, PyRockConstants.IMPORT_INDEX_FILE_NAME) return os.path.exists(file_path) - - def _run_import_indexer(self, window: Window, indexer_command: str): - process = subprocess.Popen( - indexer_command, - shell=True, - stdout=subprocess.PIPE, - ) + def _track_indexer_progress(self, window: Window, process: subprocess.Popen) -> bool: start_time = time.perf_counter() - + script_success: bool = False + log_errors: bool = False # Progress tracker for line in iter(process.stdout.readline, ""): - progress = line.decode('utf-8').strip() + output = line.decode('utf-8').strip() # Kill process after 20 sec if (time.perf_counter() - start_time) > 20: - logger.warning(f"Indexing stopped due to timeout at {progress}%") + error_reason = f"Indexing stopped due to timeout at {output}%" + logger.warning(error_reason) + self._command_error_evidence.append(error_reason) process.terminate() + script_success = False break - logger.debug(f"Indexing imports...{progress}%") - window.status_message(f"Indexing imports...{progress}%") - if "99" in str(line) or progress == "": + + if log_errors: + # Collect error generated from script + self._command_error_evidence.append(output) + elif re.match(r"^([1-9]|[1-9][0-9]|100)$", output): + logger.debug(f"Indexing imports...{output}%") + window.status_message(f"Indexing imports...{output}%") + if 95 <= int(output) <= 100: + script_success = True + elif "FAILED_INDEXING" in output: + script_success = False + log_errors = True + + if output == "" or output is None: break + return script_success + + def _collect_cmd_error_output(self, process: subprocess.Popen): + # Collect error generated from command + for line in iter(process.stderr.readline, ""): + output = line.decode('utf-8').strip() + if len(output) == 0 or output == "" or output is None: + break + logger.debug(output) + self._command_error_evidence.append(output) + + def _run_import_indexer(self, window: Window, indexer_command: str) -> Tuple[bool, str]: + process = subprocess.Popen( + indexer_command, + shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + message: str = "" + script_success: bool = self._track_indexer_progress(window, process) + + if not script_success: + if len(self._command_error_evidence) > 0: + logger.error("\n".join(self._command_error_evidence)) + else: + self._collect_cmd_error_output(process) + message = "\n".join(self._command_error_evidence) + logger.error(message) + + return script_success, message def _run_indexer(self, window: Window, force=False): if self._is_indexing_needed() and not force: @@ -62,6 +103,8 @@ def _run_indexer(self, window: Window, force=False): window.status_message("Indexing not needed") return + self._command_error_evidence: List[str] = [] + self._generate_serialized_settings() window.set_status_bar_visible(True) @@ -114,6 +157,10 @@ def _run_indexer(self, window: Window, force=False): ) logger.debug(f"Import shell command using: {import_command}") - self._run_import_indexer(window, import_command) + success, message = self._run_import_indexer(window, import_command) + logger.debug(f"Indexing result: {success}") - window.status_message("Finished imports...") + if success: + window.status_message("Finished imports...") + else: + sublime.error_message(f"Indexing Failed\n\n{message}") diff --git a/src/scripts/indexer.py b/src/scripts/indexer.py index bf35b8d..7a5210b 100644 --- a/src/scripts/indexer.py +++ b/src/scripts/indexer.py @@ -6,6 +6,7 @@ import json from collections import defaultdict import importlib +import traceback from typing import List, Dict, Tuple, Set from types import FunctionType, ModuleType import logging @@ -110,8 +111,8 @@ def _index_sub_module_members( f"{parent_module_name}.{module_name}", self.get_module_members(module_obj) ) - - def run(self): + + def _run(self): self.parse_serialized_settings() system_module_name_list: Set[str] = { @@ -159,5 +160,16 @@ def run(self): self.save_imports_to_cache() + def run(self): + try: + self._run() + except Exception: + # Send error Flag + print("FAILED_INDEXING", flush=True) + error_details = traceback.format_exc() + logger.debug(f"Indexing failed due to: {error_details}") + # Send error details to plugin + print(error_details, flush=True) + if __name__ == '__main__': Indexer().run()