Skip to content

Commit

Permalink
Add support for python_script (#145)
Browse files Browse the repository at this point in the history
  • Loading branch information
ludeeus committed Jun 21, 2019
1 parent 4275981 commit d88ce73
Show file tree
Hide file tree
Showing 14 changed files with 152 additions and 21 deletions.
3 changes: 3 additions & 0 deletions custom_components/hacs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
{
vol.Required("token"): cv.string,
vol.Optional("appdaemon", default=False): cv.boolean,
vol.Optional("python_script", default=False): cv.boolean,
}
)
},
Expand All @@ -72,6 +73,8 @@ async def async_setup(hass, config): # pylint: disable=unused-argument

if config[DOMAIN]["appdaemon"]:
ELEMENT_TYPES.append("appdaemon")
if config[DOMAIN]["python_script"]:
ELEMENT_TYPES.append("python_script")

# Print DEV warning
if VERSION == "DEV":
Expand Down
1 change: 1 addition & 0 deletions custom_components/hacs/blueprints.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@
from .hacsrepositoryappdaemon import HacsRepositoryAppDaemon
from .hacsrepositoryintegration import HacsRepositoryIntegration
from .hacsrepositorybaseplugin import HacsRepositoryPlugin
from .hacsrepositorypythonscript import HacsRepositoryPythonScripts
from .hacsviewbase import HacsViewBase
1 change: 1 addition & 0 deletions custom_components/hacs/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,5 @@
"bramkragten/swipe-card",
"CyrisXD/love-lock-card",
],
"python_script": [],
}
2 changes: 2 additions & 0 deletions custom_components/hacs/frontend/views/overview.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ async def get(self, request): # pylint: disable=unused-argument
typedisplay = "{}S".format(element_type.upper())
if element_type == "appdaemon":
typedisplay = "APPDAEMON APPS"
elif element_type == "python_script":
typedisplay = "PYTHON SCRIPTS"
if self.data.get("hacs", {}).get("view") == "Table":
content += """
<div class='hacs-overview-container'>
Expand Down
2 changes: 2 additions & 0 deletions custom_components/hacs/frontend/views/store.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ async def get(self, request): # pylint: disable=unused-argument
typedisplay = "{}S".format(element_type.upper())
if element_type == "appdaemon":
typedisplay = "APPDAEMON APPS"
elif element_type == "python_script":
typedisplay = "PYTHON SCRIPTS"
if self.data.get("hacs", {}).get("view") == "Table":
content += """
<div class='hacs-overview-container'>
Expand Down
4 changes: 4 additions & 0 deletions custom_components/hacs/hacsbase.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ async def register_new_repository(self, element_type, repo, repositoryobject=Non
HacsRepositoryAppDaemon,
HacsRepositoryIntegration,
HacsRepositoryPlugin,
HacsRepositoryPythonScripts,
)

_LOGGER.info("Starting repository registration for %s", repo)
Expand All @@ -117,6 +118,9 @@ async def register_new_repository(self, element_type, repo, repositoryobject=Non
elif element_type == "plugin":
repository = HacsRepositoryPlugin(repo, repositoryobject)

elif element_type == "python_script":
repository = HacsRepositoryPythonScripts(repo, repositoryobject)

else:
return None, False

Expand Down
45 changes: 32 additions & 13 deletions custom_components/hacs/hacsrepositorybase.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ def custom(self):
return False
elif self.repository_name in DEFAULT_REPOSITORIES["plugin"]:
return False
elif self.repository_name in DEFAULT_REPOSITORIES["python_script"]:
return False
return True

@property
Expand All @@ -89,6 +91,10 @@ def local_path(self):

elif self.repository_type == "plugin":
local_path = "{}/www/community/{}".format(self.config_dir, self.name)

elif self.repository_type == "python_script":
local_path = "{}/python_scripts".format(self.config_dir)

return local_path

@property
Expand Down Expand Up @@ -176,7 +182,10 @@ async def download_repository_directory_content(
"""Download the content of a directory."""
try:
# Get content
if self.content_path == "release":
if (
self.content_path == "release"
or self.repository_type == "python_script"
):
contents = self.content_objects
else:
contents = await self.repository.get_contents(
Expand Down Expand Up @@ -216,10 +225,13 @@ async def download_repository_directory_content(
"{}/".format(self.content_path), ""
)

local_directory = "{}/{}".format(self.local_path, _content_path)
local_directory = local_directory.split(
"/{}".format(content_object.name)
)[0]
if self.repository_type == "python_script":
local_directory = self.local_path
else:
local_directory = "{}/{}".format(self.local_path, _content_path)
local_directory = local_directory.split(
"/{}".format(content_object.name)
)[0]

# Check local directory
pathlib.Path(local_directory).mkdir(parents=True, exist_ok=True)
Expand Down Expand Up @@ -320,20 +332,27 @@ async def check_local_directory(self, path=None):
async def remove_local_directory(self):
"""Check the local directory."""
try:
if os.path.exists(self.local_path):
_LOGGER.debug(
"(%s) - Removing %s", self.repository_name, self.local_path
)
shutil.rmtree(self.local_path)
if self.repository_type == "python_script":
local_path = "{}/{}.py".format(self.local_path, self.name)
else:
local_path = self.local_path

if os.path.exists(local_path):
_LOGGER.debug("(%s) - Removing %s", self.repository_name, local_path)

while os.path.exists(self.local_path):
if self.repository_type == "python_script":
os.remove(local_path)
else:
shutil.rmtree(local_path)

while os.path.exists(local_path):
await sleep(1)

except Exception as exception:
_LOGGER.debug(
"(%s) - Removing directory %s failed with %s",
"(%s) - Removing %s failed with %s",
self.repository_name,
self.local_path,
local_path,
exception,
)
return
Expand Down
53 changes: 53 additions & 0 deletions custom_components/hacs/hacsrepositorypythonscript.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
"""Blueprint for HacsRepositoryPythonScripts."""
# pylint: disable=too-many-instance-attributes,invalid-name,broad-except
import logging

from .blueprints import HacsRepositoryBase
from .exceptions import HacsRequirement

_LOGGER = logging.getLogger("custom_components.hacs.repository")


class HacsRepositoryPythonScripts(HacsRepositoryBase):
"""
Set up a HacsRepositoryPythonScripts object.
repository_name(str): The full name of a repository
(example: awesome-dev/awesome-repo)
"""

def __init__(self, repository_name: str, repositoryobject=None):
"""Initialize a HacsRepositoryAppDaemon object."""
super().__init__()
self.repository = repositoryobject
self.repository_name = repository_name
self.repository_type = "python_script"
self.manifest_content = None

async def update(self):
"""Run update tasks."""
if await self.common_update():
return
await self.set_repository_content()

async def set_repository_content(self):
"""Set repository content attributes."""
contentfiles = []

if self.content_path is None:
self.content_objects = await self.repository.get_contents(
"python_scripts", self.ref
)

self.content_path = self.content_objects[0].path

self.name = self.content_objects[0].name.replace(".py", "")

if not isinstance(self.content_objects, list):
raise HacsRequirement("Repository structure does not meet the requirements")

for filename in self.content_objects:
contentfiles.append(filename.name)

if contentfiles:
self.content_files = contentfiles
7 changes: 3 additions & 4 deletions docs/developer/appdaemon.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,9 @@ For a AppDaemon app repository to be valid these are the requirements:

### Repository structure

- There is only one integration (one directory under `ROOT_OF_THE_REPO/apps/`) pr. repository (if you have more, only the first one will be managed.)
- The integration (all the python files for it) are located under `ROOT_OF_THE_REPO/apps/APP_NAME/`
- There is only one integration (one directory under `ROOT_OF_THE_REPO/apps/`) per repository (if you have more, only the first one will be managed.)
- The integration and all the python files for it are located under `ROOT_OF_THE_REPO/apps/APP_NAME/`
- There is only one app (one directory under `ROOT_OF_THE_REPO/apps/`) pr. repository (if you have more, only the first one will be managed.)
- The app (all the python files for it) are located under `ROOT_OF_THE_REPO/apps/APP_NAME/`
- The app and all the python files for it are located under `ROOT_OF_THE_REPO/apps/APP_NAME/`

#### OK example:

Expand Down
39 changes: 39 additions & 0 deletions docs/developer/python_script.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# `python_script` developers

A template to use as a reference is [ps-hacs](https://github.com/ludeeus/ps-hacs)

This is for the [`python_script` integration in Home Assistant](https://www.home-assistant.io/components/python_script/)

## Requirements

For a python_script repository to be valid these are the requirements:

### Repository structure

- The python script are located here `ROOT_OF_THE_REPO/python_scripts/SCRIPT_NAME.py`
- There is only one python file (one directory under `ROOT_OF_THE_REPO/python_scripts/`) per repository (if you have more, only the first one will be managed.)

#### OK example:

```text
python_scripts/awesome.py
info.md
README.md
```
#### Not OK example:

```text
awesome.py
info.md
README.md
```

### GitHub releases (optional)

#### If there are releases

When installing/upgrading it will scan the content in the latest release.

#### If there are no releases

It will scan files in the branch marked as default.
12 changes: 9 additions & 3 deletions docs/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ Although "Store" is not "technically" correct, since nothing is sold, it's more

### Highlights of what HACS can do

- Help you discover new integrations and plugins.
- Help you install (download) new integrations and plugins.
- Help you keep track of your integrations and plugins.
- Help you discover new custom elements.
- Help you install (download) new custom elements.
- Help you keep track of your custom elements.

***

Expand Down Expand Up @@ -58,6 +58,12 @@ If you make local changes to a plugin in the `.js` file, delete the `.gz` varian

The files are downloaded to `<config_dir>/www/community/*`

### Files downloaded for `python_script`

The first file under the `python_scripts` directory._

The files are downloaded to `<config_dir>/python_scripts/*`

***

## How does it work: Upgrade
Expand Down
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

## What can HACS do?

This is a manager for your custom integration (components) plugin (lovelace elements) and AppDaemon needs.
This is a manager for your custom Home Assistant needs.

It can help you download and update elements.

Expand Down
1 change: 1 addition & 0 deletions docs/installation/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ key | optional | default | description
-- | -- | -- | --
`token` | False | | A Github Personal Access Token
`appdaemon` | True | `False` | Enable tracking of AppDaemon apps.
`python_script` | True | `False` | Enable tracking of python scripts.

***

Expand Down
1 change: 1 addition & 0 deletions docs/usage/settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ Type | Description
`Appdaemon` | Apps for AppDaemon
`Integration` | Integrations for Home Assistant (custom_components)
`Plugin` | Pugins for Lovelace (cards, mods, elements, rows and so on.)
`Python_Script` | Python scripts for the [`python_script` integration](https://www.home-assistant.io/components/python_script/)

After adding a repository the repository will be scanned, if it can be tracked the element will show up under "STORE", and you will be redirected to that element.

Expand Down

0 comments on commit d88ce73

Please sign in to comment.