jolt 0.9.342__py3-none-any.whl → 0.9.429__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of jolt might be problematic. Click here for more details.
- jolt/__init__.py +47 -0
- jolt/cache.py +358 -159
- jolt/cli.py +71 -104
- jolt/config.py +14 -26
- jolt/filesystem.py +2 -2
- jolt/graph.py +56 -28
- jolt/influence.py +67 -2
- jolt/loader.py +150 -186
- jolt/log.py +12 -2
- jolt/manifest.py +0 -46
- jolt/options.py +35 -12
- jolt/pkgs/abseil.py +42 -0
- jolt/pkgs/asio.py +25 -0
- jolt/pkgs/autoconf.py +41 -0
- jolt/pkgs/automake.py +41 -0
- jolt/pkgs/b2.py +31 -0
- jolt/pkgs/boost.py +111 -0
- jolt/pkgs/boringssl.py +32 -0
- jolt/pkgs/busybox.py +39 -0
- jolt/pkgs/bzip2.py +43 -0
- jolt/pkgs/cares.py +29 -0
- jolt/pkgs/catch2.py +36 -0
- jolt/pkgs/cbindgen.py +17 -0
- jolt/pkgs/cista.py +19 -0
- jolt/pkgs/clang.py +44 -0
- jolt/pkgs/cli11.py +23 -0
- jolt/pkgs/cmake.py +48 -0
- jolt/pkgs/cpython.py +196 -0
- jolt/pkgs/crun.py +29 -0
- jolt/pkgs/curl.py +38 -0
- jolt/pkgs/dbus.py +18 -0
- jolt/pkgs/double_conversion.py +24 -0
- jolt/pkgs/fastfloat.py +21 -0
- jolt/pkgs/ffmpeg.py +28 -0
- jolt/pkgs/flatbuffers.py +29 -0
- jolt/pkgs/fmt.py +27 -0
- jolt/pkgs/fstree.py +20 -0
- jolt/pkgs/gflags.py +18 -0
- jolt/pkgs/glib.py +18 -0
- jolt/pkgs/glog.py +25 -0
- jolt/pkgs/glslang.py +21 -0
- jolt/pkgs/golang.py +16 -11
- jolt/pkgs/googlebenchmark.py +18 -0
- jolt/pkgs/googletest.py +46 -0
- jolt/pkgs/gperf.py +15 -0
- jolt/pkgs/grpc.py +73 -0
- jolt/pkgs/hdf5.py +19 -0
- jolt/pkgs/help2man.py +14 -0
- jolt/pkgs/inja.py +28 -0
- jolt/pkgs/jsoncpp.py +31 -0
- jolt/pkgs/libarchive.py +43 -0
- jolt/pkgs/libcap.py +44 -0
- jolt/pkgs/libdrm.py +44 -0
- jolt/pkgs/libedit.py +42 -0
- jolt/pkgs/libevent.py +31 -0
- jolt/pkgs/libexpat.py +27 -0
- jolt/pkgs/libfastjson.py +21 -0
- jolt/pkgs/libffi.py +16 -0
- jolt/pkgs/libglvnd.py +30 -0
- jolt/pkgs/libogg.py +28 -0
- jolt/pkgs/libpciaccess.py +18 -0
- jolt/pkgs/libseccomp.py +21 -0
- jolt/pkgs/libtirpc.py +24 -0
- jolt/pkgs/libtool.py +42 -0
- jolt/pkgs/libunwind.py +35 -0
- jolt/pkgs/libva.py +18 -0
- jolt/pkgs/libvorbis.py +33 -0
- jolt/pkgs/libxml2.py +35 -0
- jolt/pkgs/libxslt.py +17 -0
- jolt/pkgs/libyajl.py +16 -0
- jolt/pkgs/llvm.py +81 -0
- jolt/pkgs/lua.py +54 -0
- jolt/pkgs/lz4.py +26 -0
- jolt/pkgs/m4.py +14 -0
- jolt/pkgs/make.py +17 -0
- jolt/pkgs/mesa.py +81 -0
- jolt/pkgs/meson.py +17 -0
- jolt/pkgs/mstch.py +28 -0
- jolt/pkgs/mysql.py +60 -0
- jolt/pkgs/nasm.py +49 -0
- jolt/pkgs/ncurses.py +30 -0
- jolt/pkgs/ng_log.py +25 -0
- jolt/pkgs/ninja.py +45 -0
- jolt/pkgs/nlohmann_json.py +25 -0
- jolt/pkgs/nodejs.py +19 -11
- jolt/pkgs/opencv.py +24 -0
- jolt/pkgs/openjdk.py +26 -0
- jolt/pkgs/openssl.py +103 -0
- jolt/pkgs/paho.py +76 -0
- jolt/pkgs/patchelf.py +16 -0
- jolt/pkgs/perl.py +42 -0
- jolt/pkgs/pkgconfig.py +64 -0
- jolt/pkgs/poco.py +39 -0
- jolt/pkgs/protobuf.py +77 -0
- jolt/pkgs/pugixml.py +27 -0
- jolt/pkgs/python.py +19 -0
- jolt/pkgs/qt.py +35 -0
- jolt/pkgs/rapidjson.py +26 -0
- jolt/pkgs/rapidyaml.py +28 -0
- jolt/pkgs/re2.py +30 -0
- jolt/pkgs/re2c.py +17 -0
- jolt/pkgs/readline.py +15 -0
- jolt/pkgs/rust.py +41 -0
- jolt/pkgs/sdl.py +28 -0
- jolt/pkgs/simdjson.py +27 -0
- jolt/pkgs/soci.py +46 -0
- jolt/pkgs/spdlog.py +29 -0
- jolt/pkgs/spirv_llvm.py +21 -0
- jolt/pkgs/spirv_tools.py +24 -0
- jolt/pkgs/sqlite.py +83 -0
- jolt/pkgs/ssl.py +12 -0
- jolt/pkgs/texinfo.py +15 -0
- jolt/pkgs/tomlplusplus.py +22 -0
- jolt/pkgs/wayland.py +26 -0
- jolt/pkgs/x11.py +58 -0
- jolt/pkgs/xerces_c.py +20 -0
- jolt/pkgs/xorg.py +360 -0
- jolt/pkgs/xz.py +29 -0
- jolt/pkgs/yamlcpp.py +30 -0
- jolt/pkgs/zeromq.py +47 -0
- jolt/pkgs/zlib.py +69 -0
- jolt/pkgs/zstd.py +33 -0
- jolt/plugins/autotools.py +66 -0
- jolt/plugins/cmake.py +74 -6
- jolt/plugins/conan.py +238 -0
- jolt/plugins/cxxinfo.py +7 -0
- jolt/plugins/docker.py +3 -3
- jolt/plugins/environ.py +11 -0
- jolt/plugins/fetch.py +141 -0
- jolt/plugins/gdb.py +10 -6
- jolt/plugins/git.py +60 -11
- jolt/plugins/libtool.py +63 -0
- jolt/plugins/linux.py +990 -0
- jolt/plugins/meson.py +61 -0
- jolt/plugins/ninja-compdb.py +11 -7
- jolt/plugins/ninja.py +245 -26
- jolt/plugins/paths.py +11 -1
- jolt/plugins/pkgconfig.py +219 -0
- jolt/plugins/podman.py +15 -41
- jolt/plugins/python.py +137 -0
- jolt/plugins/rust.py +25 -0
- jolt/plugins/scheduler.py +18 -14
- jolt/plugins/selfdeploy/setup.py +2 -1
- jolt/plugins/selfdeploy.py +21 -30
- jolt/plugins/strings.py +19 -10
- jolt/scheduler.py +428 -138
- jolt/tasks.py +159 -7
- jolt/tools.py +105 -51
- jolt/utils.py +16 -1
- jolt/version.py +1 -1
- {jolt-0.9.342.dist-info → jolt-0.9.429.dist-info}/METADATA +64 -9
- jolt-0.9.429.dist-info/RECORD +207 -0
- {jolt-0.9.342.dist-info → jolt-0.9.429.dist-info}/WHEEL +1 -1
- jolt/plugins/debian.py +0 -338
- jolt/plugins/repo.py +0 -253
- jolt-0.9.342.dist-info/RECORD +0 -93
- {jolt-0.9.342.dist-info → jolt-0.9.429.dist-info}/entry_points.txt +0 -0
- {jolt-0.9.342.dist-info → jolt-0.9.429.dist-info}/top_level.txt +0 -0
jolt/influence.py
CHANGED
|
@@ -3,7 +3,7 @@ import hashlib
|
|
|
3
3
|
import os
|
|
4
4
|
from pathlib import Path, PurePath
|
|
5
5
|
|
|
6
|
-
from jolt import config
|
|
6
|
+
from jolt import config as jolt_config
|
|
7
7
|
from jolt import inspection
|
|
8
8
|
from jolt import utils
|
|
9
9
|
from jolt import filesystem as fs
|
|
@@ -202,6 +202,71 @@ def source(name, obj=None):
|
|
|
202
202
|
return _decorate
|
|
203
203
|
|
|
204
204
|
|
|
205
|
+
class ConfigInfluence(HashInfluenceProvider):
|
|
206
|
+
name = "Config"
|
|
207
|
+
|
|
208
|
+
def __init__(self, section, key):
|
|
209
|
+
self.section = section
|
|
210
|
+
self.key = key
|
|
211
|
+
|
|
212
|
+
def get_influence(self, task):
|
|
213
|
+
value = jolt_config.get(self.section, self.key)
|
|
214
|
+
if value is None:
|
|
215
|
+
value = "<unset>"
|
|
216
|
+
return "{}.{}: {}".format(self.section, self.key, value)
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def config(section, key):
|
|
220
|
+
""" Add configuration value as hash influence.
|
|
221
|
+
|
|
222
|
+
Note that the configuration value is read at the time
|
|
223
|
+
when the task is prepared, not when it is executed.
|
|
224
|
+
This means that if the configuration value changes after
|
|
225
|
+
influence has been calculated, the task will not be re-executed.
|
|
226
|
+
This is true also in distributed mode, where the task
|
|
227
|
+
is prepared locally and executed remotely on a worker
|
|
228
|
+
where the configuration value may be different.
|
|
229
|
+
|
|
230
|
+
Args:
|
|
231
|
+
section (str): Name of the configuration section.
|
|
232
|
+
key (str): Name of the configuration key.
|
|
233
|
+
|
|
234
|
+
Example:
|
|
235
|
+
.. code-block:: python
|
|
236
|
+
|
|
237
|
+
from jolt import influence
|
|
238
|
+
|
|
239
|
+
@influence.config("jolt", "task_timeout")
|
|
240
|
+
class Example(Task):
|
|
241
|
+
|
|
242
|
+
"""
|
|
243
|
+
def _decorate(cls):
|
|
244
|
+
_old_influence = cls._influence
|
|
245
|
+
|
|
246
|
+
def _influence(self, *args, **kwargs):
|
|
247
|
+
influence = _old_influence(self, *args, **kwargs)
|
|
248
|
+
influence.append(ConfigInfluence(section, key))
|
|
249
|
+
return influence
|
|
250
|
+
|
|
251
|
+
cls._influence = _influence
|
|
252
|
+
return cls
|
|
253
|
+
|
|
254
|
+
return _decorate
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def global_config(section, key):
|
|
258
|
+
""" Register a configuration influence globally.
|
|
259
|
+
|
|
260
|
+
See :py:func:`config` for more information.
|
|
261
|
+
|
|
262
|
+
Args:
|
|
263
|
+
section (str): Name of the configuration section.
|
|
264
|
+
key (str): Name of the configuration key.
|
|
265
|
+
"""
|
|
266
|
+
|
|
267
|
+
HashInfluenceRegistry.get().register(ConfigInfluence(section, key))
|
|
268
|
+
|
|
269
|
+
|
|
205
270
|
class TaskClassSourceInfluence(HashInfluenceProvider):
|
|
206
271
|
name = "Source"
|
|
207
272
|
|
|
@@ -250,7 +315,7 @@ class CacheLocationInfluence(HashInfluenceProvider):
|
|
|
250
315
|
name = "Cache"
|
|
251
316
|
|
|
252
317
|
def get_influence(self, task):
|
|
253
|
-
return
|
|
318
|
+
return jolt_config.get_cachedir()
|
|
254
319
|
|
|
255
320
|
|
|
256
321
|
@HashInfluenceRegistry.Register
|
jolt/loader.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
from collections import OrderedDict
|
|
2
1
|
from contextlib import contextmanager
|
|
3
2
|
import fasteners
|
|
4
3
|
import json
|
|
@@ -11,20 +10,34 @@ import sys
|
|
|
11
10
|
from types import ModuleType
|
|
12
11
|
|
|
13
12
|
from jolt import inspection
|
|
14
|
-
from jolt.tasks import
|
|
15
|
-
from jolt.
|
|
16
|
-
from jolt.error import raise_error_if, raise_task_error_if
|
|
13
|
+
from jolt.tasks import Task, TaskGenerator
|
|
14
|
+
from jolt.error import raise_error_if
|
|
17
15
|
from jolt import common_pb2 as common_pb
|
|
18
16
|
from jolt import config
|
|
19
17
|
from jolt import filesystem as fs
|
|
20
18
|
from jolt import log
|
|
21
19
|
from jolt import utils
|
|
22
|
-
from jolt.manifest import ManifestExtension
|
|
23
|
-
from jolt.manifest import ManifestExtensionRegistry
|
|
24
20
|
from jolt.tools import Tools
|
|
25
21
|
|
|
26
22
|
|
|
27
23
|
class Recipe(object):
|
|
24
|
+
"""
|
|
25
|
+
Abstract representation a single recipe file.
|
|
26
|
+
|
|
27
|
+
Implementations of this class are responsible for reading the recipe source
|
|
28
|
+
from the filesystem. The recipe source is then parsed and the tasks are
|
|
29
|
+
extracted and made available for execution.
|
|
30
|
+
|
|
31
|
+
The format of the recipe source is implementation defined.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
tasks = []
|
|
35
|
+
"""
|
|
36
|
+
List of task classes defined in the recipe.
|
|
37
|
+
|
|
38
|
+
Available after the recipe has been loaded.
|
|
39
|
+
"""
|
|
40
|
+
|
|
28
41
|
def __init__(self, path, joltdir=None, project=None, source=None):
|
|
29
42
|
self.path = path
|
|
30
43
|
self.basepath = os.path.basename(path)
|
|
@@ -33,13 +46,15 @@ class Recipe(object):
|
|
|
33
46
|
self.source = source
|
|
34
47
|
self.tasks = []
|
|
35
48
|
|
|
36
|
-
def load(self
|
|
49
|
+
def load(self):
|
|
50
|
+
""" Load the recipe source from the file system. """
|
|
37
51
|
raise_error_if(self.source is not None, "recipe already loaded: {}", self.path)
|
|
38
52
|
|
|
39
53
|
with open(self.path) as f:
|
|
40
54
|
self.source = f.read()
|
|
41
55
|
|
|
42
56
|
def save(self):
|
|
57
|
+
""" Save the recipe source to the file system. """
|
|
43
58
|
raise_error_if(self.source is None, "recipe source unknown: {}", self.path)
|
|
44
59
|
|
|
45
60
|
with open(self.path, "w") as f:
|
|
@@ -47,6 +62,8 @@ class Recipe(object):
|
|
|
47
62
|
|
|
48
63
|
|
|
49
64
|
class NativeRecipe(Recipe):
|
|
65
|
+
""" Represents a Python recipe file (.jolt, .py). """
|
|
66
|
+
|
|
50
67
|
@staticmethod
|
|
51
68
|
def _is_abstract(cls):
|
|
52
69
|
return cls.__dict__.get("abstract", False) or cls.__name__.startswith("_")
|
|
@@ -58,6 +75,13 @@ class NativeRecipe(Recipe):
|
|
|
58
75
|
not NativeRecipe._is_abstract(cls)
|
|
59
76
|
|
|
60
77
|
def load(self, joltdir=None):
|
|
78
|
+
"""
|
|
79
|
+
Load the recipe source from the file system.
|
|
80
|
+
|
|
81
|
+
Python classes defined in the recipe source are extracted and made available
|
|
82
|
+
as tasks for execution. Task classes must be subclasses of Task or TaskGenerator.
|
|
83
|
+
|
|
84
|
+
"""
|
|
61
85
|
super(NativeRecipe, self).load()
|
|
62
86
|
|
|
63
87
|
name = utils.canonical(self.path)
|
|
@@ -88,17 +112,42 @@ class NativeRecipe(Recipe):
|
|
|
88
112
|
|
|
89
113
|
|
|
90
114
|
class Loader(object):
|
|
91
|
-
|
|
115
|
+
"""
|
|
116
|
+
Base class for recipe loaders.
|
|
117
|
+
|
|
118
|
+
A Loader is responsible for finding recipes in the file system providing a list
|
|
119
|
+
of Recipe:s from which tasks can be loaded.
|
|
120
|
+
"""
|
|
121
|
+
|
|
122
|
+
def recipes(self) -> list:
|
|
123
|
+
""" Return a list of Recipe:s from which tasks can be loaded. """
|
|
92
124
|
pass
|
|
93
125
|
|
|
94
126
|
|
|
95
127
|
class LoaderFactory(object):
|
|
128
|
+
"""
|
|
129
|
+
A factory for creating Loader instances.
|
|
130
|
+
|
|
131
|
+
Factories are registered with the JoltLoader where it is used to create Loader instances.
|
|
132
|
+
"""
|
|
96
133
|
def create(self):
|
|
97
134
|
raise NotImplementedError()
|
|
98
135
|
|
|
99
136
|
|
|
100
137
|
class NativeLoader(Loader):
|
|
138
|
+
""" A loader for Python recipe files (.jolt, .py). """
|
|
139
|
+
|
|
101
140
|
def __init__(self, searchpath):
|
|
141
|
+
"""
|
|
142
|
+
Create a new NativeLoader instance.
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
searchpath (str): The path to search for recipe files. If the path is a file,
|
|
146
|
+
only that file will be loaded. If the path is a directory, all files with
|
|
147
|
+
the .jolt or .py extension will be loaded.
|
|
148
|
+
|
|
149
|
+
"""
|
|
150
|
+
|
|
102
151
|
self._files = self._find_files(searchpath)
|
|
103
152
|
self._recipes = self._load_files(self._files) if self._files else []
|
|
104
153
|
|
|
@@ -109,7 +158,7 @@ class NativeLoader(Loader):
|
|
|
109
158
|
|
|
110
159
|
_, ext = fs.path.splitext(searchpath)
|
|
111
160
|
raise_error_if(not fs.path.exists(searchpath), "File does not exist: {}", searchpath)
|
|
112
|
-
raise_error_if(ext not in [".jolt", ".py"], "Invalid file extension: {}", ext)
|
|
161
|
+
raise_error_if(ext not in [".build", ".jolt", ".py"], "Invalid file extension: {}", ext)
|
|
113
162
|
|
|
114
163
|
return [searchpath]
|
|
115
164
|
|
|
@@ -129,6 +178,7 @@ _loaders = []
|
|
|
129
178
|
|
|
130
179
|
|
|
131
180
|
def register(factory):
|
|
181
|
+
""" Register a LoaderFactory with the JoltLoader. """
|
|
132
182
|
raise_error_if(not issubclass(factory, LoaderFactory),
|
|
133
183
|
"{} is not a LoaderFactory", factory.__name__)
|
|
134
184
|
_loaders.append(factory)
|
|
@@ -136,12 +186,22 @@ def register(factory):
|
|
|
136
186
|
|
|
137
187
|
@register
|
|
138
188
|
class NativeLoaderFactory(LoaderFactory):
|
|
189
|
+
""" A factory for creating NativeLoader instances. """
|
|
139
190
|
def create(self, searchpath):
|
|
140
191
|
return NativeLoader(searchpath)
|
|
141
192
|
|
|
142
193
|
|
|
143
194
|
@utils.Singleton
|
|
144
195
|
class JoltLoader(object):
|
|
196
|
+
"""
|
|
197
|
+
The JoltLoader is responsible for loading recipes from the file system.
|
|
198
|
+
|
|
199
|
+
The JoltLoader is a singleton and is used to load recipes from the file system.
|
|
200
|
+
The recipes are loaded from the workspace directory and any project directories
|
|
201
|
+
defined in the workspace. The recipes are then made available for execution.
|
|
202
|
+
|
|
203
|
+
"""
|
|
204
|
+
|
|
145
205
|
filename = "*.jolt"
|
|
146
206
|
|
|
147
207
|
def __init__(self):
|
|
@@ -149,61 +209,14 @@ class JoltLoader(object):
|
|
|
149
209
|
self._recipes = []
|
|
150
210
|
self._tasks = []
|
|
151
211
|
self._path = None
|
|
152
|
-
self._project_modules = OrderedDict()
|
|
153
|
-
self._project_recipes = OrderedDict()
|
|
154
|
-
self._project_resources = OrderedDict()
|
|
155
212
|
self._build_path = None
|
|
156
213
|
self._workspace_name = None
|
|
157
214
|
|
|
158
|
-
def _add_project_module(self, project, src):
|
|
159
|
-
modules = self._project_modules.get(project, [])
|
|
160
|
-
modules.append(src)
|
|
161
|
-
self._project_modules[project] = modules
|
|
162
|
-
|
|
163
|
-
def _get_project_modules(self, project):
|
|
164
|
-
return self._project_modules.get(project, [])
|
|
165
|
-
|
|
166
|
-
def _add_project_recipe(self, project, joltdir, src):
|
|
167
|
-
recipes = self._project_recipes.get(project, [])
|
|
168
|
-
recipes.append((joltdir, src))
|
|
169
|
-
self._project_recipes[project] = recipes
|
|
170
|
-
|
|
171
|
-
def _get_project_recipes(self, project):
|
|
172
|
-
return self._project_recipes.get(project, [])
|
|
173
|
-
|
|
174
215
|
def _get_first_recipe_path(self):
|
|
175
216
|
for recipe in self.recipes:
|
|
176
217
|
return recipe.path
|
|
177
|
-
for project, recipes in self._project_recipes.items():
|
|
178
|
-
for joltdir, src in recipes:
|
|
179
|
-
return fs.path.join(self._path, src)
|
|
180
218
|
return None
|
|
181
219
|
|
|
182
|
-
def _add_project_resource(self, project, resource_name, resource_task):
|
|
183
|
-
class ProjectResource(Alias):
|
|
184
|
-
name = project + "/" + resource_name
|
|
185
|
-
requires = [resource_task]
|
|
186
|
-
|
|
187
|
-
self._tasks.append(ProjectResource)
|
|
188
|
-
resources = self._project_resources.get(project, [])
|
|
189
|
-
resources.append((resource_name, resource_task))
|
|
190
|
-
self._project_resources[project] = resources
|
|
191
|
-
|
|
192
|
-
def _get_project_resources(self, project):
|
|
193
|
-
return self._project_resources.get(project, [])
|
|
194
|
-
|
|
195
|
-
def _load_project_recipes(self):
|
|
196
|
-
for project, recipes in self._project_recipes.items():
|
|
197
|
-
resources = [resource for _, resource in self._get_project_resources(project)]
|
|
198
|
-
for joltdir, src in recipes:
|
|
199
|
-
joltdir = fs.path.join(self.joltdir, joltdir) if joltdir else self.joltdir
|
|
200
|
-
recipe = NativeRecipe(fs.path.join(self._path, src), joltdir, project)
|
|
201
|
-
recipe.load()
|
|
202
|
-
for task in recipe.tasks:
|
|
203
|
-
task._resources = resources
|
|
204
|
-
attributes.requires("_resources")(task)
|
|
205
|
-
self._tasks += recipe.tasks
|
|
206
|
-
|
|
207
220
|
def _find_workspace_path(self, searchdir):
|
|
208
221
|
for factory in _loaders:
|
|
209
222
|
loader = factory().create(searchdir)
|
|
@@ -219,7 +232,16 @@ class JoltLoader(object):
|
|
|
219
232
|
def _get_searchpaths(self):
|
|
220
233
|
return [self.workspace_path]
|
|
221
234
|
|
|
222
|
-
def load(self,
|
|
235
|
+
def load(self, registry=None):
|
|
236
|
+
"""
|
|
237
|
+
Load all recipes from the workspace directory.
|
|
238
|
+
|
|
239
|
+
Optionally populate the task registry with the tasks found in the recipes.
|
|
240
|
+
|
|
241
|
+
Returns:
|
|
242
|
+
List of Task classes found in the recipes.
|
|
243
|
+
"""
|
|
244
|
+
|
|
223
245
|
if not self.workspace_path:
|
|
224
246
|
self.set_workspace_path(self._find_workspace_path(os.getcwd()))
|
|
225
247
|
|
|
@@ -230,21 +252,27 @@ class JoltLoader(object):
|
|
|
230
252
|
for factory in _loaders:
|
|
231
253
|
loader = factory().create(searchpath)
|
|
232
254
|
for recipe in loader.recipes:
|
|
255
|
+
recipe.workspace_path = os.path.relpath(recipe.path, self.workspace_path)
|
|
233
256
|
recipe.load()
|
|
234
257
|
self._recipes.append(recipe)
|
|
235
258
|
self._tasks += recipe.tasks
|
|
236
259
|
|
|
237
|
-
self._load_project_recipes()
|
|
238
|
-
|
|
239
260
|
# Create workspace lock on the first loaded recipe
|
|
240
261
|
if not self._lock:
|
|
241
262
|
path = self._get_first_recipe_path()
|
|
242
263
|
if path:
|
|
243
264
|
self._lock = fasteners.InterProcessLock(path)
|
|
244
265
|
|
|
266
|
+
# Add tasks to the registry if provided
|
|
267
|
+
if registry is not None:
|
|
268
|
+
for task in self._tasks:
|
|
269
|
+
registry.add_task_class(task)
|
|
270
|
+
|
|
245
271
|
return self._tasks
|
|
246
272
|
|
|
247
273
|
def load_file(self, path, joltdir=None):
|
|
274
|
+
""" Load a single recipe file. """
|
|
275
|
+
|
|
248
276
|
for factory in _loaders:
|
|
249
277
|
loader = factory().create(path)
|
|
250
278
|
for recipe in loader.recipes:
|
|
@@ -254,6 +282,8 @@ class JoltLoader(object):
|
|
|
254
282
|
self._tasks += recipe.tasks
|
|
255
283
|
|
|
256
284
|
def load_plugin(self, filepath):
|
|
285
|
+
""" Load a single plugin file. """
|
|
286
|
+
|
|
257
287
|
plugin, ext = os.path.splitext(fs.path.basename(filepath))
|
|
258
288
|
loader = SourceFileLoader("jolt.plugins." + plugin, filepath)
|
|
259
289
|
module = ModuleType(loader.name)
|
|
@@ -262,6 +292,15 @@ class JoltLoader(object):
|
|
|
262
292
|
sys.modules[loader.name] = module
|
|
263
293
|
|
|
264
294
|
def load_plugins(self):
|
|
295
|
+
"""
|
|
296
|
+
Load all configured plugins.
|
|
297
|
+
|
|
298
|
+
Plugins are loaded from the plugin path configured in the Jolt configuration file
|
|
299
|
+
or from the default plugin path in the Jolt package.
|
|
300
|
+
|
|
301
|
+
If a plugin is already loaded, it will not be loaded again. If a plugin is not found
|
|
302
|
+
in the plugin path, it will not be loaded.
|
|
303
|
+
"""
|
|
265
304
|
searchpath = config.get("jolt", "pluginpath")
|
|
266
305
|
searchpath = searchpath.split(":") if searchpath else []
|
|
267
306
|
searchpath.append(fs.path.join(fs.path.dirname(__file__), "plugins"))
|
|
@@ -288,14 +327,17 @@ class JoltLoader(object):
|
|
|
288
327
|
|
|
289
328
|
@property
|
|
290
329
|
def tasks(self):
|
|
330
|
+
""" Returns a list of all loaded tasks. """
|
|
291
331
|
return self._tasks
|
|
292
332
|
|
|
293
333
|
@property
|
|
294
334
|
def joltdir(self):
|
|
335
|
+
""" Returns the path to the workspace. """
|
|
295
336
|
return self._path
|
|
296
337
|
|
|
297
338
|
@property
|
|
298
339
|
def workspace_name(self):
|
|
340
|
+
""" Returns the name of the workspace. """
|
|
299
341
|
return self._workspace_name or os.path.basename(self.workspace_path)
|
|
300
342
|
|
|
301
343
|
def set_workspace_name(self, name):
|
|
@@ -303,6 +345,7 @@ class JoltLoader(object):
|
|
|
303
345
|
|
|
304
346
|
@property
|
|
305
347
|
def workspace_path(self):
|
|
348
|
+
""" Returns the path to the workspace. """
|
|
306
349
|
return self._path
|
|
307
350
|
|
|
308
351
|
@contextmanager
|
|
@@ -319,10 +362,12 @@ class JoltLoader(object):
|
|
|
319
362
|
|
|
320
363
|
@property
|
|
321
364
|
def build_path(self):
|
|
365
|
+
""" Returns the path to the build directory. """
|
|
322
366
|
return self._build_path or os.path.join(self.workspace_path, "build")
|
|
323
367
|
|
|
324
368
|
@property
|
|
325
369
|
def build_path_rel(self):
|
|
370
|
+
"""" Returns the path to the build directory relative to the workspace. """
|
|
326
371
|
return os.path.relpath(self.build_path, self.workspace_path)
|
|
327
372
|
|
|
328
373
|
def set_build_path(self, path):
|
|
@@ -330,98 +375,6 @@ class JoltLoader(object):
|
|
|
330
375
|
log.debug("Jolt build path: {}", self._build_path)
|
|
331
376
|
|
|
332
377
|
|
|
333
|
-
class RecipeExtension(ManifestExtension):
|
|
334
|
-
def export_manifest(self, manifest, tasks):
|
|
335
|
-
loader = JoltLoader.get()
|
|
336
|
-
|
|
337
|
-
for recipe in loader.recipes:
|
|
338
|
-
manifest_recipe = manifest.create_recipe()
|
|
339
|
-
manifest_recipe.path = recipe.basepath
|
|
340
|
-
manifest_recipe.source = recipe.source
|
|
341
|
-
|
|
342
|
-
projects = set([task.task.joltproject for task in tasks])
|
|
343
|
-
for project in filter(lambda x: x is not None, projects):
|
|
344
|
-
manifest_project = manifest.create_project()
|
|
345
|
-
manifest_project.name = project
|
|
346
|
-
|
|
347
|
-
for name, resource_task in loader._get_project_resources(project):
|
|
348
|
-
resource = manifest_project.create_resource()
|
|
349
|
-
resource.name = name
|
|
350
|
-
resource.text = resource_task
|
|
351
|
-
|
|
352
|
-
for joltdir, src in loader._get_project_recipes(project):
|
|
353
|
-
recipe = manifest_project.create_recipe()
|
|
354
|
-
recipe.src = src
|
|
355
|
-
if joltdir:
|
|
356
|
-
recipe.joltdir = joltdir
|
|
357
|
-
|
|
358
|
-
for path in loader._get_project_modules(project):
|
|
359
|
-
module = manifest_project.create_module()
|
|
360
|
-
module.path = path
|
|
361
|
-
|
|
362
|
-
def import_manifest(self, manifest):
|
|
363
|
-
loader = JoltLoader.get()
|
|
364
|
-
loader.set_workspace_path(manifest.get_workspace_path() or os.getcwd())
|
|
365
|
-
loader.set_workspace_name(manifest.get_workspace_name())
|
|
366
|
-
if manifest.build:
|
|
367
|
-
loader.set_build_path(manifest.build)
|
|
368
|
-
|
|
369
|
-
for recipe in manifest.recipes:
|
|
370
|
-
recipe = Recipe(recipe.path, source=recipe.source)
|
|
371
|
-
recipe.save()
|
|
372
|
-
|
|
373
|
-
for project in manifest.projects:
|
|
374
|
-
for recipe in project.recipes:
|
|
375
|
-
loader._add_project_recipe(project.name, recipe.joltdir, recipe.src)
|
|
376
|
-
|
|
377
|
-
for resource in project.resources:
|
|
378
|
-
loader._add_project_resource(project.name, resource.name, resource.text)
|
|
379
|
-
|
|
380
|
-
# Acquire resource immediately
|
|
381
|
-
task = TaskRegistry.get().get_task(resource.text, manifest=manifest)
|
|
382
|
-
raise_task_error_if(not isinstance(task, WorkspaceResource), task,
|
|
383
|
-
"only workspace resources are allowed in manifest")
|
|
384
|
-
task.acquire_ws()
|
|
385
|
-
|
|
386
|
-
for module in project.modules:
|
|
387
|
-
loader._add_project_module(project.name, module.src)
|
|
388
|
-
sys.path.append(fs.path.join(manifest.get_workspace_path(), module.src))
|
|
389
|
-
|
|
390
|
-
def import_protobuf(self, buildenv):
|
|
391
|
-
loader = JoltLoader.get()
|
|
392
|
-
loader.set_workspace_path(os.getcwd())
|
|
393
|
-
loader.set_workspace_name(buildenv.workspace.name)
|
|
394
|
-
if buildenv.workspace.builddir:
|
|
395
|
-
loader.set_build_path(buildenv.workspace.builddir)
|
|
396
|
-
|
|
397
|
-
# Write .jolt files into workspace
|
|
398
|
-
for file in buildenv.workspace.files:
|
|
399
|
-
if file.content:
|
|
400
|
-
with open(file.path, "w") as f:
|
|
401
|
-
f.write(file.content)
|
|
402
|
-
|
|
403
|
-
for project in buildenv.workspace.projects:
|
|
404
|
-
for recipe in project.recipes:
|
|
405
|
-
loader._add_project_recipe(project.name, recipe.workdir, recipe.path)
|
|
406
|
-
|
|
407
|
-
for resource in project.resources:
|
|
408
|
-
loader._add_project_resource(project.name, resource.alias, resource.name)
|
|
409
|
-
|
|
410
|
-
# Acquire resource immediately
|
|
411
|
-
task = TaskRegistry.get().get_task(resource.name, buildenv=buildenv)
|
|
412
|
-
raise_task_error_if(
|
|
413
|
-
not isinstance(task, WorkspaceResource), task,
|
|
414
|
-
"only workspace resources are allowed in manifest")
|
|
415
|
-
task.acquire_ws()
|
|
416
|
-
|
|
417
|
-
for path in project.paths:
|
|
418
|
-
loader._add_project_module(project.name, path.path)
|
|
419
|
-
sys.path.append(fs.path.join(loader.workspace_path, path.path))
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
ManifestExtensionRegistry.add(RecipeExtension())
|
|
423
|
-
|
|
424
|
-
|
|
425
378
|
def get_workspacedir():
|
|
426
379
|
workspacedir = JoltLoader.get().workspace_path
|
|
427
380
|
assert workspacedir is not None, "No workspace present"
|
|
@@ -441,8 +394,45 @@ def workspace_locked(func):
|
|
|
441
394
|
return wrapper
|
|
442
395
|
|
|
443
396
|
|
|
397
|
+
def import_workspace(buildenv: common_pb.BuildEnvironment):
|
|
398
|
+
"""
|
|
399
|
+
Import workspace from a BuildEnvironment protobuf message.
|
|
400
|
+
|
|
401
|
+
This function will create files, recipes, resources and modules in the workspace
|
|
402
|
+
based on the information in the BuildEnvironment message.
|
|
403
|
+
|
|
404
|
+
The workspace tree is not pulled and checked out here. This is done by the
|
|
405
|
+
worker before it starts the executor.
|
|
406
|
+
|
|
407
|
+
"""
|
|
408
|
+
loader = JoltLoader.get()
|
|
409
|
+
loader.set_workspace_path(os.getcwd())
|
|
410
|
+
loader.set_workspace_name(buildenv.workspace.name)
|
|
411
|
+
if buildenv.workspace.builddir:
|
|
412
|
+
loader.set_build_path(buildenv.workspace.builddir)
|
|
413
|
+
|
|
414
|
+
# Write .jolt files into workspace
|
|
415
|
+
for file in buildenv.workspace.files:
|
|
416
|
+
if file.content:
|
|
417
|
+
with open(file.path, "w") as f:
|
|
418
|
+
f.write(file.content)
|
|
419
|
+
|
|
420
|
+
|
|
444
421
|
@workspace_locked
|
|
445
|
-
def export_workspace(tasks=None):
|
|
422
|
+
def export_workspace(tasks=None) -> common_pb.Workspace:
|
|
423
|
+
"""
|
|
424
|
+
Export workspace to a Workspace protobuf message.
|
|
425
|
+
|
|
426
|
+
This function will create a Workspace protobuf message containing all the
|
|
427
|
+
recipes, resources and modules in the workspace. If tasks is provided, only
|
|
428
|
+
the projects associated with the tasks will be exported. Otherwise, all
|
|
429
|
+
projects will be exported.
|
|
430
|
+
|
|
431
|
+
If the workspace is configured to use a remote cache, the workspace will be
|
|
432
|
+
pushed to the remote cache using the fstree tool. The tree hash of the
|
|
433
|
+
workspace will be included in the returned Workspace message.
|
|
434
|
+
|
|
435
|
+
"""
|
|
446
436
|
loader = JoltLoader.get()
|
|
447
437
|
tools = Tools()
|
|
448
438
|
tree = None
|
|
@@ -461,6 +451,7 @@ def export_workspace(tasks=None):
|
|
|
461
451
|
cache_grpc_uri = config.geturi("cache", "grpc_uri")
|
|
462
452
|
if fstree_enabled:
|
|
463
453
|
if not cache_grpc_uri:
|
|
454
|
+
fstree_enabled = False
|
|
464
455
|
log.warning("No cache gRPC URI configured, will not push workspace to remote cache")
|
|
465
456
|
else:
|
|
466
457
|
raise_error_if(cache_grpc_uri.scheme not in ["tcp"], "Invalid scheme in cache gRPC URI config: {}", cache_grpc_uri.scheme)
|
|
@@ -553,40 +544,13 @@ def export_workspace(tasks=None):
|
|
|
553
544
|
tree=tree,
|
|
554
545
|
)
|
|
555
546
|
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
547
|
+
if not fstree_enabled:
|
|
548
|
+
for recipe in loader.recipes:
|
|
549
|
+
workspace.files.append(
|
|
550
|
+
common_pb.File(
|
|
551
|
+
path=recipe.workspace_path,
|
|
552
|
+
content=recipe.source,
|
|
553
|
+
)
|
|
561
554
|
)
|
|
562
|
-
)
|
|
563
|
-
|
|
564
|
-
if tasks is None:
|
|
565
|
-
projects = loader._project_recipes.keys()
|
|
566
|
-
else:
|
|
567
|
-
projects = set([task.task.joltproject for task in tasks])
|
|
568
|
-
|
|
569
|
-
for project in filter(lambda x: x is not None, projects):
|
|
570
|
-
pb_project = common_pb.Project()
|
|
571
|
-
pb_project.name = project
|
|
572
|
-
|
|
573
|
-
for name, resource_task in loader._get_project_resources(project):
|
|
574
|
-
resource = common_pb.Project.Resource()
|
|
575
|
-
resource.alias = name
|
|
576
|
-
resource.name = resource_task
|
|
577
|
-
pb_project.resources.append(resource)
|
|
578
|
-
|
|
579
|
-
for joltdir, src in loader._get_project_recipes(project):
|
|
580
|
-
recipe = common_pb.Project.Recipe()
|
|
581
|
-
recipe.path = src
|
|
582
|
-
if joltdir:
|
|
583
|
-
recipe.workdir = joltdir
|
|
584
|
-
pb_project.recipes.append(recipe)
|
|
585
|
-
|
|
586
|
-
for path in loader._get_project_modules(project):
|
|
587
|
-
syspath = common_pb.Project.SystemPath(path=path)
|
|
588
|
-
pb_project.paths.append(syspath)
|
|
589
|
-
|
|
590
|
-
workspace.projects.append(pb_project)
|
|
591
555
|
|
|
592
556
|
return workspace
|
jolt/log.py
CHANGED
|
@@ -364,6 +364,9 @@ class _Progress(object):
|
|
|
364
364
|
def reset(self, *args, **kwargs):
|
|
365
365
|
pass
|
|
366
366
|
|
|
367
|
+
def set_description(self, *args, **kwargs):
|
|
368
|
+
pass
|
|
369
|
+
|
|
367
370
|
|
|
368
371
|
def progress_log(desc, count, unit):
|
|
369
372
|
return _Progress(desc)
|
|
@@ -376,8 +379,15 @@ def progress(desc, count, unit, estimates=True, debug=False):
|
|
|
376
379
|
else:
|
|
377
380
|
bar_format = '{desc}{n_fmt}{unit} [{elapsed}]'
|
|
378
381
|
if not debug and is_interactive() and not is_verbose():
|
|
379
|
-
|
|
380
|
-
|
|
382
|
+
class ProgressTqdm(tqdm.tqdm):
|
|
383
|
+
def __init__(self, *args, **kwargs):
|
|
384
|
+
super(ProgressTqdm, self).__init__(*args, **kwargs)
|
|
385
|
+
|
|
386
|
+
def set_description(self, desc=None, refresh=True):
|
|
387
|
+
return super().set_description("[ INFO] " + desc, refresh)
|
|
388
|
+
|
|
389
|
+
p = ProgressTqdm(total=count, unit=unit, unit_scale=True, bar_format=bar_format, dynamic_ncols=True)
|
|
390
|
+
p.set_description(desc)
|
|
381
391
|
return p
|
|
382
392
|
return progress_log(desc, count, unit)
|
|
383
393
|
|
jolt/manifest.py
CHANGED
|
@@ -241,49 +241,3 @@ class JoltManifest(ElementTree):
|
|
|
241
241
|
for manifest_task in self.tasks:
|
|
242
242
|
self._identities[manifest_task.name] = manifest_task.identity
|
|
243
243
|
return self._identities
|
|
244
|
-
|
|
245
|
-
@staticmethod
|
|
246
|
-
def export(task):
|
|
247
|
-
manifest = JoltManifest()
|
|
248
|
-
ManifestExtensionRegistry.export_manifest(manifest, task)
|
|
249
|
-
return manifest
|
|
250
|
-
|
|
251
|
-
def process_import(self):
|
|
252
|
-
ManifestExtensionRegistry.import_manifest(self)
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
class ManifestExtensionRegistry(object):
|
|
256
|
-
extensions = []
|
|
257
|
-
|
|
258
|
-
@staticmethod
|
|
259
|
-
def add(extension, priority=0):
|
|
260
|
-
ManifestExtensionRegistry.extensions.append((extension, priority))
|
|
261
|
-
ManifestExtensionRegistry.extensions.sort(key=lambda x: x[1])
|
|
262
|
-
|
|
263
|
-
@staticmethod
|
|
264
|
-
def export_manifest(manifest, task):
|
|
265
|
-
for extension, _ in ManifestExtensionRegistry.extensions:
|
|
266
|
-
extension.export_manifest(manifest, task)
|
|
267
|
-
|
|
268
|
-
@staticmethod
|
|
269
|
-
def import_manifest(manifest):
|
|
270
|
-
if not manifest.is_valid():
|
|
271
|
-
return
|
|
272
|
-
for extension, _ in ManifestExtensionRegistry.extensions:
|
|
273
|
-
extension.import_manifest(manifest)
|
|
274
|
-
|
|
275
|
-
@staticmethod
|
|
276
|
-
def import_protobuf(pb):
|
|
277
|
-
for extension, _ in ManifestExtensionRegistry.extensions:
|
|
278
|
-
extension.import_protobuf(pb)
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
class ManifestExtension(object):
|
|
282
|
-
def export_manifest(self, manifest, task):
|
|
283
|
-
pass
|
|
284
|
-
|
|
285
|
-
def import_manifest(self, manifest):
|
|
286
|
-
pass
|
|
287
|
-
|
|
288
|
-
def import_protobuf(self, pb):
|
|
289
|
-
pass
|