def install_skill(self, skill: SkillEntry, folder=None): """ Installs a SkillEntry with any required auth_token :param skill: Skill to install :param folder: Skills directory to install to (skill unpacked to {folder}/{skill.uuid}) """ self.emit("osm.install.start", {"folder": folder, "skill": skill.json}) store = None try: self.validate_appstore_name(skill.appstore) store = self.get_appstore(skill.appstore) store.authenticate(bootstrap=False) except Exception as e: LOG.error(e) self.emit("osm.install.error", { "folder": folder, "skill": skill.json, "error": str(e) }) try: skill.install(folder) except Exception as e: LOG.error(e) self.emit("osm.install.error", { "folder": folder, "skill": skill.json, "error": str(e) }) if store: store.clear_authentication() self.emit("osm.install.finish", { "folder": folder, "skill": skill.json })
def search_skills_by_tag(self, tag, as_json=False, fuzzy=True, thresh=0.85, ignore_case=True): query = Query(self.db) query.contains_value('tags', tag, fuzzy, thresh, ignore_case) results = query.result for idx in range(0, len(results)): if "appstore" not in results[idx]: results[idx]["appstore"] = self.appstore_id if as_json: return query.result return [SkillEntry.from_json(s, False) for s in results]
def search_skills_by_description(self, value, as_json: bool = False, fuzzy: bool = True, thresh=0.85, ignore_case: bool = True): query = Query(self.db) query.value_contains_token('description', value, fuzzy, thresh, ignore_case) results = query.result for idx in range(0, len(results)): if "appstore" not in results[idx]: results[idx]["appstore"] = self.appstore_id if as_json: return query.result return [SkillEntry.from_json(s, False) for s in results]
def search_skills_by_author(self, authorname: str, as_json=False, fuzzy=True, thresh: float = 0.85, ignore_case=True): query = Query(self.db) query.value_contains_token('authorname', authorname, fuzzy, thresh, ignore_case) results = query.result for idx in range(0, len(results)): if "appstore" not in results[idx]: results[idx]["appstore"] = self.appstore_id if as_json: return query.result return [SkillEntry.from_json(s, False) for s in results]
def install(method: str, skill: str, fuzzy: bool, no_ignore_case: bool, thresh: float, appstore: str, search: bool, branch: str, folder: str): if search: skills = search_skill(method, skill, fuzzy, no_ignore_case, thresh, appstore) elif not skill.startswith("http"): click.confirm('{s} does not look like a valid skill url, do you ' 'want to enable search?'.format(s=skill), abort=True) skills = search_skill(method, skill, fuzzy, no_ignore_case, thresh, appstore) else: skills = [SkillEntry.from_github_url(skill, branch)] if not len(skills): click.echo("NO RESULTS") else: # ask option prompt = "\nSearch Results:\n appstore - branch - url \n" opts = {} for s in skills: idx = len(opts) + 1 prompt += str(idx) + " - " + s.appstore + " - " + s.branch + " " +\ s.url + "\n" opts[idx] = s prompt += "0 - cancel installation\n" def ask_selection(): click.echo(prompt) value = click.prompt('Select an option', type=int) if value < 0 or value > len(opts): click.echo("Invalid choice") return ask_selection() return value value = ask_selection() if value == 0: click.echo("Installation cancelled") return skill = opts[value] skill_str = skill.branch + " " + skill.url click.confirm('Do you want to install {s} ?'.format(s=skill_str), abort=True) skill.install(folder)
def search_skills_by_url(self, url, as_json=False): query = Query(self.db) try: # if branch implicit in url, be sure to use it! branch = get_branch_from_github_url(url) except GithubInvalidBranch: branch = None url = normalize_github_url(url) query.equal("url", url, ignore_case=True) results = query.result for idx in range(0, len(results)): if "appstore" not in results[idx]: results[idx]["appstore"] = self.appstore_id if branch: # TODO what if branch does not exist? should throw exception results[idx]["branch"] = branch if as_json: return query.result return [SkillEntry.from_json(s, parse_github=False) for s in results]
def search_skills_by_id(self, skill_id, as_json=False, fuzzy=False, thresh=0.85, ignore_case=True): """ skill_id is repo.author , case insensitive, searchs by name and filters results by author """ name = ".".join(skill_id.split(".")[:-1]) author = skill_id.rsplit('.', 1)[1] query = Query(self.db) query.contains_value('skillname', name, fuzzy, thresh, ignore_case) query.value_contains_token('authorname', author, fuzzy, thresh, ignore_case) results = query.result for idx in range(0, len(results)): if "appstore" not in results[idx]: results[idx]["appstore"] = self.appstore_id if as_json: return query.result return [SkillEntry.from_json(s, False) for s in results]
def get_andlos_list_skills(parse_github: bool = False, skiplist=None): skiplist = skiplist or [] url = "https://raw.githubusercontent.com/andlo/mycroft-skills-list-gitbook/master/_data/skills.json" andlos_list = requests.get(url).json() for idx, skill in enumerate(andlos_list): LOG.debug("Parsing skill {i} out of {n}".format(i=idx, n=len(andlos_list))) s = skill['skill_info'] if s['repo'] in skiplist: continue cats = [s for s in s['categories'] if len(s) > 2] cat = cats[0] if len(cats) else None tags = list(set(s['tags'] + cats)) license = skill.get('license') or {} data = { "created": skill['created_at'], 'archived': skill['archived'], "license": license.get("key"), 'modified': skill['updated_at'], "authorname": s['github_username'], "skillname": s['name'], "foldername": s['id'], "name": s['name'], "url": s['repo'], 'category': cat, "description": s['description'], "short_description": s['short_desc'], "branch": s['branch'], "examples": s['examples'], 'tags': tags, 'platforms': s['platforms'], 'stars': skill['stargazers_count'] } try: yield SkillEntry.from_json(data, parse_github) except GithubInvalidUrl: LOG.error("this skill does not seem to be valid! " + s['repo'])
def skill_entry_from_url(url: str): """ Builds a minimal SkillEntry object from the passed GitHub URL to use for skill installation :param url: URL of skill to install :return: SkillEntry object with url, branch, requirements, and authorname populated """ from ovos_skills_manager.exceptions import GithubInvalidBranch, GithubFileNotFound from ovos_skills_manager.github import get_branch_from_github_url, normalize_github_url, get_requirements_json,\ get_skill_json from ovos_skills_manager.skill_entry import SkillEntry try: branch = get_branch_from_github_url(url) except GithubInvalidBranch: branch = None url = normalize_github_url(url) requirements = get_requirements_json(url, branch) requirements["system"] = { k: v.split() for k, v in requirements.get("system", {}).items() } try: json = get_skill_json(url, branch) requirements = merge_dict(requirements, json.get("requirements", {}), merge_lists=True, skip_empty=True, no_dupes=True) except GithubFileNotFound: json = {"authorname": author_repo_from_github_url(url)[0]} return SkillEntry.from_json( { "url": url, "branch": branch, "requirements": requirements, "authorname": json.get("authorname") }, False)
def __iter__(self): for s in self.db: yield SkillEntry.from_json(s, parse_github=False)
from ovos_skills_manager import SkillEntry # from github url with json available (all urls work) url = "https://github.com/JarbasSkills/skill-wolfie/blob/master/__init__.py" url = "https://github.com/JarbasSkills/skill-wolfie/blob/v0.1/res/desktop/skill.json" url = "https://raw.githubusercontent.com/JarbasSkills/skill-wolfie/v0.1/res/desktop/skill.json" url = "https://github.com/JarbasSkills/skill-wolfie" s = SkillEntry.from_github_url(url) print(s.json) # from github url with no .json available url = "https://github.com/MycroftAI/skill-hello-world" s = SkillEntry.from_github_url(url) print(s.json) # from github url + implicit branch with json available url = "https://github.com/MycroftAI/skill-hello-world/tree/20.08" s = SkillEntry.from_github_url(url) print(s.json) # parse .json from github url to file (all urls work assuming json in standard location) url = "https://github.com/JarbasSkills/skill-wolfie/blob/master/__init__.py" url = "https://github.com/JarbasSkills/skill-wolfie" url = "https://raw.githubusercontent.com/JarbasSkills/skill-wolfie/v0.1/res/desktop/skill.json" url = "https://github.com/JarbasSkills/skill-wolfie/blob/v0.1/res/desktop/skill.json" s = SkillEntry.from_json(url) print(s.json) # parse .json from github url to file (json not available) url = "https://github.com/AIIX/youtube-skill" s = SkillEntry.from_json(url)
from ovos_skills_manager import SkillEntry # from github url + implicit branch with json available url = "https://github.com/MycroftAI/skill-hello-world/tree/20.08" s = SkillEntry.from_github_url(url) print(s.generate_readme()) print(s.generate_desktop_file())
from ovos_skills_manager import SkillEntry skills_folder = "installed_skills" # skill requirements, branch not specified c url = "https://github.com/JarbasSkills/mycroft-node-red" s = SkillEntry.from_github_url(url, "master") updated = s.install(skills_folder) print("skill updated:", updated) # from github url + implicit branch with json available url = "https://github.com/MycroftAI/skill-hello-world/tree/20.08" s = SkillEntry.from_github_url(url) updated = s.install(skills_folder) print("skill updated:", updated) updated = s.update(skills_folder) print("skill updated:", updated) # test requirements.txt url = "https://github.com/JarbasSkills/skill-wolfie" s = SkillEntry.from_github_url(url) updated = s.install(skills_folder) print("skill updated:", updated) # test manifest.yml # NOTE most likely baresip install will fail because it needs sudo url = "https://github.com/JarbasSkills/skill-voip" s = SkillEntry.from_github_url(url) updated = s.install(skills_folder) print("skill updated:", updated)