22
33import ast
44import asyncio
5+ import os
6+ import sys
57import weakref
68from abc import ABC , abstractmethod
79from collections import OrderedDict
1416 Coroutine ,
1517 Dict ,
1618 List ,
19+ Mapping ,
1720 Optional ,
1821 Tuple ,
1922 cast ,
2023 final ,
2124)
2225
26+ from robotcode .language_server .robotframework .utils .robot_path import find_file_ex
27+
28+ from ..utils .version import get_robot_version
29+
2330from ....utils .async_tools import Lock , async_tasking_event , create_sub_task
2431from ....utils .logging import LoggingDescriptor
2532from ....utils .path import path_is_relative_to
3845
3946from ..utils .process_pool import get_process_pool
4047from .library_doc import (
48+ ROBOT_LIBRARY_PACKAGE ,
4149 ArgumentSpec ,
4250 CompleteResult ,
4351 Error ,
5563 get_library_doc ,
5664 get_variables_doc ,
5765 is_embedded_keyword ,
66+ is_library_by_path ,
67+ is_variables_by_path ,
5868 resolve_variable ,
5969)
6070
@@ -453,13 +463,11 @@ async def get_libdoc(self) -> VariablesDoc:
453463class ImportsManager :
454464 _logger = LoggingDescriptor ()
455465
456- def __init__ (
457- self , parent_protocol : RobotLanguageServerProtocol , folder : Uri , config : Optional [RobotConfig ]
458- ) -> None :
466+ def __init__ (self , parent_protocol : RobotLanguageServerProtocol , folder : Uri , config : RobotConfig ) -> None :
459467 super ().__init__ ()
460468 self .parent_protocol = parent_protocol
461469 self .folder = folder
462- self .config = config
470+ self .config : RobotConfig = config
463471 self ._libaries_lock = Lock ()
464472 self ._libaries : OrderedDict [_LibrariesEntryKey , _LibrariesEntry ] = OrderedDict ()
465473 self ._resources_lock = Lock ()
@@ -471,6 +479,34 @@ def __init__(
471479 self ._command_line_variables : Optional [List [VariableDefinition ]] = None
472480
473481 self .process_pool = get_process_pool ()
482+ self ._python_path : Optional [List [str ]] = None
483+ self ._environment : Optional [Mapping [str , str ]] = None
484+
485+ @property
486+ def environment (self ) -> Mapping [str , str ]:
487+ if self ._environment is None :
488+ self ._environment = dict (os .environ )
489+
490+ self ._environment .update (self .config .env )
491+
492+ return self ._environment
493+
494+ @property
495+ def python_path (self ) -> List [str ]:
496+ if self ._python_path is None :
497+ self ._python_path = sys .path
498+
499+ file = Path (__file__ ).resolve ()
500+ top = file .parents [3 ]
501+ for p in filter (lambda v : path_is_relative_to (v , top ), sys .path .copy ()):
502+ self ._python_path .remove (p )
503+
504+ for p in self .config .python_path :
505+ absolute_path = str (Path (p ).absolute ())
506+ if absolute_path not in self ._python_path :
507+ self ._python_path .insert (0 , absolute_path )
508+
509+ return self ._python_path or []
474510
475511 @_logger .call
476512 def get_command_line_variables (self ) -> List [VariableDefinition ]:
@@ -621,37 +657,67 @@ async def remove(k: _VariablesEntryKey, e: _VariablesEntry) -> None:
621657
622658 @_logger .call
623659 async def find_library (self , name : str , base_dir : str , variables : Optional [Dict [str , Any ]] = None ) -> str :
624- return await asyncio .wait_for (
625- asyncio .get_running_loop ().run_in_executor (
626- self .process_pool ,
627- find_library ,
628- name ,
629- str (self .folder .to_path ()),
630- base_dir ,
631- self .config .python_path if self .config is not None else None ,
632- self .config .env if self .config is not None else None ,
633- self .config .variables if self .config is not None else None ,
634- variables ,
635- ),
636- FIND_FILE_TIME_OUT ,
637- )
660+ from robot .variables .search import contains_variable
661+
662+ from robot .libraries import STDLIBS
663+
664+ if contains_variable (name , "$@&%" ):
665+ return await asyncio .wait_for (
666+ asyncio .get_running_loop ().run_in_executor (
667+ self .process_pool ,
668+ find_library ,
669+ name ,
670+ str (self .folder .to_path ()),
671+ base_dir ,
672+ self .config .python_path if self .config is not None else None ,
673+ self .config .env if self .config is not None else None ,
674+ self .config .variables if self .config is not None else None ,
675+ variables ,
676+ ),
677+ FIND_FILE_TIME_OUT ,
678+ )
679+
680+ if name in STDLIBS :
681+ result = ROBOT_LIBRARY_PACKAGE + "." + name
682+ else :
683+ result = name
684+
685+ if is_library_by_path (result ):
686+ result = find_file_ex (result , base_dir , self .python_path , "Library" )
687+
688+ return result
638689
639690 @_logger .call
640691 async def find_variables (self , name : str , base_dir : str , variables : Optional [Dict [str , Any ]] = None ) -> str :
641- return await asyncio .wait_for (
642- asyncio .get_running_loop ().run_in_executor (
643- self .process_pool ,
644- find_variables ,
645- name ,
646- str (self .folder .to_path ()),
647- base_dir ,
648- self .config .python_path if self .config is not None else None ,
649- self .config .env if self .config is not None else None ,
650- self .config .variables if self .config is not None else None ,
651- variables ,
652- ),
653- FIND_FILE_TIME_OUT ,
654- )
692+ from robot .variables .search import contains_variable
693+
694+ # if contains_variable(name, "$@&%"):
695+ # name = name.replace("%{CI_PROJECT_DIR}", self.environment["CI_PROJECT_DIR"])
696+
697+ if contains_variable (name , "$@&%" ):
698+ return await asyncio .wait_for (
699+ asyncio .get_running_loop ().run_in_executor (
700+ self .process_pool ,
701+ find_variables ,
702+ name ,
703+ str (self .folder .to_path ()),
704+ base_dir ,
705+ self .config .python_path if self .config is not None else None ,
706+ self .config .env if self .config is not None else None ,
707+ self .config .variables if self .config is not None else None ,
708+ variables ,
709+ ),
710+ FIND_FILE_TIME_OUT ,
711+ )
712+
713+ if get_robot_version () >= (5 , 0 ):
714+
715+ if is_variables_by_path (name ):
716+ return str (find_file_ex (name , base_dir , self .python_path , "Library" ))
717+
718+ return name
719+
720+ return str (find_file_ex (name , base_dir , self .python_path , "Library" ))
655721
656722 @_logger .call
657723 async def get_libdoc_for_library_import (
@@ -662,7 +728,6 @@ async def get_libdoc_for_library_import(
662728 sentinel : Any = None ,
663729 variables : Optional [Dict [str , Any ]] = None ,
664730 ) -> LibraryDoc :
665-
666731 source = await self .find_library (
667732 name ,
668733 base_dir ,
@@ -872,32 +937,38 @@ async def _get_libdoc() -> VariablesDoc:
872937 return await entry .get_libdoc ()
873938
874939 @_logger .call
875- async def find_file (
940+ async def find_resource (
876941 self , name : str , base_dir : str , file_type : str = "Resource" , variables : Optional [Dict [str , Any ]] = None
877942 ) -> str :
878- result = await asyncio .wait_for (
879- asyncio .get_running_loop ().run_in_executor (
880- self .process_pool ,
881- find_file ,
882- name ,
883- str (self .folder .to_path ()),
884- base_dir ,
885- self .config .python_path if self .config is not None else None ,
886- self .config .env if self .config is not None else None ,
887- self .config .variables if self .config is not None else None ,
888- variables ,
889- file_type ,
890- ),
891- FIND_FILE_TIME_OUT ,
892- )
943+ from robot .variables .search import contains_variable
893944
894- return result
945+ # if contains_variable(name, "$@&%"):
946+ # name = name.replace("%{CI_PROJECT_DIR}", self.environment["CI_PROJECT_DIR"])
947+
948+ if contains_variable (name , "$@&%" ):
949+ return await asyncio .wait_for (
950+ asyncio .get_running_loop ().run_in_executor (
951+ self .process_pool ,
952+ find_file ,
953+ name ,
954+ str (self .folder .to_path ()),
955+ base_dir ,
956+ self .config .python_path if self .config is not None else None ,
957+ self .config .env if self .config is not None else None ,
958+ self .config .variables if self .config is not None else None ,
959+ variables ,
960+ file_type ,
961+ ),
962+ FIND_FILE_TIME_OUT ,
963+ )
964+
965+ return str (find_file_ex (name , base_dir , self .python_path , file_type ))
895966
896967 @_logger .call
897968 async def _get_entry_for_resource_import (
898969 self , name : str , base_dir : str , sentinel : Any = None , variables : Optional [Dict [str , Any ]] = None
899970 ) -> _ResourcesEntry :
900- source = await self .find_file (name , base_dir , variables = variables )
971+ source = await self .find_resource (name , base_dir , variables = variables )
901972
902973 async def _get_document () -> TextDocument :
903974 self ._logger .debug (lambda : f"Load resource { name } from source { source } " )
0 commit comments