예제 #1
0
    def install_from_giturl(self, message):
        git_link = message.data["skillurl"]
        git_branch = message.data["skillbranch"]
        if git_link:
            LOG.info("installing skill" + git_link)
            repo_name = SkillEntry.extract_repo_name(git_link)
            try:
                self.gui['process'] = True
                self.gui['processmessage'] = "installing skill"
                self.msm.install(git_link)
                self.update_home_screen()
                hashomepage = self.check_skill_for_home(git_link)
                if hashomepage:
                    self.check_android_entry_exist_with_home(git_link, message)
                else:
                    self.check_android_entry_exist_without_home(
                        git_link, message)

            except MsmException as e:
                self.gui['process'] = False
                self.gui['processmessage'] = ""
                LOG.info('msm failed: ' + repr(e))

        if git_branch:
            repo_name = SkillEntry.extract_repo_name(git_link)
            repo_author = SkillEntry.extract_author(git_link)
            skill_path = "/opt/mycroft/skills/" + repo_name + "." + repo_author.lower(
            )
            process = subprocess.popen(["git", "checkout", git_branch],
                                       stdout=subprocess.pipe,
                                       cwd=skill_path)
            output = process.communicate()[0]
            LOG.info(output)
예제 #2
0
    def install_from_giturl(self, message):
        gitLink = message.data["downloadLink"]
        gitBranch = message.data["branch"]
        if gitLink:
            LOG.info("installing skill" + gitLink)
            repo_name = SkillEntry.extract_repo_name(gitLink)
            try:
                self.gui['process'] = True
                self.gui['processMessage'] = "Installing Skill"
                self.msm.install(gitLink)
                self.update_home_screen()
            except MsmException as e:
                self.gui['process'] = False
                self.gui['processMessage'] = ""
                LOG.info('MSM failed: ' + repr(e))

        if gitBranch:
            repo_name = SkillEntry.extract_repo_name(gitLink)
            repo_author = SkillEntry.extract_author(gitLink)
            skill_path = "/opt/mycroft/skills/" + repo_name + "." + repo_author.lower(
            )
            process = subprocess.Popen(["git", "checkout", gitBranch],
                                       stdout=subprocess.PIPE,
                                       cwd=skill_path)
            output = process.communicate()[0]
            LOG.info(output)
 def setup(self):
     self.root = dirname(abspath(__file__))
     self.url = 'https://github.com/testuser/testrepo.git/'
     self.entry = SkillEntry(
         'test-name',
         'test-path',
         url='https://github.com/testuser/testrepo.git/')
예제 #4
0
def generate_summary(github: Github, skill_entry: SkillEntry):
    author = skill_entry.extract_author(skill_entry.url)
    repo_name = skill_entry.extract_repo_name(skill_entry.url)
    repo_id = '/'.join([author, repo_name])
    repo = github.get_repo(repo_id)  # type: Repository
    readme_file = repo.get_readme()  # type: ContentFile
    readme = readme_file.decoded_content.decode()
    sections = extract_sections(readme)
    title, short_desc = find_title_info(sections, skill_entry.name)

    return {
        'repo':
        repo.html_url,
        'title':
        title,
        'name':
        skill_entry.name,
        'author':
        (find_section('credits', sections, 0.9)
         or find_section('author', sections, 0.9) or caps(skill_entry.author)),
        'github_username':
        skill_entry.author,
        'short_desc':
        format_sent(short_desc.replace('\n', ' ')).rstrip('.'),
        'description':
        format_sent(find_section('description', sections) or ''),
        'examples': [parse_example(i) for i in find_examples(sections)],
        'requires': (find_section('require', sections, 0.9) or '').split(),
        'excludes': (find_section('exclude', sections, 0.9) or '').split()
    }
예제 #5
0
 def check_android_entry_exist_without_home(self, url, message):
     repo_name = SkillEntry.extract_repo_name(url)
     repo_author = SkillEntry.extract_author(url)
     android_json = "android.json"
     android_path = "/opt/mycroft/skills/" + repo_name + "." + repo_author.lower(
     ) + "/" + android_json
     if not path.exists(android_path) and not path.isfile(android_path):
         LOG.info("Android File Not Exist")
예제 #6
0
 def check_android_entry_exist_with_home(self, url, message):
     repo_name = SkillEntry.extract_repo_name(url)
     repo_author = SkillEntry.extract_author(url)
     android_json = "android.json"
     android_path = "/opt/mycroft/skills/" + repo_name + "." + repo_author.lower(
     ) + "/" + android_json
     if not path.exists(android_path) and not path.isfile(android_path):
         LOG.info("Android File Does Not Exist Creating Android With Home")
         self.build_android_json_with_home(message.data["skillImage"],
                                           message.data["skillName"],
                                           repo_name, repo_author)
예제 #7
0
 def checkInstalled(self, url):
     repo_name = SkillEntry.extract_repo_name(url)
     repo_author = SkillEntry.extract_author(url)
     skill_path = "/opt/mycroft/skills/" + repo_name + "." + repo_author.lower(
     )
     LOG.info(skill_path)
     if path.exists(skill_path):
         LOG.info("Found Skill Installed")
         return True
     else:
         LOG.info("Skill Not Installed")
         return False
예제 #8
0
 def check_skill_for_home(self, url):
     repo_name = SkillEntry.extract_repo_name(url)
     repo_author = SkillEntry.extract_author(url)
     check_file = "/opt/mycroft/skills/" + repo_name + "." + repo_author.lower(
     ) + "/__init__.py"
     LOG.info(check_file)
     home_string = [".home"]
     with open(check_file) as f:
         results = {word: [] for word in home_string}
         for num, line in enumerate(f, start=1):
             for word in home_string:
                 if word in line:
                     LOG.info("Home Entry Found")
                     return True
예제 #9
0
 def __init__(self, args):
     folder = abspath(expanduser(args.skill_folder))
     self.entry = SkillEntry.from_folder(folder)
     skills_dir = abspath(expanduser(self.msm.skills_dir))
     if join(skills_dir, basename(folder)) != folder:
         raise MskException('Skill folder, {}, not directly within skills directory, {}.'.format(
             args.skill_folder, self.msm.skills_dir
         ))
 def test_attach(self):
     """Attach a remote entry to a local entry"""
     remote = SkillEntry('test-name2',
                         'test-path2',
                         url='https://github.com/testname/testrepo2.git/')
     self.entry.is_local = True
     self.entry.attach(remote)
     assert self.entry.url == remote.url
     assert self.entry.path == 'test-path'
     assert self.entry.is_local
예제 #11
0
 def uninstall_from_giturl(self, message):
     gitLink = message.data["downloadLink"]
     if gitLink:
         repo_name = SkillEntry.extract_repo_name(gitLink)
         try:
             self.gui['process'] = True
             self.gui['processMessage'] = "Removing Skill"
             self.msm.remove(gitLink)
             self.update_home_screen()
         except MsmException as e:
             self.gui['process'] = False
             self.gui['processMessage'] = ""
             LOG.info('MSM failed: ' + repr(e))
예제 #12
0
def build_global_id(directory, config):
    """ Create global id for the skill.

    TODO: Handle dirty skill

    Arguments:
        directory:  skill directory
        config:     config for the device to fetch msm setup
     """
    # Update the msm object if it's more than an hour old
    global msm
    global msm_creation_time
    if msm is None or time.time() - msm_creation_time > 60 * 60:
        msm_creation_time = time.time()
        msm = create_msm(config)

    s = SkillEntry.from_folder(directory, msm)
    # If modified prepend the device uuid
    return s.skill_gid, s.meta_info.get('display_name')
예제 #13
0
    def on_web_settings_change(self):
        s = self.settings
        link = s.get('installer_link')
        prev_link = s.get('previous_link')
        auto_install = s.get('auto_install')

        # Check if we should auto-install a skill due to web setting change
        if link and prev_link != link and auto_install:
            s['previous_link'] = link

            self.log.info('Installing from the web...')
            action = self.translate_list('action')[0]
            name = SkillEntry.extract_repo_name(link)
            with self.handle_msm_errors(name, action):
                self.msm.install(link)

        to_install = s.get('to_install', [])
        if isinstance(to_install, str):
            to_install = json.loads(to_install)
        to_remove = s.get('to_remove', [])
        if isinstance(to_remove, str):
            to_remove = json.loads(to_remove)
        self.handle_marketplace(to_install, to_remove)
class TestSkillEntry(object):
    def setup(self):
        self.root = dirname(abspath(__file__))
        self.url = 'https://github.com/testuser/testrepo.git/'
        self.entry = SkillEntry(
            'test-name',
            'test-path',
            url='https://github.com/testuser/testrepo.git/')

    def test_https_init(self):
        s = SkillEntry('test-name',
                       'test-path',
                       url='https://github.com/testuser/testrepo.git/')
        assert s.author == 'testuser'

    def test_git_ssl_init(self):
        s = SkillEntry('test-name',
                       'test-path',
                       url='[email protected]:forslund/skill-cocktail.git')
        assert s.author == ''

    def test_attach(self):
        """Attach a remote entry to a local entry"""
        remote = SkillEntry('test-name2',
                            'test-path2',
                            url='https://github.com/testname/testrepo2.git/')
        self.entry.is_local = True
        self.entry.attach(remote)
        assert self.entry.url == remote.url
        assert self.entry.path == 'test-path'
        assert self.entry.is_local

    def test_from_folder(self):
        entry = SkillEntry.from_folder('test/folder')
        assert entry.name == 'folder'
        assert entry.url == ''

    def test_create_path(self):
        SkillEntry.create_path('myfolder', 'https://github.com/myname/myrepo')
        SkillEntry.create_path('myfolder', 'https://github.com/myname/myrepo',
                               'skillname')

    def test_extract_repo_name(self):
        assert SkillEntry.extract_repo_name(self.url) == 'testrepo'

    def test_extract_repo_id(self):
        assert SkillEntry.extract_repo_id(self.url) == 'testuser:testrepo'

    def test_match(self):
        assert self.entry.match('test-name') == 1.0
        assert self.entry.match('test-name', 'testuser') == 1.0
        assert self.entry.match('jsfaiasfa') < 0.5
        assert self.entry.match('test-name', 'fjasfa') < 1.0

    def test_run_pip(self):
        assert self.entry.run_pip() is False

    def test_run_requirements_sh(self):
        assert self.entry.run_requirements_sh() is False

    def test_run_skill_requirements(self):
        with pytest.raises(ValueError):
            self.entry.run_skill_requirements()

    def get_dependent_skills(self):
        reqs = join(self.path, "skill_requirements.txt")
        if not exists(reqs):
            return []

        with open(reqs, "r") as f:
            return [i.strip() for i in f.readlines() if i.strip()]

    def test_repr(self):
        str(self.entry)
예제 #15
0
def skill_repo_name(url: str):
    return '{}/{}'.format(SkillEntry.extract_author(url),
                          SkillEntry.extract_repo_name(url))
예제 #16
0
 def install_custom(self, message):
     link = self.settings.get('installer_link')
     if link:
         repo_name = SkillEntry.extract_repo_name(link)
         with self.handle_msm_errors(repo_name, self.install_word):
             self.msm.install(link, origin='')
 def test_extract_repo_id(self):
     assert SkillEntry.extract_repo_id(self.url) == 'testuser:testrepo'
 def test_extract_repo_name(self):
     assert SkillEntry.extract_repo_name(self.url) == 'testrepo'
 def test_create_path(self):
     SkillEntry.create_path('myfolder', 'https://github.com/myname/myrepo')
     SkillEntry.create_path('myfolder', 'https://github.com/myname/myrepo',
                            'skillname')
 def test_from_folder(self):
     entry = SkillEntry.from_folder('test/folder')
     assert entry.name == 'folder'
     assert entry.url == ''
 def test_git_ssl_init(self):
     s = SkillEntry('test-name',
                    'test-path',
                    url='[email protected]:forslund/skill-cocktail.git')
     assert s.author == ''
 def test_https_init(self):
     s = SkillEntry('test-name',
                    'test-path',
                    url='https://github.com/testuser/testrepo.git/')
     assert s.author == 'testuser'
예제 #23
0
def generate_summary(github: Github, skill_entry: SkillEntry):
    """
    Generate an entry for a Skill that has been accepted to the
    Mycroft Skills repo (https://github.com/mycroft-skills).

    {
       "mycroft-reminder": {
            # repo url
            "repo": "https://github.com/MycroftAI/skill-reminder",
            # branch of the repo
            "branch": "18.08",
            # Exact commit accepted
            "tree": "https://github.com/MycroftAI/skill-reminder/tree/afb9d3387e782de19fdf2ae9ec6d2e6c83fee48c",
            # name for the folder on disk, e.g. /opt/mycroft/skills/mycroft-reminder.mycroftai
            "name": "mycroft-reminder",
            "github_username": "******",

            # Used in titles and for 'Hey Mycroft, install ...'
            "title": "Set reminders",

            # One of the following two entries
            "icon" : {"name": "info", "color": "#22a7f0" },
            "icon_img" : "https://somewhere.org/picture.png",

            # List of credited contributors.  Some might not have a github_id
            # such as when crediting a song.
            "credits" : [
                {"name": "Mycroft AI", "github_id": "MycroftAI"},
                {"name": "Reminder tone from Tony of Tony's Sounds"}
            ],

            # The tagline description
            "short_desc": "Set single and repeating reminders for tasks",

            # The detailed description.  Can contain markdown
            "description": "Flexible reminder Skill, allowing you to set single and repeating reminders for tasks. The reminders are set on the Device, and have no external dependencies. ",

            # Example phrases.  Order counts, first is most representative.
            "examples": [
                "Set a reminder every day to take my vitamin pill.",
                "Remind me to put the garbage out at 8pm.",
                "Remind me to walk the dog in an hour.",
                "Set a reminder every Friday at 2pm.",
                "Remind me to stretch in 10 minutes."
            ],

            # Categories.  Order counts, first is the primary category.
            "categories": ["Daily","Productivity"],

            # Tags are arbitrary and order has no meaning.
            "tags": ["reminder", "reminders"],

            # Supported platforms by name, or "all"
            "platforms": ["platform_mark1"]
        }
    }
    """
    if github:
        author = skill_entry.extract_author(skill_entry.url)
        repo_name = skill_entry.extract_repo_name(skill_entry.url)
        repo_id = '/'.join([author, repo_name])
        repo = github.get_repo(repo_id)  # type: Repository
        repo_url = repo.html_url
        readme_file = repo.get_readme()  # type: ContentFile
        readme = readme_file.decoded_content.decode()
    else:
        readme = skill_entry.readme
        repo_url = "http://dummy.url"
    sections = extract_sections(readme)
    title, short_desc = find_title_info(sections, skill_entry.name)

    entry = {
        'repo': repo_url,
        # 'branch': "18.08",              # TODO: repo.branch,
        'tree': skill_entry.sha,
        'name': skill_entry.name,
        'github_username': skill_entry.author,

        'title': title,
        'short_desc': format_sentence(short_desc.replace('\n',
                                                         ' ')).rstrip('.'),
        'description': format_sentence(find_section('About', sections) or
                                       find_section('Description', sections) or
                                       ''),

        'examples': [parse_example(i) for i in find_examples(sections)],

        'credits': make_credits((find_section('Credits',
                                              sections, 0.9) or
                                 caps(skill_entry.author))),
        'categories': [
            cat.replace('*', '') for cat in sorted((find_section('Category',
                                                    sections,
                                                    0.9) or '').split())],
        'platforms': (find_section('Supported Devices',
                                   sections, 0.9) or 'all').split(),
        'tags': (find_section('Tags',
                              sections) or '').replace('#', '').split()
    }

    icon_url, icon_name, icon_color = find_icon(sections, repo_url,
                                                skill_entry.sha)
    if icon_url:
        entry["icon_img"] = icon_url
    elif icon_name:
        entry["icon"] = {"icon": icon_name, "color": icon_color}

    return entry