Mercurial > libervia-web
comparison 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 |
comparison
equal
deleted
inserted
replaced
1246:aaf28d45ae67 | 1247:a6c7f07f1e4d |
---|---|
15 | 15 |
16 # You should have received a copy of the GNU Affero General Public License | 16 # You should have received a copy of the GNU Affero General Public License |
17 # along with this program. If not, see <http://www.gnu.org/licenses/>. | 17 # along with this program. If not, see <http://www.gnu.org/licenses/>. |
18 import os | 18 import os |
19 import os.path | 19 import os.path |
20 from pathlib import Path | |
20 import importlib.util | 21 import importlib.util |
22 from twisted.internet import defer | |
21 from sat.core.log import getLogger | 23 from sat.core.log import getLogger |
22 from sat.core import exceptions | 24 from sat.core import exceptions |
23 from sat.core.i18n import _ | 25 from sat.core.i18n import _ |
24 from sat.tools import utils | 26 from sat.tools import utils |
25 from libervia.server.constants import Const as C | 27 from libervia.server.constants import Const as C |
28 from . import implicit | |
26 | 29 |
27 log = getLogger(__name__) | 30 log = getLogger(__name__) |
28 | 31 |
29 | 32 |
30 class TasksManager: | 33 class TasksManager: |
31 """Handle tasks of a Libervia site""" | 34 """Handle tasks of a Libervia site""" |
32 FILE_EXTS = {'py'} | |
33 | 35 |
34 def __init__(self, host, site_resource): | 36 def __init__(self, host, site_resource): |
35 """ | 37 """ |
36 @param site_resource(LiberviaRootResource): root resource of the site to manage | 38 @param site_resource(LiberviaRootResource): root resource of the site to manage |
37 """ | 39 """ |
38 self.host = host | 40 self.host = host |
39 self.resource = site_resource | 41 self.resource = site_resource |
40 self.tasks_dir = os.path.join(self.resource.site_path, C.TASKS_DIR) | 42 self.tasks_dir = self.site_path / C.TASKS_DIR |
41 self.tasks = {} | 43 self.tasks = {} |
42 self._build_path = None | 44 self._build_path = None |
43 self._current_task = None | 45 self._current_task = None |
44 | 46 |
45 @property | 47 @property |
46 def site_path(self): | 48 def site_path(self): |
47 return self.resource.site_path | 49 return Path(self.resource.site_path) |
48 | 50 |
49 @property | 51 @property |
50 def build_path(self): | 52 def build_path(self): |
51 """path where generated files will be build for this site""" | 53 """path where generated files will be build for this site""" |
52 if self._build_path is None: | 54 if self._build_path is None: |
75 else: | 77 else: |
76 if not value in allowed: | 78 if not value in allowed: |
77 raise ValueError(_("Unexpected value for {var}: {value!r}").format( | 79 raise ValueError(_("Unexpected value for {var}: {value!r}").format( |
78 var=var, value=value)) | 80 var=var, value=value)) |
79 | 81 |
80 async def parseTasks(self): | 82 async def parseTasksDir(self, dir_path): |
81 if not os.path.isdir(self.tasks_dir): | 83 log.debug(f"parsing tasks in {dir_path}") |
82 log.debug(_("{name} has no task to launch.").format( | 84 tasks_paths = sorted(dir_path.glob('task_*.py')) |
83 name = self.resource.site_name or "default site")) | 85 for task_path in tasks_paths: |
84 return | 86 if not task_path.is_file(): |
85 filenames = os.listdir(self.tasks_dir) | |
86 filenames.sort() | |
87 for filename in filenames: | |
88 filepath = os.path.join(self.tasks_dir, filename) | |
89 if not filename.startswith('task_') or not os.path.isfile(filepath): | |
90 continue | 87 continue |
91 task_name, ext = os.path.splitext(filename) | 88 task_name = task_path.stem[5:].lower().strip() |
92 task_name = task_name[5:].lower().strip() | |
93 if not task_name: | 89 if not task_name: |
94 continue | |
95 if ext[1:] not in self.FILE_EXTS: | |
96 continue | 90 continue |
97 if task_name in self.tasks: | 91 if task_name in self.tasks: |
98 raise exceptions.ConflictError( | 92 raise exceptions.ConflictError( |
99 "A task with the name [{name}] already exists".format( | 93 "A task with the name [{name}] already exists".format( |
100 name=task_name)) | 94 name=task_name)) |
95 log.debug(f"task {task_name} found") | |
101 module_name = f"{self.site_name}.task.{task_name}" | 96 module_name = f"{self.site_name}.task.{task_name}" |
102 | 97 |
103 spec = importlib.util.spec_from_file_location(module_name, filepath) | 98 spec = importlib.util.spec_from_file_location(module_name, task_path) |
104 task_module = importlib.util.module_from_spec(spec) | 99 task_module = importlib.util.module_from_spec(spec) |
105 spec.loader.exec_module(task_module) | 100 spec.loader.exec_module(task_module) |
106 task = task_module.Task(self) | 101 task = task_module.Task(self) |
107 self.tasks[task_name] = task | |
108 | |
109 | 102 |
110 # we launch prepare, which is a method used to prepare | 103 # we launch prepare, which is a method used to prepare |
111 # data at runtime (e.g. set WATCH_DIRS using config) | 104 # data at runtime (e.g. set WATCH_DIRS using config) |
112 try: | 105 try: |
113 prepare = task.prepare | 106 prepare = task.prepare |
114 except AttributeError: | 107 except AttributeError: |
115 pass | 108 pass |
116 else: | 109 else: |
117 await utils.asDeferred(prepare) | 110 try: |
111 await utils.asDeferred(prepare) | |
112 except exceptions.CancelError as e: | |
113 log.debug(f"Skipping {task_name} which cancelled itself: {e}") | |
114 continue | |
115 | |
116 self.tasks[task_name] = task | |
118 self.validateData(task) | 117 self.validateData(task) |
119 if self.host.options['dev_mode']: | 118 if self.host.options['dev_mode']: |
120 dirs = task.WATCH_DIRS or [] | 119 dirs = task.WATCH_DIRS or [] |
121 for dir_ in dirs: | 120 for dir_ in dirs: |
122 self.host.files_watcher.watchDir( | 121 self.host.files_watcher.watchDir( |
123 dir_, auto_add=True, recursive=True, | 122 dir_, auto_add=True, recursive=True, |
124 callback=self._autorunTask, task_name=task_name) | 123 callback=self._autorunTask, task_name=task_name) |
124 | |
125 async def parseTasks(self): | |
126 # implicit tasks are always run | |
127 implicit_path = Path(implicit.__file__).parent | |
128 await self.parseTasksDir(implicit_path) | |
129 # now we check if there are tasks specific to this site | |
130 if not self.tasks_dir.is_dir(): | |
131 log.debug(_("{name} has no task to launch.").format( | |
132 name = self.resource.site_name or "default site")) | |
133 return | |
134 else: | |
135 await self.parseTasksDir(self.tasks_dir) | |
125 | 136 |
126 def _autorunTask(self, host, filepath, flags, task_name): | 137 def _autorunTask(self, host, filepath, flags, task_name): |
127 """Called when an event is received from a watched directory""" | 138 """Called when an event is received from a watched directory""" |
128 if flags == ['create']: | 139 if flags == ['create']: |
129 return | 140 return |