11"""Represent a Supervisor repository."""
22
3+ from __future__ import annotations
4+
5+ from abc import ABC , abstractmethod
36import logging
47from pathlib import Path
58
1215from ..exceptions import ConfigurationFileError , StoreError
1316from ..utils .common import read_json_or_yaml_file
1417from .const import StoreType
15- from .git import GitRepo , GitRepoBuiltin , GitRepoCustom
18+ from .git import GitRepo
1619from .utils import get_hash_from_repository
1720from .validate import SCHEMA_REPOSITORY_CONFIG , BuiltinRepository
1821
1922_LOGGER : logging .Logger = logging .getLogger (__name__ )
2023UNKNOWN = "unknown"
2124
2225
23- class Repository (CoreSysAttributes ):
26+ class Repository (CoreSysAttributes , ABC ):
2427 """Add-on store repository in Supervisor."""
2528
2629 def __init__ (self , coresys : CoreSys , repository : str ):
2730 """Initialize add-on store repository object."""
31+ self ._slug : str
32+ self ._type : StoreType
2833 self .coresys : CoreSys = coresys
29- self .git : GitRepo | None = None
30-
3134 self .source : str = repository
35+
36+ @staticmethod
37+ def create (coresys : CoreSys , repository : str ) -> Repository :
38+ """Create a repository instance."""
3239 if repository == StoreType .LOCAL :
33- self ._slug = repository
34- self ._type = StoreType .LOCAL
35- self ._latest_mtime : float | None = None
36- elif repository in BuiltinRepository :
37- builtin = BuiltinRepository (repository )
38- self .git = GitRepoBuiltin (coresys , builtin )
39- self ._slug = builtin .id
40- self ._type = builtin .type
41- else :
42- self .git = GitRepoCustom (coresys , repository )
43- self ._slug = get_hash_from_repository (repository )
44- self ._type = StoreType .GIT
40+ return RepositoryLocal (coresys )
41+ if repository in BuiltinRepository :
42+ return RepositoryGitBuiltin (coresys , BuiltinRepository (repository ))
43+ return RepositoryCustom (coresys , repository )
4544
4645 def __repr__ (self ) -> str :
4746 """Return internal representation."""
@@ -77,52 +76,117 @@ def maintainer(self) -> str:
7776 """Return url of repository."""
7877 return self .data .get (ATTR_MAINTAINER , UNKNOWN )
7978
80- def validate (self ) -> bool :
81- """Check if store is valid.
79+ @abstractmethod
80+ async def validate (self ) -> bool :
81+ """Check if store is valid."""
82+
83+ @abstractmethod
84+ async def load (self ) -> None :
85+ """Load addon repository."""
86+
87+ @abstractmethod
88+ async def update (self ) -> bool :
89+ """Update add-on repository.
8290
83- Must be run in executor .
91+ Returns True if the repository was updated .
8492 """
85- if not self .git or self .type == StoreType .CORE :
86- return True
8793
88- # If exists?
89- for filetype in FILE_SUFFIX_CONFIGURATION :
90- repository_file = Path (self .git .path / f"repository{ filetype } " )
91- if repository_file .exists ():
92- break
94+ @abstractmethod
95+ async def remove (self ) -> None :
96+ """Remove add-on repository."""
9397
94- if not repository_file .exists ():
95- return False
98+ @abstractmethod
99+ async def reset (self ) -> None :
100+ """Reset add-on repository to fix corruption issue with files."""
96101
97- # If valid?
98- try :
99- SCHEMA_REPOSITORY_CONFIG (read_json_or_yaml_file (repository_file ))
100- except (ConfigurationFileError , vol .Invalid ) as err :
101- _LOGGER .warning ("Could not validate repository configuration %s" , err )
102- return False
103102
103+ class RepositoryBuiltin (Repository , ABC ):
104+ """A built-in add-on repository."""
105+
106+ def __init__ (self , coresys : CoreSys , builtin : BuiltinRepository ) -> None :
107+ """Initialize object."""
108+ super ().__init__ (coresys , builtin .value )
109+ self ._builtin = builtin
110+ self ._slug = builtin .id
111+ self ._type = builtin .type
112+
113+ async def validate (self ) -> bool :
114+ """Assume built-in repositories are always valid."""
104115 return True
105116
117+ async def remove (self ) -> None :
118+ """Raise. Not supported for built-in repositories."""
119+ raise StoreError ("Can't remove built-in repositories!" , _LOGGER .error )
120+
121+
122+ class RepositoryGit (Repository , ABC ):
123+ """A git based add-on repository."""
124+
125+ _git : GitRepo
126+
106127 async def load (self ) -> None :
107128 """Load addon repository."""
108- if not self .git :
109- self ._latest_mtime , _ = await self .sys_run_in_executor (
110- get_latest_mtime , self .sys_config .path_addons_local
111- )
112- return
113- await self .git .load ()
129+ await self ._git .load ()
114130
115131 async def update (self ) -> bool :
116132 """Update add-on repository.
117133
118134 Returns True if the repository was updated.
119135 """
120- if not await self .sys_run_in_executor ( self . validate ):
136+ if not await self .validate ( ):
121137 return False
122138
123- if self .git :
124- return await self .git .pull ()
139+ return await self ._git .pull ()
140+
141+ async def validate (self ) -> bool :
142+ """Check if store is valid."""
143+
144+ def validate_file () -> bool :
145+ # If exists?
146+ for filetype in FILE_SUFFIX_CONFIGURATION :
147+ repository_file = Path (self ._git .path / f"repository{ filetype } " )
148+ if repository_file .exists ():
149+ break
150+
151+ if not repository_file .exists ():
152+ return False
153+
154+ # If valid?
155+ try :
156+ SCHEMA_REPOSITORY_CONFIG (read_json_or_yaml_file (repository_file ))
157+ except (ConfigurationFileError , vol .Invalid ) as err :
158+ _LOGGER .warning ("Could not validate repository configuration %s" , err )
159+ return False
125160
161+ return True
162+
163+ return await self .sys_run_in_executor (validate_file )
164+
165+ async def reset (self ) -> None :
166+ """Reset add-on repository to fix corruption issue with files."""
167+ await self ._git .reset ()
168+ await self .load ()
169+
170+
171+ class RepositoryLocal (RepositoryBuiltin ):
172+ """A local add-on repository."""
173+
174+ def __init__ (self , coresys : CoreSys ) -> None :
175+ """Initialize object."""
176+ super ().__init__ (coresys , BuiltinRepository .LOCAL )
177+ self ._latest_mtime : float | None = None
178+
179+ async def load (self ) -> None :
180+ """Load addon repository."""
181+ self ._latest_mtime , _ = await self .sys_run_in_executor (
182+ get_latest_mtime , self .sys_config .path_addons_local
183+ )
184+
185+ async def update (self ) -> bool :
186+ """Update add-on repository.
187+
188+ Returns True if the repository was updated.
189+ """
126190 # Check local modifications
127191 latest_mtime , modified_path = await self .sys_run_in_executor (
128192 get_latest_mtime , self .sys_config .path_addons_local
@@ -138,9 +202,32 @@ async def update(self) -> bool:
138202
139203 return False
140204
205+ async def reset (self ) -> None :
206+ """Raise. Not supported for local repository."""
207+ raise StoreError (
208+ "Can't reset local repository as it is not git based!" , _LOGGER .error
209+ )
210+
211+
212+ class RepositoryGitBuiltin (RepositoryBuiltin , RepositoryGit ):
213+ """A built-in add-on repository based on git."""
214+
215+ def __init__ (self , coresys : CoreSys , builtin : BuiltinRepository ) -> None :
216+ """Initialize object."""
217+ super ().__init__ (coresys , builtin )
218+ self ._git = GitRepo (coresys , builtin .get_path (coresys ), builtin .url )
219+
220+
221+ class RepositoryCustom (RepositoryGit ):
222+ """A custom add-on repository."""
223+
224+ def __init__ (self , coresys : CoreSys , url : str ) -> None :
225+ """Initialize object."""
226+ super ().__init__ (coresys , url )
227+ self ._slug = get_hash_from_repository (url )
228+ self ._type = StoreType .GIT
229+ self ._git = GitRepo (coresys , coresys .config .path_addons_git / self ._slug , url )
230+
141231 async def remove (self ) -> None :
142232 """Remove add-on repository."""
143- if not self .git or self .git .builtin :
144- raise StoreError ("Can't remove built-in repositories!" , _LOGGER .error )
145-
146- await self .git .remove ()
233+ await self ._git .remove ()
0 commit comments