Hello community,

here is the log from the commit of package python-msm for openSUSE:Factory 
checked in at 2019-02-04 14:25:00
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-msm (Old)
 and      /work/SRC/openSUSE:Factory/.python-msm.new.28833 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-msm"

Mon Feb  4 14:25:00 2019 rev:6 rq:670889 version:0.6.3

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-msm/python-msm.changes    2018-11-06 
14:31:44.305263738 +0100
+++ /work/SRC/openSUSE:Factory/.python-msm.new.28833/python-msm.changes 
2019-02-04 14:25:03.221063950 +0100
@@ -1,0 +2,29 @@
+Sat Feb  2 22:41:00 UTC 2019 - [email protected]
+
+- Update to python-msm 0.6.3
+  * Do not destroy the existing repo on git errors
+
+- Update to python-msm 0.6.2
+  * Convert booleans in installed field to 0
+
+- Update to python-msm 0.6.1
+  * Make sure saving_handled is reset
+  * Handle writing automatically
+
+- Update to python-msm 0.6.0
+  * Use existing installation/update times
+  * Only write skills data if the info has changed
+  * Fix update_deps() issue with constraints
+  * Fix handling of beta and cleanup
+  * Add process lock using fasteners
+  * Add handling of the skills.json file
+  * Updates returns True if an update occured
+  * Try to handle errors in the .skills-repo
+  * Add option to use pip constraints
+
+- Rebase patches:
+  * add-local-patch-support.patch
+  * do-not-run-pip-or-requirements-script.patch
+  * fix-skills-directories.patch
+
+-------------------------------------------------------------------

Old:
----
  msm-0.5.19.tar.gz

New:
----
  msm-0.6.3.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-msm.spec ++++++
--- /var/tmp/diff_new_pack.ovvQ57/_old  2019-02-04 14:25:03.785063683 +0100
+++ /var/tmp/diff_new_pack.ovvQ57/_new  2019-02-04 14:25:03.789063681 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python-msm
 #
-# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -19,7 +19,7 @@
 %define skip_python2 1
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-msm
-Version:        0.5.19
+Version:        0.6.3
 Release:        0
 Summary:        Mycroft Skills Manager
 License:        Apache-2.0
@@ -60,6 +60,7 @@
 %files %{python_files}
 %license LICENSE
 %python3_only %{_bindir}/msm
-%{python_sitelib}/*
+%{python_sitelib}/msm
+%{python_sitelib}/msm-%{version}-py%{python_version}.egg-info
 
 %changelog

++++++ add-local-patch-support.patch ++++++
--- /var/tmp/diff_new_pack.ovvQ57/_old  2019-02-04 14:25:03.813063670 +0100
+++ /var/tmp/diff_new_pack.ovvQ57/_new  2019-02-04 14:25:03.817063668 +0100
@@ -11,13 +11,13 @@
  
  LOG = logging.getLogger(__name__)
  
-@@ -242,6 +244,7 @@ class SkillEntry(object):
+@@ -256,6 +258,7 @@ class SkillEntry(object):
          try:
              move(tmp_location, self.path)
  
 +            apply_skill_patch(self.name, self.path)
              self.run_requirements_sh()
-             self.run_pip()
+             self.run_pip(constraints)
          finally:
 @@ -274,6 +277,7 @@ class SkillEntry(object):
          with git_to_msm_exceptions():

++++++ do-not-run-pip-or-requirements-script.patch ++++++
--- /var/tmp/diff_new_pack.ovvQ57/_old  2019-02-04 14:25:03.825063664 +0100
+++ /var/tmp/diff_new_pack.ovvQ57/_new  2019-02-04 14:25:03.825063664 +0100
@@ -9,8 +9,8 @@
 +        LOG.info("Please check manually the requirements file at " + 
requirements_file)
 +        return False
  
-         LOG.info('Installing requirements.txt for ' + self.name)
-         can_pip = os.access(dirname(sys.executable), os.W_OK | os.X_OK)
+         # Use constraints to limit the installed versions
+         if constraints and not exists(constraints):
 @@ -184,6 +186,8 @@ class SkillEntry(object):
          setup_script = join(self.path, "requirements.sh")
          if not exists(setup_script):

++++++ fix-skills-directories.patch ++++++
--- /var/tmp/diff_new_pack.ovvQ57/_old  2019-02-04 14:25:03.833063660 +0100
+++ /var/tmp/diff_new_pack.ovvQ57/_new  2019-02-04 14:25:03.833063660 +0100
@@ -69,14 +69,15 @@
 ===================================================================
 --- msm-0.5.17.orig/msm/mycroft_skills_manager.py
 +++ msm-0.5.17/msm/mycroft_skills_manager.py
-@@ -31,13 +31,14 @@ from msm import GitException
- from msm.exceptions import MsmException, SkillNotFound, MultipleSkillMatches
- from msm.skill_entry import SkillEntry
- from msm.skill_repo import SkillRepo
-+from msm.configuration import get_skills_directory
- 
- LOG = logging.getLogger(__name__)
+@@ -30,6 +30,7 @@ from msm import GitException
+ from typing import Dict, List
  
+ from msm import GitException
++from msm.configuration import get_skills_directory
+ from msm.exceptions import (MsmException, SkillNotFound, MultipleSkillMatches,
+                             AlreadyInstalled)
+ from msm.skill_entry import SkillEntry
+@@ -68,7 +69,7 @@ from msm import GitException
  
  class MycroftSkillsManager(object):
      SKILL_GROUPS = {'default', 'mycroft_mark_1', 'picroft', 'kde'}

++++++ msm-0.5.19.tar.gz -> msm-0.6.3.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/msm-0.5.19/PKG-INFO new/msm-0.6.3/PKG-INFO
--- old/msm-0.5.19/PKG-INFO     2018-08-28 13:37:00.000000000 +0200
+++ new/msm-0.6.3/PKG-INFO      2018-12-07 00:25:44.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 1.0
 Name: msm
-Version: 0.5.19
+Version: 0.6.3
 Summary: Mycroft Skills Manager
 Home-page: https://github.com/MycroftAI/mycroft-skills-manager
 Author: jarbasAI, Matthew Scholefield
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/msm-0.5.19/msm/__main__.py 
new/msm-0.6.3/msm/__main__.py
--- old/msm-0.5.19/msm/__main__.py      2018-08-28 13:22:08.000000000 +0200
+++ new/msm-0.6.3/msm/__main__.py       2018-12-07 00:25:28.000000000 +0100
@@ -63,6 +63,11 @@
     subparsers = parser.add_subparsers(dest='action')
     subparsers.required = True
 
+    def add_constraint_args(subparser):
+        subparser.add_argument('--constraints',
+                               help='limit the installed requirements using '
+                                    'a pip constraint.txt file.')
+
     def add_search_args(subparser, skill_is_optional=False):
         if skill_is_optional:
             subparser.add_argument('skill', nargs='?')
@@ -70,7 +75,9 @@
             subparser.add_argument('skill')
         subparser.add_argument('author', nargs='?')
 
-    add_search_args(subparsers.add_parser('install'))
+    install_parser = subparsers.add_parser('install')
+    add_search_args(install_parser)
+    add_constraint_args(install_parser)
     add_search_args(subparsers.add_parser('remove'))
     add_search_args(subparsers.add_parser('search'))
     add_search_args(subparsers.add_parser('info'))
@@ -90,7 +97,8 @@
         args.platform, args.skills_dir, repo, args.versioned
     )
     main_functions = {
-        'install': lambda: msm.install(args.skill, args.author),
+        'install': lambda: msm.install(args.skill, args.author,
+                                       args.constraints, 'cli'),
         'remove': lambda: msm.remove(args.skill, args.author),
         'list': lambda: '\n'.join(
             skill.name + (
@@ -108,18 +116,18 @@
         ),
         'info': lambda: skill_info(msm.find_skill(args.skill, args.author))
     }
-    try:
-        result = main_functions[args.action]()
-        if result is False:
-            return 1
-        if isinstance(result, str):
-            printer(result)
-        return 0
-    except MsmException as e:
-        exc_type = e.__class__.__name__
-        printer('{}: {}'.format(exc_type, str(e)))
-        return get_error_code(e.__class__)
-
+    with msm.lock:
+        try:
+            result = main_functions[args.action]()
+            if result is False:
+                return 1
+            if isinstance(result, str):
+                printer(result)
+            return 0
+        except MsmException as e:
+            exc_type = e.__class__.__name__
+            printer('{}: {}'.format(exc_type, str(e)))
+            return get_error_code(e.__class__)
 
 if __name__ == "__main__":
     main()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/msm-0.5.19/msm/mycroft_skills_manager.py 
new/msm-0.6.3/msm/mycroft_skills_manager.py
--- old/msm-0.5.19/msm/mycroft_skills_manager.py        2018-08-28 
13:22:08.000000000 +0200
+++ new/msm-0.6.3/msm/mycroft_skills_manager.py 2018-12-07 00:25:28.000000000 
+0100
@@ -24,16 +24,47 @@
 from itertools import chain
 from multiprocessing.pool import ThreadPool
 from os.path import expanduser, join, dirname, isdir
+from functools import wraps
+import time
 
 from typing import Dict, List
 
 from msm import GitException
-from msm.exceptions import MsmException, SkillNotFound, MultipleSkillMatches
+from msm.exceptions import (MsmException, SkillNotFound, MultipleSkillMatches,
+                            AlreadyInstalled)
 from msm.skill_entry import SkillEntry
 from msm.skill_repo import SkillRepo
+from msm.skills_data import (build_skill_entry, get_skill_entry,
+                             write_skills_data, load_skills_data,
+                             skills_data_hash)
+
+from msm.util import MsmProcessLock
 
 LOG = logging.getLogger(__name__)
 
+CURRENT_SKILLS_DATA_VERSION = 1
+
+
+def save_skills_data(func):
+    @wraps(func)
+    def func_wrapper(self, *args, **kwargs):
+        will_save = False
+        if not self.saving_handled:
+            will_save = self.saving_handled = True
+        try:
+            ret = func(self, *args, **kwargs)
+            # Write only if no exception occurs
+            if will_save:
+                self.write_skills_data()
+        finally:
+            # Always restore saving_handled flag
+            if will_save:
+                self.saving_handled = False
+
+        return ret
+
+    return func_wrapper
+
 
 class MycroftSkillsManager(object):
     SKILL_GROUPS = {'default', 'mycroft_mark_1', 'picroft', 'kde'}
@@ -46,30 +77,165 @@
                           or self.DEFAULT_SKILLS_DIR
         self.repo = repo or SkillRepo()
         self.versioned = versioned
+        self.lock = MsmProcessLock()
+
+        self.skills_data = None
+        self.saving_handled = False
+        with self.lock:
+            self.sync_skills_data()
+
+    def __upgrade_skills_data(self, skills_data):
+        new = {}
+        if skills_data.get('version', 0) == 0:
+            new['blacklist'] = []
+            new['version'] = 1
+            new['skills'] = []
+            local_skills = [s for s in self.list() if s.is_local]
+            default_skills = [s.name for s in self.list_defaults()]
+            for skill in local_skills:
+                if 'origin' in skills_data.get(skill.name, {}):
+                    origin = skills_data[skill.name]['origin']
+                elif skill.name in default_skills:
+                    origin = 'default'
+                elif skill.url:
+                    origin = 'cli'
+                else:
+                    origin = 'non-msm'
+                beta = skills_data.get(skill.name, {}).get('beta', False)
+                entry = build_skill_entry(skill.name, origin, beta)
+                entry['installed'] = \
+                    skills_data.get(skill.name, {}).get('installed') or 0
+                if isinstance(entry['installed'], bool):
+                    entry['installed'] = 0
+
+                entry['update'] = \
+                    skills_data.get(skill.name, {}).get('updated') or 0
+
+                new['skills'].append(entry)
+            new['upgraded'] = True
+        return new
+
+    def curate_skills_data(self, skills_data):
+        """ Sync skills_data with actual skills on disk. """
+        local_skills = [s for s in self.list() if s.is_local]
+        default_skills = [s.name for s in self.list_defaults()]
+        local_skill_names = [s.name for s in local_skills]
+        skills_data_skills = [s['name'] for s in skills_data['skills']]
+
+        # Check for skills that aren't in the list
+        for skill in local_skills:
+            if skill.name not in skills_data_skills:
+                if skill.name in default_skills:
+                    origin = 'default'
+                elif skill.url:
+                    origin = 'cli'
+                else:
+                    origin = 'non-msm'
+                entry = build_skill_entry(skill.name, origin, False)
+                skills_data['skills'].append(entry)
+
+        # Check for skills in the list that doesn't exist in the filesystem
+        remove_list = []
+        for s in skills_data.get('skills', []):
+            if (s['name'] not in local_skill_names and
+                    s['installation'] == 'installed'):
+                remove_list.append(s)
+        for skill in remove_list:
+            skills_data['skills'].remove(skill)
+        return skills_data
+
+    def load_skills_data(self) -> dict:
+        skills_data = load_skills_data()
+        if skills_data.get('version', 0) < CURRENT_SKILLS_DATA_VERSION:
+            skills_data = self.__upgrade_skills_data(skills_data)
+        else:
+            skills_data = self.curate_skills_data(skills_data)
+        return skills_data
+
+    def sync_skills_data(self):
+        """ Update internal skill_data_structure from disk. """
+        self.skills_data = self.load_skills_data()
+        if 'upgraded' in self.skills_data:
+            self.skills_data.pop('upgraded')
+            self.skills_data_hash = ''
+        else:
+            self.skills_data_hash = skills_data_hash(self.skills_data)
+
+    def write_skills_data(self, data=None):
+        """ Write skills data hash if it has been modified. """
+        data = data or self.skills_data
+        if skills_data_hash(data) != self.skills_data_hash:
+            write_skills_data(data)
 
-    def install(self, param, author=None):
+    @save_skills_data
+    def install(self, param, author=None, constraints=None, origin=''):
         """Install by url or name"""
-        self.find_skill(param, author).install()
+        if isinstance(param, SkillEntry):
+            skill = param
+        else:
+            skill = self.find_skill(param, author)
+        entry = build_skill_entry(skill.name, origin, skill.is_beta)
+        try:
+            skill.install(constraints)
+            entry['installed'] = time.time()
+            entry['installation'] = 'installed'
+            entry['status'] = 'active'
+        except AlreadyInstalled:
+            entry = None
+            raise
+        except MsmException as e:
+            entry['installation'] = 'failed'
+            entry['status'] = 'error'
+            entry['failure_message'] = repr(e)
+            raise
+        finally:
+            # Store the entry in the list
+            if entry:
+                self.skills_data['skills'].append(entry)
 
+    @save_skills_data
     def remove(self, param, author=None):
         """Remove by url or name"""
-        self.find_skill(param, author).remove()
+        if isinstance(param, SkillEntry):
+            skill = param
+        else:
+            skill = self.find_skill(param, author)
+        skill.remove()
+        skills = [s for s in self.skills_data['skills']
+                  if s['name'] != skill.name]
+        self.skills_data['skills'] = skills
+        return
 
     def update_all(self):
         local_skills = [skill for skill in self.list() if skill.is_local]
 
         def update_skill(skill):
-            skill.update()
+            entry = get_skill_entry(skill.name, self.skills_data)
+            if entry:
+                entry['beta'] = skill.is_beta
+            if skill.update():
+                if entry:
+                    entry['updated'] = time.time()
 
         return self.apply(update_skill, local_skills)
 
+    @save_skills_data
     def update(self, skill=None, author=None):
         """Update all downloaded skills or one specified skill."""
         if skill is None:
             return self.update_all()
         else:
-            return self.find_skill(skill, author).update()
+            if isinstance(skill, str):
+                skill = self.find_skill(skill, author)
+            entry = get_skill_entry(skill.name, self.skills_data)
+            if entry:
+                entry['beta'] = skill.is_beta
+            if skill.update():
+                # On successful update update the update value
+                if entry:
+                    entry['updated'] = time.time()
 
+    @save_skills_data
     def apply(self, func, skills):
         """Run a function on all skills in parallel"""
 
@@ -88,16 +254,16 @@
                 ))
 
         with ThreadPool(100) as tp:
-            return all(tp.map(run_item, skills))
+            return (tp.map(run_item, skills))
 
+    @save_skills_data
     def install_defaults(self):
         """Installs the default skills, updates all others"""
-
         def install_or_update_skill(skill):
             if skill.is_local:
-                skill.update()
+                self.update(skill)
             else:
-                skill.install()
+                self.install(skill, origin='default')
 
         return self.apply(install_or_update_skill, self.list_defaults())
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/msm-0.5.19/msm/skill_entry.py 
new/msm-0.6.3/msm/skill_entry.py
--- old/msm-0.5.19/msm/skill_entry.py   2018-08-28 13:22:08.000000000 +0200
+++ new/msm-0.6.3/msm/skill_entry.py    2018-11-14 14:28:24.000000000 +0100
@@ -46,6 +46,8 @@
 # TODO Make this configurable
 SWITCHABLE_BRANCHES = ['master']
 
+# default constraints to use if no are given
+DEFAULT_CONSTRAINTS = '/etc/mycroft/constraints.txt'
 
 @contextmanager
 def work_dir(directory):
@@ -71,6 +73,13 @@
         self.id = self.extract_repo_id(url) if url else name
         self.is_local = exists(path)
 
+    @property
+    def is_beta(self):
+        return not self.sha or self.sha == 'HEAD'
+
+    def __str__(self):
+        return self.name
+
     def attach(self, remote_entry):
         """Attach a remote entry to a local entry"""
         self.name = remote_entry.name
@@ -150,16 +159,25 @@
                 sum(weight for weight, val in weights)
         )
 
-    def run_pip(self):
+    def run_pip(self, constraints):
         requirements_file = join(self.path, "requirements.txt")
         if not exists(requirements_file):
             return False
 
+        # Use constraints to limit the installed versions
+        if constraints and not exists(constraints):
+            LOG.error('Couldn\'t find the constraints file')
+            return False
+        elif exists(DEFAULT_CONSTRAINTS):
+            constraints = DEFAULT_CONSTRAINTS
+
         LOG.info('Installing requirements.txt for ' + self.name)
         can_pip = os.access(dirname(sys.executable), os.W_OK | os.X_OK)
         pip_args = [
             sys.executable, '-m', 'pip', 'install', '-r', requirements_file
         ]
+        if constraints:
+            pip_args += ['-c', constraints]
 
         if not can_pip:
             pip_args = ['sudo', '-n'] + pip_args
@@ -215,7 +233,7 @@
         with open(reqs, "r") as f:
             return [i.strip() for i in f.readlines() if i.strip()]
 
-    def install(self):
+    def install(self, constraints=None):
         if self.is_local:
             raise AlreadyInstalled(self.name)
 
@@ -239,7 +257,7 @@
             move(tmp_location, self.path)
 
             self.run_requirements_sh()
-            self.run_pip()
+            self.run_pip(constraints)
         finally:
             if isfile(join(self.path, '__init__')):
                 move(join(self.path, '__init__'),
@@ -247,11 +265,11 @@
 
         LOG.info('Successfully installed ' + self.name)
 
-    def update_deps(self):
+    def update_deps(self, constraints=None):
         if self.msm:
             self.run_skill_requirements()
         self.run_requirements_sh()
-        self.run_pip()
+        self.run_pip(constraints)
 
     def _find_sha_branch(self):
         git = Git(self.path)
@@ -291,8 +309,10 @@
             LOG.info('Updated ' + self.name)
             # Trigger reload by modifying the timestamp
             os.utime(join(self.path, '__init__.py'))
+            return True
         else:
             LOG.info('Nothing new for ' + self.name)
+            return False
 
     def remove(self):
         if not self.is_local:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/msm-0.5.19/msm/skill_repo.py 
new/msm-0.6.3/msm/skill_repo.py
--- old/msm-0.5.19/msm/skill_repo.py    2018-08-28 13:22:08.000000000 +0200
+++ new/msm-0.6.3/msm/skill_repo.py     2018-12-07 00:25:28.000000000 +0100
@@ -24,7 +24,7 @@
 from os.path import exists, join, isdir, dirname, basename
 
 from git import Repo
-from git.exc import GitCommandError
+from git.exc import GitCommandError, GitError
 
 from msm import git_to_msm_exceptions
 from msm.exceptions import MsmException
@@ -45,17 +45,16 @@
         with open(join(self.path, filename)) as f:
             return f.read()
 
-    def update(self):
+    def __prepare_repo(self):
         if not exists(dirname(self.path)):
             makedirs(dirname(self.path))
 
-        with git_to_msm_exceptions():
-            if not isdir(self.path):
-                Repo.clone_from(self.url, self.path)
-
-            git = Git(self.path)
-            git.config('remote.origin.url', self.url)
-            git.fetch()
+        if not isdir(self.path):
+            Repo.clone_from(self.url, self.path)
+
+        git = Git(self.path)
+        git.config('remote.origin.url', self.url)
+        git.fetch()
 
         try:
             git.checkout(self.branch)
@@ -63,6 +62,24 @@
         except GitCommandError:
             raise MsmException('Invalid branch: ' + self.branch)
 
+    def update(self):
+        try:
+            self.__prepare_repo()
+        except GitError as e:
+            LOG.warning('Could not prepare repo ({}), '
+                        ' Creating temporary repo'.format(repr(e)))
+            original_path = self.path
+            self.path = '/tmp/.skills-repo'
+            try:
+                with git_to_msm_exceptions():
+                    self.__prepare_repo()
+            except Exception:
+                LOG.warning('Could not use temporary repo either ({}), '
+                            ' trying to use existing one without '
+                            'update'.format(repr(e)))
+                self.path = original_path  # Restore path to previous value
+                raise
+
     def get_skill_data(self):
         """ generates tuples of name, path, url, sha """
         path_to_sha = {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/msm-0.5.19/msm/skills_data.py 
new/msm-0.6.3/msm/skills_data.py
--- old/msm-0.5.19/msm/skills_data.py   1970-01-01 01:00:00.000000000 +0100
+++ new/msm-0.6.3/msm/skills_data.py    2018-11-14 14:28:24.000000000 +0100
@@ -0,0 +1,55 @@
+"""
+    Functions related to manipulating the skills_data.json
+"""
+
+from os.path import expanduser, isfile
+import json
+
+def load_skills_data() -> dict:
+    """Contains info on how skills should be updated"""
+    skills_data_file = expanduser('~/.mycroft/skills.json')
+    if isfile(skills_data_file):
+        try:
+            with open(skills_data_file) as f:
+                return json.load(f)
+        except json.JSONDecodeError:
+            return {}
+    else:
+        return {}
+
+def write_skills_data(data: dict):
+    skills_data_file = expanduser('~/.mycroft/skills.json')
+    with open(skills_data_file, 'w') as f:
+        json.dump(data, f, indent=4, separators=(',',':'))
+
+def get_skill_entry(name, skills_data) -> dict:
+    """ Find a skill entry in the skills_data and returns it. """
+    for e in skills_data.get('skills', []):
+        if e.get('name') == name:
+            return e
+    return None
+
+
+def build_skill_entry(name, origin, beta) -> dict:
+    """ Create a new skill entry
+    
+    Arguments:
+        name: skill name
+        origin: the source of the installation
+        beta: Boolean indicating wether the skill is in beta
+    Returns:
+        populated skills entry
+    """
+    entry = {}
+    entry['name'] = name
+    entry['origin'] = origin
+    entry['beta'] = beta
+    entry['status'] = 'active'
+    entry['installed'] = 0
+    entry['updated'] = 0
+    entry['installation'] = 'installed'
+    return entry
+
+
+def skills_data_hash(data):
+    return hash(json.dumps(data, sort_keys=True))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/msm-0.5.19/msm/util.py new/msm-0.6.3/msm/util.py
--- old/msm-0.5.19/msm/util.py  2018-08-28 13:22:08.000000000 +0200
+++ new/msm-0.6.3/msm/util.py   2018-11-14 14:28:24.000000000 +0100
@@ -20,7 +20,9 @@
 # specific language governing permissions and limitations
 # under the License.
 import git
-
+from os.path import exists
+from os import chmod
+from fasteners.process_lock import InterProcessLock
 
 class Git(git.cmd.Git):
     """Prevents asking for password for private repos"""
@@ -32,3 +34,13 @@
             env.update(self.env)
             return super(Git, self).__getattr__(item)(*args, env=env, **kwargs)
         return wrapper
+
+
+class MsmProcessLock(InterProcessLock):
+    def __init__(self):
+        lock_path = '/tmp/msm_lock'
+        if not exists(lock_path):
+            lock_file = open(lock_path, '+w')
+            lock_file.close()
+            chmod(lock_path, 0o777)
+        super().__init__(lock_path)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/msm-0.5.19/msm.egg-info/PKG-INFO 
new/msm-0.6.3/msm.egg-info/PKG-INFO
--- old/msm-0.5.19/msm.egg-info/PKG-INFO        2018-08-28 13:37:00.000000000 
+0200
+++ new/msm-0.6.3/msm.egg-info/PKG-INFO 2018-12-07 00:25:44.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 1.0
 Name: msm
-Version: 0.5.19
+Version: 0.6.3
 Summary: Mycroft Skills Manager
 Home-page: https://github.com/MycroftAI/mycroft-skills-manager
 Author: jarbasAI, Matthew Scholefield
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/msm-0.5.19/msm.egg-info/SOURCES.txt 
new/msm-0.6.3/msm.egg-info/SOURCES.txt
--- old/msm-0.5.19/msm.egg-info/SOURCES.txt     2018-08-28 13:37:00.000000000 
+0200
+++ new/msm-0.6.3/msm.egg-info/SOURCES.txt      2018-12-07 00:25:44.000000000 
+0100
@@ -6,6 +6,7 @@
 msm/mycroft_skills_manager.py
 msm/skill_entry.py
 msm/skill_repo.py
+msm/skills_data.py
 msm/util.py
 msm.egg-info/PKG-INFO
 msm.egg-info/SOURCES.txt
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/msm-0.5.19/msm.egg-info/requires.txt 
new/msm-0.6.3/msm.egg-info/requires.txt
--- old/msm-0.5.19/msm.egg-info/requires.txt    2018-08-28 13:37:00.000000000 
+0200
+++ new/msm-0.6.3/msm.egg-info/requires.txt     2018-12-07 00:25:44.000000000 
+0100
@@ -1,2 +1,3 @@
 GitPython
 typing
+fasteners
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/msm-0.5.19/setup.py new/msm-0.6.3/setup.py
--- old/msm-0.5.19/setup.py     2018-08-28 13:22:08.000000000 +0200
+++ new/msm-0.6.3/setup.py      2018-12-07 00:25:28.000000000 +0100
@@ -23,9 +23,9 @@
 
 setup(
     name='msm',
-    version='0.5.19',
+    version='0.6.3',
     packages=['msm'],
-    install_requires=['GitPython', 'typing'],
+    install_requires=['GitPython', 'typing', 'fasteners'],
     url='https://github.com/MycroftAI/mycroft-skills-manager',
     license='Apache-2.0',
     author='jarbasAI, Matthew Scholefield',


Reply via email to