Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor default skill installation #188

Merged
merged 4 commits into from
Dec 17, 2021
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 53 additions & 6 deletions neon_core/util/skill_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,29 +23,72 @@
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

from os.path import expanduser
import git
import json
import requests

from os import listdir
from tempfile import mkdtemp
from shutil import rmtree
from os.path import expanduser, join
from ovos_skills_manager.skill_entry import SkillEntry
from ovos_skills_manager.osm import OVOSSkillsManager
from ovos_skills_manager.session import SESSION as requests, set_github_token, clear_github_token
from ovos_skills_manager.session import SESSION, set_github_token, clear_github_token
from ovos_skills_manager.github import normalize_github_url, get_branch_from_github_url
from neon_utils.configuration_utils import get_neon_skills_config
from neon_utils import LOG


def get_neon_skills_data(skill_meta_repository: str = "https://github.com/neongeckocom/neon_skills",
branch: str = None,
repo_metadata_path: str = "skill_metadata") -> dict:
"""
Get skill data from configured neon_skills repository.
:param skill_meta_repository: URL of skills repository containing metadata
:param branch: branch of repository to checkout
:param repo_metadata_path: Path to repo directory containing json metadata files
"""
skills_data = dict()
temp_download_dir = mkdtemp()
git.Repo.clone_from(skill_meta_repository, temp_download_dir, branch=branch)
NeonDaniel marked this conversation as resolved.
Show resolved Hide resolved
base_dir = join(temp_download_dir, repo_metadata_path)
for entry in listdir(base_dir):
with open(join(base_dir, entry)) as f:
skill_entry = json.load(f)
skills_data[normalize_github_url(skill_entry["url"])] = skill_entry
rmtree(temp_download_dir)
return skills_data


def install_skills_from_list(skills_to_install: list, config: dict = None):
"""
Installs the passed list of skill URLs
:param skills_to_install: list or skill URLs to install
:param skills_to_install: list of skill URLs to install
:param config: optional dict configuration
"""
config = config or get_neon_skills_config()
skill_dir = expanduser(config["directory"])
osm = OVOSSkillsManager()
skills_catalog = get_neon_skills_data()
token_set = False
if config.get("neon_token"):
token_set = True
set_github_token(config["neon_token"])
for url in skills_to_install:
try:
osm.install_skill_from_url(url, skill_dir)
normalized_url = normalize_github_url(url)
# Check if this skill is in the Neon list
if normalized_url in skills_catalog:
branch = get_branch_from_github_url(url)
# Set URL and branch to requested spec
skills_catalog[normalized_url]["url"] = normalized_url
skills_catalog[normalized_url]["branch"] = branch
entry = SkillEntry.from_json(skills_catalog.get(normalized_url), False)
else:
LOG.warning(f"Requested Skill not in Neon skill store ({url})")
entry = osm.skill_entry_from_url(url)
# try:
osm.install_skill(entry, skill_dir)
LOG.info(f"Installed {url} to {skill_dir}")
except Exception as e:
LOG.error(e)
Expand All @@ -70,8 +113,12 @@ def install_skills_default(config: dict = None):
def get_remote_entries(url):
""" parse url and return a list of SkillEntry,
expects 1 skill per line, can be a skill_id or url"""
r = requests.get(url)
if r.status_code == 200:
r = SESSION.get(url)
if not r.ok:
LOG.warning(f"Cached response returned: {r.status_code}")
SESSION.cache.delete_url(r.url)
r = requests.get(url)
if r.ok:
return [s for s in r.text.split("\n") if s.strip()]
else:
LOG.error(f"{url} request failed with code: {r.status_code}")
Expand Down
2 changes: 1 addition & 1 deletion test/test_run_neon.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ def test_audio_module(self):
# self.assertIsInstance(data["success"], bool)

def test_skills_module(self):
response = self.bus.wait_for_response(Message('mycroft.skills.is_ready'))
response = self.bus.wait_for_response(Message('mycroft.skills.is_ready'), timeout=10)
self.assertTrue(response.data['status'])

response = self.bus.wait_for_response(Message("skillmanager.list"), "mycroft.skills.list")
Expand Down
12 changes: 10 additions & 2 deletions test/test_skill_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
]
SKILL_DIR = os.path.join(os.path.dirname(__file__), "test_skills")
SKILL_CONFIG = {
"default_skills": "https://raw.githubusercontent.com/NeonGeckoCom/neon-skills-submodules/dev/.utilities/"
"default_skills": "https://raw.githubusercontent.com/NeonGeckoCom/neon_skills/master/skill_lists/"
"DEFAULT-SKILLS-DEV",
"neon_token": os.environ.get("GITHUB_TOKEN"),
"directory": SKILL_DIR
Expand Down Expand Up @@ -83,7 +83,15 @@ def test_install_skills_from_list_with_auth(self):
def test_install_skills_default(self):
install_skills_default(SKILL_CONFIG)
skill_dirs = [d for d in os.listdir(SKILL_DIR) if os.path.isdir(os.path.join(SKILL_DIR, d))]
self.assertEqual(len(skill_dirs), len(get_remote_entries(SKILL_CONFIG["default_skills"])), f"{skill_dirs}\n\n{get_remote_entries(SKILL_CONFIG['default_skills'])}")
self.assertEqual(len(skill_dirs), len(get_remote_entries(SKILL_CONFIG["default_skills"])),
f"{skill_dirs}\n\n{get_remote_entries(SKILL_CONFIG['default_skills'])}")

def test_get_neon_skills_data(self):
neon_skills = get_neon_skills_data()
self.assertIsInstance(neon_skills, dict)
for skill in neon_skills:
self.assertIsInstance(neon_skills[skill], dict)
self.assertEqual(skill, normalize_github_url(neon_skills[skill]["url"]))


if __name__ == '__main__':
Expand Down