Don't reload skill if a mod time is in the future
This stops a skill from being reloaded repeatedly if a file gets a bad
modification time.
It also logs the offending files in the error message.
@@ -73,6 +73,19 @@ def load_skill_module(path, skill_id):
return mod
+def _bad_mod_times(mod_times):
+ """Return all entries with modification time in the future.
+
+ Arguments:
+ mod_times (dict): dict mapping file paths to modification times.
+
+ Returns:
+ List of files with bad modification times.
+ """
+ current_time = time()
+ return [path for path in mod_times if mod_times[path] > current_time]
+
+
def _get_last_modified_time(path):
"""Get the last modified date of the most recently updated file in a path.
@@ -99,6 +112,11 @@ def _get_last_modified_time(path):
all_files.append(os.path.join(root_dir, f))
# check files of interest in the skill root directory
+ mod_times = {f: os.path.getmtime(f) for f in all_files}
+ # Ensure modification times are valid
+ bad_times = _bad_mod_times(mod_times)
+ if bad_times:
+ raise OSError('{} had bad modification times'.format(bad_times))
if all_files:
return max(os.path.getmtime(f) for f in all_files)
else:
@@ -118,6 +136,8 @@ class SkillLoader:
self.active = True
self.config = Configuration.get()
+ self.modtime_error_log_written = False
+
@property
def is_blacklisted(self):
"""Boolean value representing whether or not a skill is blacklisted."""
@@ -135,10 +155,14 @@ class SkillLoader:
"""
try:
self.last_modified = _get_last_modified_time(self.skill_directory)
- except FileNotFoundError as e:
- LOG.error('Failed to get last_modification time '
- '({})'.format(repr(e)))
+ except OSError as err:
self.last_modified = self.last_loaded
+ if not self.modtime_error_log_written:
+ self.modtime_error_log_written = True
+ LOG.error('Failed to get last_modification time '
+ '({})'.format(repr(err)))
+ else:
+ self.modtime_error_log_written = False
modified = self.last_modified > self.last_loaded
