44from collections .abc import Awaitable
55import logging
66
7- from ..const import ATTR_REPOSITORIES , URL_HASSIO_ADDONS
7+ from ..const import ATTR_REPOSITORIES , REPOSITORY_CORE , URL_HASSIO_ADDONS
88from ..coresys import CoreSys , CoreSysAttributes
99from ..exceptions import (
1010 StoreError ,
1818from ..resolution .const import ContextType , IssueType , SuggestionType
1919from ..utils .common import FileConfiguration
2020from .addon import AddonStore
21- from .const import FILE_HASSIO_STORE , StoreType
21+ from .const import FILE_HASSIO_STORE , BuiltinRepository
2222from .data import StoreData
2323from .repository import Repository
24- from .validate import (
25- BUILTIN_REPOSITORIES ,
26- SCHEMA_STORE_FILE ,
27- ensure_builtin_repositories ,
28- )
24+ from .validate import SCHEMA_STORE_FILE , ensure_builtin_repositories
2925
3026_LOGGER : logging .Logger = logging .getLogger (__name__ )
3127
@@ -56,7 +52,8 @@ def repository_urls(self) -> list[str]:
5652 return [
5753 repository .source
5854 for repository in self .all
59- if repository .type == StoreType .GIT
55+ if repository .slug
56+ not in {BuiltinRepository .LOCAL .value , BuiltinRepository .CORE .value }
6057 ]
6158
6259 def get (self , slug : str ) -> Repository :
@@ -65,19 +62,11 @@ def get(self, slug: str) -> Repository:
6562 raise StoreNotFound ()
6663 return self .repositories [slug ]
6764
68- def get_from_url (self , url : str ) -> Repository :
69- """Return Repository with slug."""
70- for repository in self .all :
71- if repository .source != url :
72- continue
73- return repository
74- raise StoreNotFound ()
75-
7665 async def load (self ) -> None :
7766 """Start up add-on management."""
7867 # Init custom repositories and load add-ons
7968 await self .update_repositories (
80- self ._data [ATTR_REPOSITORIES ], add_with_errors = True
69+ self ._data [ATTR_REPOSITORIES ], issue_on_error = True
8170 )
8271
8372 @Job (
@@ -126,14 +115,14 @@ async def reload(self, repository: Repository | None = None) -> None:
126115 )
127116 async def add_repository (self , url : str , * , persist : bool = True ) -> None :
128117 """Add a repository."""
129- await self ._add_repository (url , persist = persist , add_with_errors = False )
118+ await self ._add_repository (url , persist = persist , issue_on_error = False )
130119
131120 async def _add_repository (
132- self , url : str , * , persist : bool = True , add_with_errors : bool = False
121+ self , url : str , * , persist : bool = True , issue_on_error : bool = False
133122 ) -> None :
134123 """Add a repository."""
135124 if url == URL_HASSIO_ADDONS :
136- url = StoreType . CORE
125+ url = REPOSITORY_CORE
137126
138127 repository = Repository .create (self .coresys , url )
139128
@@ -145,7 +134,7 @@ async def _add_repository(
145134 await repository .load ()
146135 except StoreGitCloneError as err :
147136 _LOGGER .error ("Can't retrieve data from %s due to %s" , url , err )
148- if add_with_errors :
137+ if issue_on_error :
149138 self .sys_resolution .create_issue (
150139 IssueType .FATAL_ERROR ,
151140 ContextType .STORE ,
@@ -158,7 +147,7 @@ async def _add_repository(
158147
159148 except StoreGitError as err :
160149 _LOGGER .error ("Can't load data from repository %s due to %s" , url , err )
161- if add_with_errors :
150+ if issue_on_error :
162151 self .sys_resolution .create_issue (
163152 IssueType .FATAL_ERROR ,
164153 ContextType .STORE ,
@@ -171,7 +160,7 @@ async def _add_repository(
171160
172161 except StoreJobError as err :
173162 _LOGGER .error ("Can't add repository %s due to %s" , url , err )
174- if add_with_errors :
163+ if issue_on_error :
175164 self .sys_resolution .create_issue (
176165 IssueType .FATAL_ERROR ,
177166 ContextType .STORE ,
@@ -184,7 +173,7 @@ async def _add_repository(
184173
185174 else :
186175 if not await repository .validate ():
187- if add_with_errors :
176+ if issue_on_error :
188177 _LOGGER .error ("%s is not a valid add-on repository" , url )
189178 self .sys_resolution .create_issue (
190179 IssueType .CORRUPT_REPOSITORY ,
@@ -213,7 +202,7 @@ async def _add_repository(
213202
214203 async def remove_repository (self , repository : Repository , * , persist : bool = True ):
215204 """Remove a repository."""
216- if repository .source in BUILTIN_REPOSITORIES :
205+ if repository .is_builtin :
217206 raise StoreInvalidAddonRepo (
218207 "Can't remove built-in repositories!" , logger = _LOGGER .error
219208 )
@@ -236,38 +225,54 @@ async def update_repositories(
236225 self ,
237226 list_repositories : list [str ],
238227 * ,
239- add_with_errors : bool = False ,
228+ issue_on_error : bool = False ,
240229 replace : bool = True ,
241230 ):
242- """Add a new custom repository."""
243- new_rep = set (
244- ensure_builtin_repositories (list_repositories )
245- if replace
246- else list_repositories + self .repository_urls
247- )
248- old_rep = {repository .source for repository in self .all }
231+ """Update repositories by adding new ones and removing stale ones."""
232+ current_repositories = {repository .source for repository in self .all }
233+
234+ # Determine changes needed
235+ if replace :
236+ target_repositories = set (ensure_builtin_repositories (list_repositories ))
237+ repositories_to_add = target_repositories - current_repositories
238+ else :
239+ # When not replacing, just add the new repositories
240+ repositories_to_add = set (list_repositories ) - current_repositories
241+ target_repositories = current_repositories | repositories_to_add
249242
250243 # Add new repositories
251244 add_errors = await asyncio .gather (
252245 * [
253- self ._add_repository (url , persist = False , add_with_errors = True )
254- if add_with_errors
246+ # Use _add_repository to avoid JobCondition.SUPERVISOR_UPDATED
247+ # to prevent proper loading of repositories on startup.
248+ self ._add_repository (url , persist = False , issue_on_error = True )
249+ if issue_on_error
255250 else self .add_repository (url , persist = False )
256- for url in new_rep - old_rep
251+ for url in repositories_to_add
257252 ],
258253 return_exceptions = True ,
259254 )
260255
261- # Delete stale repositories
262- remove_errors = await asyncio .gather (
263- * [
264- self .remove_repository (self .get_from_url (url ), persist = False )
265- for url in old_rep - new_rep - BUILTIN_REPOSITORIES
266- ],
267- return_exceptions = True ,
268- )
256+ remove_errors : list [BaseException | None ] = []
257+ if replace :
258+ # Determine repositories to remove
259+ repositories_to_remove : list [Repository ] = [
260+ repository
261+ for repository in self .all
262+ if repository .source not in target_repositories
263+ and not repository .is_builtin
264+ ]
265+
266+ # Remove repositories
267+ remove_errors = await asyncio .gather (
268+ * [
269+ self .remove_repository (repository , persist = False )
270+ for repository in repositories_to_remove
271+ ],
272+ return_exceptions = True ,
273+ )
269274
270- # Always update data, even there are errors, some changes may have succeeded
275+ # Always update data, even if there are errors, some changes may have succeeded
271276 await self .data .update ()
272277 await self ._read_addons ()
273278
0 commit comments