Skip to content

Commit a3f6780

Browse files
authored
Merge pull request #3 from pvizeli/addons
Addon support
2 parents 9afb136 + e0be15c commit a3f6780

21 files changed

+916
-45
lines changed

API.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,15 @@ On success
6969
"version": "INSTALL_VERSION",
7070
"current": "CURRENT_VERSION",
7171
"beta": "true|false",
72-
"addons": {}
72+
"addons": [
73+
{
74+
"name": "xy bla",
75+
"slug": "xy",
76+
"version": "CURRENT_VERSION",
77+
"installed": "none|INSTALL_VERSION",
78+
"description": "description"
79+
}
80+
]
7381
}
7482
```
7583

hassio/addons/__init__.py

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
"""Init file for HassIO addons."""
2+
import asyncio
3+
import logging
4+
import os
5+
import shutil
6+
7+
from .data import AddonsData
8+
from .git import AddonsRepo
9+
from ..const import STATE_STOPPED, STATE_STARTED
10+
from ..dock.addon import DockerAddon
11+
12+
_LOGGER = logging.getLogger(__name__)
13+
14+
15+
class AddonManager(AddonsData):
16+
"""Manage addons inside HassIO."""
17+
18+
def __init__(self, config, loop, dock):
19+
"""Initialize docker base wrapper."""
20+
super().__init__(config)
21+
22+
self.loop = loop
23+
self.dock = dock
24+
self.repo = AddonsRepo(config, loop)
25+
self.dockers = {}
26+
27+
async def prepare(self, arch):
28+
"""Startup addon management."""
29+
self.arch = arch
30+
31+
# load addon repository
32+
if await self.repo.load():
33+
self.read_addons_repo()
34+
35+
# load installed addons
36+
for addon in self.list_installed:
37+
self.dockers[addon] = DockerAddon(
38+
self.config, self.loop, self.dock, self, addon)
39+
40+
async def relaod(self):
41+
"""Update addons from repo and reload list."""
42+
if not await self.repo.pull():
43+
return
44+
self.read_addons_repo()
45+
46+
# remove stalled addons
47+
tasks = []
48+
for addon in self.list_removed:
49+
_LOGGER.info("Old addon %s found")
50+
tasks.append(self.loop.create_task(self.dockers[addon].remove()))
51+
52+
if tasks:
53+
await asyncio.wait(tasks, loop=self.loop)
54+
55+
async def auto_boot(self, start_type):
56+
"""Boot addons with mode auto."""
57+
boot_list = self.list_startup(start_type)
58+
tasks = []
59+
60+
for addon in boot_list:
61+
tasks.append(self.loop.create_task(self.start(addon)))
62+
63+
_LOGGER.info("Startup %s run %d addons", start_type, len(tasks))
64+
if tasks:
65+
await asyncio.wait(tasks, loop=self.loop)
66+
67+
async def install(self, addon, version=None):
68+
"""Install a addon."""
69+
if not self.exists_addon(addon):
70+
_LOGGER.error("Addon %s not exists for install", addon)
71+
return False
72+
73+
if self.is_installed(addon):
74+
_LOGGER.error("Addon %s is already installed", addon)
75+
return False
76+
77+
if not os.path.isdir(self.path_data(addon)):
78+
_LOGGER.info("Create Home-Assistant addon data folder %s",
79+
self.path_data(addon))
80+
os.mkdir(self.path_data(addon))
81+
82+
addon_docker = DockerAddon(
83+
self.config, self.loop, self.dock, self, addon)
84+
85+
version = version or self.get_version(addon)
86+
if not await addon_docker.install(version):
87+
return False
88+
89+
self.dockers[addon] = addon_docker
90+
self.set_install_addon(addon, version)
91+
return True
92+
93+
async def uninstall(self, addon):
94+
"""Remove a addon."""
95+
if not self.is_installed(addon):
96+
_LOGGER.error("Addon %s is already uninstalled", addon)
97+
return False
98+
99+
if addon not in self.dockers:
100+
_LOGGER.error("No docker found for addon %s", addon)
101+
return False
102+
103+
if not await self.dockers[addon].remove():
104+
return False
105+
106+
if os.path.isdir(self.path_data(addon)):
107+
_LOGGER.info("Remove Home-Assistant addon data folder %s",
108+
self.path_data(addon))
109+
shutil.rmtree(self.path_data(addon))
110+
111+
self.dockers.pop(addon)
112+
self.set_uninstall_addon(addon)
113+
return True
114+
115+
async def state(self, addon):
116+
"""Return running state of addon."""
117+
if addon not in self.dockers:
118+
_LOGGER.error("No docker found for addon %s", addon)
119+
return
120+
121+
if await self.dockers[addon].is_running():
122+
return STATE_STARTED
123+
return STATE_STOPPED
124+
125+
async def start(self, addon):
126+
"""Set options and start addon."""
127+
if addon not in self.dockers:
128+
_LOGGER.error("No docker found for addon %s", addon)
129+
return False
130+
131+
if not self.write_addon_options(addon):
132+
_LOGGER.error("Can't write options for addon %s", addon)
133+
return False
134+
135+
return await self.dockers[addon].run()
136+
137+
async def stop(self, addon):
138+
"""Stop addon."""
139+
if addon not in self.dockers:
140+
_LOGGER.error("No docker found for addon %s", addon)
141+
return False
142+
143+
return await self.dockers[addon].stop()
144+
145+
async def update(self, addon, version=None):
146+
"""Update addon."""
147+
if not self.is_installed(addon):
148+
_LOGGER.error("Addon %s is not installed", addon)
149+
return False
150+
151+
if addon not in self.dockers:
152+
_LOGGER.error("No docker found for addon %s", addon)
153+
return False
154+
155+
version = version or self.get_version(addon)
156+
if await self.dockers[addon].update(version):
157+
self.set_version(addon, version)
158+
return True
159+
return False

0 commit comments

Comments
 (0)