diff libervia/server/tasks/manager.py @ 1247:a6c7f07f1e4d

tasks: implicit tasks + Brython task: - implicit tasks are tasks launched for every site. - a first one is made for Brython: it will install Brython and copy suitable files and set template data if Brython code is written in page `_browser` subdirectory.
author Goffi <goffi@goffi.org>
date Sun, 26 Apr 2020 22:07:18 +0200
parents 079e8eb6e327
children 80a92eb82b7f
line wrap: on
line diff
--- a/libervia/server/tasks/manager.py	Sun Apr 26 22:01:13 2020 +0200
+++ b/libervia/server/tasks/manager.py	Sun Apr 26 22:07:18 2020 +0200
@@ -17,19 +17,21 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 import os
 import os.path
+from pathlib import Path
 import importlib.util
+from twisted.internet import defer
 from sat.core.log import getLogger
 from sat.core import exceptions
 from sat.core.i18n import _
 from sat.tools import utils
 from libervia.server.constants import Const as C
+from . import implicit
 
 log = getLogger(__name__)
 
 
 class TasksManager:
     """Handle tasks of a Libervia site"""
-    FILE_EXTS = {'py'}
 
     def __init__(self, host, site_resource):
         """
@@ -37,14 +39,14 @@
         """
         self.host = host
         self.resource = site_resource
-        self.tasks_dir = os.path.join(self.resource.site_path, C.TASKS_DIR)
+        self.tasks_dir = self.site_path / C.TASKS_DIR
         self.tasks = {}
         self._build_path = None
         self._current_task = None
 
     @property
     def site_path(self):
-        return self.resource.site_path
+        return Path(self.resource.site_path)
 
     @property
     def build_path(self):
@@ -77,35 +79,26 @@
                     raise ValueError(_("Unexpected value for {var}: {value!r}").format(
                         var=var, value=value))
 
-    async def parseTasks(self):
-        if not os.path.isdir(self.tasks_dir):
-            log.debug(_("{name} has no task to launch.").format(
-                name = self.resource.site_name or "default site"))
-            return
-        filenames = os.listdir(self.tasks_dir)
-        filenames.sort()
-        for filename in filenames:
-            filepath = os.path.join(self.tasks_dir, filename)
-            if not filename.startswith('task_') or not os.path.isfile(filepath):
+    async def parseTasksDir(self, dir_path):
+        log.debug(f"parsing tasks in {dir_path}")
+        tasks_paths = sorted(dir_path.glob('task_*.py'))
+        for task_path in tasks_paths:
+            if not task_path.is_file():
                 continue
-            task_name, ext = os.path.splitext(filename)
-            task_name = task_name[5:].lower().strip()
+            task_name = task_path.stem[5:].lower().strip()
             if not task_name:
                 continue
-            if ext[1:] not in self.FILE_EXTS:
-                continue
             if task_name in self.tasks:
                 raise exceptions.ConflictError(
                     "A task with the name [{name}] already exists".format(
                         name=task_name))
+            log.debug(f"task {task_name} found")
             module_name = f"{self.site_name}.task.{task_name}"
 
-            spec = importlib.util.spec_from_file_location(module_name, filepath)
+            spec = importlib.util.spec_from_file_location(module_name, task_path)
             task_module = importlib.util.module_from_spec(spec)
             spec.loader.exec_module(task_module)
             task = task_module.Task(self)
-            self.tasks[task_name] = task
-
 
             # we launch prepare, which is a method used to prepare
             # data at runtime (e.g. set WATCH_DIRS using config)
@@ -114,7 +107,13 @@
             except AttributeError:
                 pass
             else:
-                await utils.asDeferred(prepare)
+                try:
+                    await utils.asDeferred(prepare)
+                except exceptions.CancelError as e:
+                    log.debug(f"Skipping {task_name} which cancelled itself: {e}")
+                    continue
+
+            self.tasks[task_name] = task
             self.validateData(task)
             if self.host.options['dev_mode']:
                 dirs = task.WATCH_DIRS or []
@@ -123,6 +122,18 @@
                         dir_, auto_add=True, recursive=True,
                         callback=self._autorunTask, task_name=task_name)
 
+    async def parseTasks(self):
+        # implicit tasks are always run
+        implicit_path = Path(implicit.__file__).parent
+        await self.parseTasksDir(implicit_path)
+        # now we check if there are tasks specific to this site
+        if not self.tasks_dir.is_dir():
+            log.debug(_("{name} has no task to launch.").format(
+                name = self.resource.site_name or "default site"))
+            return
+        else:
+            await self.parseTasksDir(self.tasks_dir)
+
     def _autorunTask(self, host, filepath, flags, task_name):
         """Called when an event is received from a watched directory"""
         if flags == ['create']: