1111from .stack_meter import StackMeter
1212
1313
14+ try :
15+ from package_control .package_manager import PackageManager
16+
17+ def is_dependency (pkg_name ):
18+ return PackageManager ()._is_dependency (pkg_name )
19+
20+ except ImportError :
21+ def is_dependency (pkg_name ):
22+ return False
23+
24+
1425def dprint (* args , fill = None , fill_width = 60 , ** kwargs ):
1526 if fill is not None :
1627 sep = str (kwargs .get ('sep' , ' ' ))
1728 caption = sep .join (args )
1829 args = "{0:{fill}<{width}}" .format (caption and caption + sep ,
1930 fill = fill , width = fill_width ),
20- print ("[UnitTesting]" , * args , ** kwargs )
31+ print ("[Package Reloader]" , * args , ** kwargs )
32+
33+
34+ def path_contains (a , b ):
35+ return a == b or b .startswith (a + os .sep )
36+
37+
38+ def get_package_modules (pkg_name ):
39+ in_installed_path = functools .partial (
40+ path_contains ,
41+ os .path .join (
42+ sublime .installed_packages_path (),
43+ pkg_name + '.sublime-package'
44+ )
45+ )
46+
47+ in_package_path = functools .partial (
48+ path_contains ,
49+ os .path .join (sublime .packages_path (), pkg_name )
50+ )
51+
52+ def module_in_package (module ):
53+ file = getattr (module , '__file__' , '' )
54+ paths = getattr (module , '__path__' , ())
55+ return (
56+ in_installed_path (file ) or any (map (in_installed_path , paths )) or
57+ in_package_path (file ) or any (map (in_package_path , paths ))
58+ )
59+
60+ return {
61+ name : module
62+ for name , module in sys .modules .items ()
63+ if module_in_package (module )
64+ }
2165
2266
2367# check the link for comments
2468# https://github.com/divmain/GitSavvy/blob/599ba3cdb539875568a96a53fafb033b01708a67/common/util/reload.py
2569def reload_package (pkg_name , dummy = True , verbose = True ):
70+ if is_dependency (pkg_name ):
71+ reload_dependency (pkg_name , dummy , verbose )
72+ return
73+
2674 if pkg_name not in sys .modules :
2775 dprint ("error:" , pkg_name , "is not loaded." )
2876 return
2977
30- main = sys .modules [pkg_name ]
31-
3278 if verbose :
3379 dprint ("begin" , fill = '=' )
3480
35- modules = {main .__name__ : main }
36- modules .update ({name : module for name , module in sys .modules .items ()
37- if name .startswith (pkg_name + "." )})
81+ modules = get_package_modules (pkg_name )
82+
3883 for m in modules :
3984 if m in sys .modules :
4085 sublime_plugin .unload_module (modules [m ])
@@ -44,7 +89,7 @@ def reload_package(pkg_name, dummy=True, verbose=True):
4489 with intercepting_imports (modules , verbose ), \
4590 importing_fromlist_aggresively (modules ):
4691
47- reload_plugin (main . __name__ )
92+ reload_plugin (pkg_name )
4893 except Exception :
4994 dprint ("reload failed." , fill = '-' )
5095 reload_missing (modules , verbose )
@@ -57,6 +102,27 @@ def reload_package(pkg_name, dummy=True, verbose=True):
57102 dprint ("end" , fill = '-' )
58103
59104
105+ def reload_dependency (dependency_name , dummy = True , verbose = True ):
106+ """
107+ Package Control dependencies aren't regular packages, so we don't want to
108+ call `sublime_plugin.unload_module` or `sublime_plugin.reload_plugin`.
109+ Instead, we manually unload all of the modules in the dependency and then
110+ `reload_package` any packages that use that dependency. (We have to manually
111+ unload the dependency's modules because calling `reload_package` on a
112+ dependent module will not unload the dependency.)
113+ """
114+ for name in get_package_modules (dependency_name ):
115+ del sys .modules [name ]
116+
117+ manager = PackageManager ()
118+ for package in manager .list_packages ():
119+ if dependency_name in manager .get_dependencies (package ):
120+ reload_package (package , dummy = False , verbose = verbose )
121+
122+ if dummy :
123+ load_dummy (verbose )
124+
125+
60126def load_dummy (verbose ):
61127 """
62128 Hack to trigger automatic "reloading plugins".
@@ -67,20 +133,25 @@ def load_dummy(verbose):
67133 dprint ("installing dummy package" )
68134 dummy = "_dummy_package"
69135 dummy_py = os .path .join (sublime .packages_path (), "%s.py" % dummy )
70- open (dummy_py , "w" ).close ()
136+ with open (dummy_py , "w" ):
137+ pass
71138
72139 def remove_dummy (trial = 0 ):
73140 if dummy in sys .modules :
74141 if verbose :
75142 dprint ("removing dummy package" )
76- if os . path . exists ( dummy_py ) :
143+ try :
77144 os .unlink (dummy_py )
145+ except FileNotFoundError :
146+ pass
78147 after_remove_dummy ()
79148 elif trial < 300 :
80149 threading .Timer (0.1 , lambda : remove_dummy (trial + 1 )).start ()
81150 else :
82- if os . path . exists ( dummy_py ) :
151+ try :
83152 os .unlink (dummy_py )
153+ except FileNotFoundError :
154+ pass
84155
85156 condition = threading .Condition ()
86157
@@ -112,8 +183,8 @@ def reload_missing(modules, verbose):
112183
113184def reload_plugin (pkg_name ):
114185 pkg_path = os .path .join (os .path .realpath (sublime .packages_path ()), pkg_name )
115- plugins = [pkg_name + "." + os .path .splitext (f )[0 ]
116- for f in os .listdir (pkg_path ) if f .endswith (".py" )]
186+ plugins = [pkg_name + "." + os .path .splitext (file_path )[0 ]
187+ for file_path in os .listdir (pkg_path ) if file_path .endswith (".py" )]
117188 for plugin in plugins :
118189 sublime_plugin .reload_plugin (plugin )
119190
0 commit comments