4
4
from loguru import logger
5
5
from pathlib import Path
6
6
from tempfile import TemporaryDirectory
7
- from typing import Optional , List , Union , Dict , Sequence , Any , cast
7
+ from typing import Optional , List , Union , Dict , Sequence
8
8
9
9
from .utils import Spinner
10
10
@@ -56,6 +56,7 @@ def register_web_module(name: str, source: Union[str, Path]) -> str:
56
56
57
57
def delete_web_modules (names : Sequence [str ], skip_missing : bool = False ) -> None :
58
58
paths = []
59
+ cache = Cache (BUILD_DIR )
59
60
for name in _to_list_of_str (names ):
60
61
exists = False
61
62
@@ -78,9 +79,13 @@ def delete_web_modules(names: Sequence[str], skip_missing: bool = False) -> None
78
79
if not exists and not skip_missing :
79
80
raise ValueError (f"Module '{ name } ' does not exist." )
80
81
82
+ cache .delete_package (name )
83
+
81
84
for p in paths :
82
85
_delete_os_paths (p )
83
86
87
+ cache .save ()
88
+
84
89
85
90
def installed () -> List [str ]:
86
91
names : List [str ] = []
@@ -91,56 +96,33 @@ def installed() -> List[str]:
91
96
return list (sorted (names ))
92
97
93
98
94
- def install (
95
- packages : Sequence [str ], exports : Sequence [str ] = (), force : bool = False
96
- ) -> None :
97
- package_list = _to_list_of_str (packages )
98
- export_list = _to_list_of_str (exports )
99
-
100
- for pkg in package_list :
101
- at_count = pkg .count ("@" )
102
- if pkg .startswith ("@" ) and at_count == 1 :
103
- export_list .append (pkg )
104
- else :
105
- # this works even if there are no @ symbols
106
- export_list .append (pkg .rsplit ("@" , 1 )[0 ])
107
-
108
- if force :
109
- for exp in export_list :
110
- delete_web_modules (exp , skip_missing = True )
111
-
99
+ def install (packages : Sequence [str ], exports : Sequence [str ] = ()) -> None :
112
100
with TemporaryDirectory () as tempdir :
113
101
tempdir_path = Path (tempdir )
114
102
temp_static_dir = tempdir_path / "static"
103
+ temp_build_dir = temp_static_dir / "build"
115
104
105
+ # copy over the whole ./static directory into the temp one
116
106
shutil .copytree (STATIC_DIR , temp_static_dir , symlinks = True )
117
- assert (temp_static_dir / "package.json" ).exists ()
107
+
108
+ cache = Cache (temp_build_dir )
109
+ cache .add_packages (packages , exports )
118
110
119
111
with open (temp_static_dir / "package.json" ) as f :
120
112
package_json = json .load (f )
121
113
122
- temp_build_dir = temp_static_dir / "build"
123
-
124
- cache = _read_idom_build_cache (temp_build_dir )
125
-
126
- export_list = list (set (cache ["export_list" ] + export_list ))
127
- package_list = list (set (cache ["package_list" ] + package_list ))
128
-
129
114
pkg_snowpack = package_json .setdefault ("snowpack" , {})
130
- pkg_snowpack .setdefault ("install" , []).extend (export_list )
115
+ pkg_snowpack .setdefault ("install" , []).extend (cache . export_list )
131
116
132
117
with (temp_static_dir / "package.json" ).open ("w+" ) as f :
133
118
json .dump (package_json , f )
134
119
135
- with Spinner (f"Installing: { ', ' .join (package_list )} " ):
120
+ with Spinner (f"Installing: { ', ' .join (packages )} " ):
136
121
_run_subprocess (["npm" , "install" ], temp_static_dir )
137
- _run_subprocess (["npm" , "install" ] + package_list , temp_static_dir )
122
+ _run_subprocess (["npm" , "install" ] + cache . package_list , temp_static_dir )
138
123
_run_subprocess (["npm" , "run" , "build" ], temp_static_dir )
139
124
140
- cache ["export_list" ] = export_list
141
- cache ["package_list" ] = package_list
142
-
143
- _write_idom_build_cache (temp_build_dir , cache )
125
+ cache .save ()
144
126
145
127
if BUILD_DIR .exists ():
146
128
shutil .rmtree (BUILD_DIR )
@@ -150,12 +132,56 @@ def install(
150
132
151
133
def restore () -> None :
152
134
with Spinner ("Restoring" ):
153
- _delete_os_paths (WEB_MODULES , NODE_MODULES )
135
+ _delete_os_paths (BUILD_DIR )
154
136
_run_subprocess (["npm" , "install" ], STATIC_DIR )
155
137
_run_subprocess (["npm" , "run" , "build" ], STATIC_DIR )
156
138
STATIC_SHIMS .clear ()
157
139
158
140
141
+ class Cache :
142
+ """Manages a cache file stored at ``build/.idom-cache.json``"""
143
+
144
+ __slots__ = "_file" , "package_list" , "export_list"
145
+
146
+ def __init__ (self , path : Path ) -> None :
147
+ self ._file = path / ".idom-cache.json"
148
+ if not self ._file .exists ():
149
+ self .package_list : List [str ] = []
150
+ self .export_list : List [str ] = []
151
+ else :
152
+ self ._load ()
153
+
154
+ def add_packages (self , packages : Sequence [str ], exports : Sequence [str ]) -> None :
155
+ package_list = _to_list_of_str (packages )
156
+ export_list = _to_list_of_str (exports )
157
+ export_list .extend (map (_export_name_from_package , package_list ))
158
+ self .package_list = list (set (self .package_list + package_list ))
159
+ self .export_list = list (set (self .export_list + export_list ))
160
+
161
+ def delete_package (self , export_name : str ) -> None :
162
+ self .export_list .remove (export_name )
163
+ for i , pkg in enumerate (self .package_list ):
164
+ if _export_name_from_package (pkg ) == export_name :
165
+ del self .package_list [i ]
166
+ break
167
+
168
+ def save (self ) -> None :
169
+ cache = {
170
+ name : getattr (self , name )
171
+ for name in self .__slots__
172
+ if not name .startswith ("_" )
173
+ }
174
+ with self ._file .open ("w+" ) as f :
175
+ json .dump (cache , f )
176
+
177
+ def _load (self ) -> None :
178
+ with self ._file .open () as f :
179
+ cache = json .load (f )
180
+ for name in self .__slots__ :
181
+ if not name .startswith ("_" ):
182
+ setattr (self , name , cache [name ])
183
+
184
+
159
185
def _run_subprocess (args : List [str ], cwd : Union [str , Path ]) -> None :
160
186
try :
161
187
subprocess .run (
@@ -176,23 +202,14 @@ def _delete_os_paths(*paths: Path) -> None:
176
202
shutil .rmtree (p )
177
203
178
204
179
- def _read_idom_build_cache (path : Path ) -> Dict [str , Any ]:
180
- cache_file = path / ".idom-cache.json"
181
- if not cache_file .exists ():
182
- return {
183
- "package_list" : [],
184
- "export_list" : [],
185
- }
186
- else :
187
- with cache_file .open () as f :
188
- return cast (Dict [str , Any ], json .load (f ))
189
-
190
-
191
- def _write_idom_build_cache (path : Path , cache : Dict [str , Any ]) -> None :
192
- cache_file = path / ".idom-cache.json"
193
- with cache_file .open ("w+" ) as f :
194
- json .dump (cache , f )
195
-
196
-
197
205
def _to_list_of_str (value : Sequence [str ]) -> List [str ]:
198
206
return [value ] if isinstance (value , str ) else list (value )
207
+
208
+
209
+ def _export_name_from_package (pkg : str ) -> str :
210
+ at_count = pkg .count ("@" )
211
+ if pkg .startswith ("@" ) and at_count == 1 :
212
+ return pkg
213
+ else :
214
+ # this works even if there are no @ symbols
215
+ return pkg .rsplit ("@" , 1 )[0 ]
0 commit comments