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/cache.py
CHANGED
|
@@ -33,194 +33,122 @@ def locked(func):
|
|
|
33
33
|
return _f
|
|
34
34
|
|
|
35
35
|
|
|
36
|
-
class StorageProvider(object):
|
|
37
|
-
def download(self, artifact, force=False):
|
|
38
|
-
return False
|
|
39
|
-
|
|
40
|
-
def download_enabled(self):
|
|
41
|
-
return True
|
|
42
|
-
|
|
43
|
-
def upload(self, artifact, force=False):
|
|
44
|
-
return False
|
|
45
|
-
|
|
46
|
-
def upload_enabled(self):
|
|
47
|
-
return True
|
|
48
|
-
|
|
49
|
-
def location(self, artifact):
|
|
50
|
-
return '' # URL
|
|
51
|
-
|
|
52
|
-
def availability(self, artifacts):
|
|
53
|
-
# Ensure artifacts is a list
|
|
54
|
-
artifacts = utils.as_list(artifacts)
|
|
55
|
-
|
|
56
|
-
present = set()
|
|
57
|
-
missing = set()
|
|
58
|
-
|
|
59
|
-
for artifact in artifacts:
|
|
60
|
-
if self.location(artifact):
|
|
61
|
-
present.add(artifact)
|
|
62
|
-
else:
|
|
63
|
-
missing.add(artifact)
|
|
64
|
-
|
|
65
|
-
return list(present), list(missing)
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
class StorageProviderFactory(StorageProvider):
|
|
69
|
-
def create(self):
|
|
70
|
-
pass
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
def RegisterStorage(cls):
|
|
74
|
-
ArtifactCache.storage_provider_factories.append(cls)
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
class ArtifactAttributeSet(object):
|
|
78
|
-
def __init__(self):
|
|
79
|
-
super(ArtifactAttributeSet, self).__setattr__("_attributes", {})
|
|
80
|
-
|
|
81
|
-
def _get_attributes(self):
|
|
82
|
-
return self._attributes
|
|
83
|
-
|
|
84
|
-
def __getattr__(self, name):
|
|
85
|
-
attributes = self._get_attributes()
|
|
86
|
-
if name not in attributes:
|
|
87
|
-
attributes[name] = self.create(name)
|
|
88
|
-
return attributes[name]
|
|
89
|
-
|
|
90
|
-
def __setattr__(self, name, value):
|
|
91
|
-
attributes = self._get_attributes()
|
|
92
|
-
if name not in attributes:
|
|
93
|
-
attributes[name] = self.create(name)
|
|
94
|
-
attributes[name].set_value(value)
|
|
95
|
-
return attributes[name]
|
|
96
|
-
|
|
97
|
-
def __dict__(self):
|
|
98
|
-
return {key: str(value) for key, value in self.items()}
|
|
99
|
-
|
|
100
|
-
def items(self):
|
|
101
|
-
return self._get_attributes().items()
|
|
102
|
-
|
|
103
|
-
def apply(self, task, artifact):
|
|
104
|
-
for _, value in self.items():
|
|
105
|
-
value.apply(task, artifact)
|
|
106
|
-
|
|
107
|
-
def apply_deps(self, task, deps):
|
|
108
|
-
pass
|
|
109
|
-
|
|
110
|
-
def unapply(self, task, artifact):
|
|
111
|
-
for _, value in self.items():
|
|
112
|
-
value.unapply(task, artifact)
|
|
113
|
-
|
|
114
|
-
def unapply_deps(self, task, deps):
|
|
115
|
-
pass
|
|
116
|
-
|
|
117
|
-
def visit(self, task, artifact, visitor):
|
|
118
|
-
for _, value in self.items():
|
|
119
|
-
value.visit(task, artifact, visitor)
|
|
120
|
-
|
|
121
|
-
|
|
122
36
|
class ArtifactAttributeSetRegistry(object):
|
|
123
|
-
|
|
37
|
+
"""
|
|
38
|
+
Registry for providers of artifact attribute sets.
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
providers = [] # List of objects that implement ArtifactAttributeSetProvider
|
|
124
42
|
|
|
125
43
|
@staticmethod
|
|
126
44
|
def create_all(artifact):
|
|
45
|
+
""" Create all artifact attribute sets. """
|
|
127
46
|
for provider in ArtifactAttributeSetRegistry.providers:
|
|
128
47
|
provider().create(artifact)
|
|
129
48
|
|
|
130
49
|
@staticmethod
|
|
131
50
|
def parse_all(artifact, content):
|
|
51
|
+
""" Parse all artifact attribute sets. """
|
|
132
52
|
for provider in ArtifactAttributeSetRegistry.providers:
|
|
133
53
|
provider().parse(artifact, content)
|
|
134
54
|
|
|
135
55
|
@staticmethod
|
|
136
56
|
def format_all(artifact, content):
|
|
57
|
+
""" Format all artifact attribute sets. """
|
|
137
58
|
for provider in ArtifactAttributeSetRegistry.providers:
|
|
138
59
|
provider().format(artifact, content)
|
|
139
60
|
|
|
140
61
|
@staticmethod
|
|
141
62
|
def apply_all(task, artifact):
|
|
63
|
+
""" Apply all artifact attribute sets. """
|
|
142
64
|
for provider in ArtifactAttributeSetRegistry.providers:
|
|
143
65
|
provider().apply(task, artifact)
|
|
144
66
|
|
|
145
|
-
@staticmethod
|
|
146
|
-
def apply_all_deps(task, deps):
|
|
147
|
-
for provider in ArtifactAttributeSetRegistry.providers:
|
|
148
|
-
provider().apply_deps(task, deps)
|
|
149
|
-
|
|
150
67
|
@staticmethod
|
|
151
68
|
def unapply_all(task, artifact):
|
|
69
|
+
""" Unapply all artifact attribute sets. """
|
|
152
70
|
for provider in ArtifactAttributeSetRegistry.providers:
|
|
153
71
|
provider().unapply(task, artifact)
|
|
154
72
|
|
|
155
|
-
@staticmethod
|
|
156
|
-
def unapply_all_deps(task, deps):
|
|
157
|
-
for provider in ArtifactAttributeSetRegistry.providers:
|
|
158
|
-
provider().unapply_deps(task, deps)
|
|
159
|
-
|
|
160
73
|
@staticmethod
|
|
161
74
|
def visit_all(task, artifact, visitor):
|
|
75
|
+
""" Visit all artifact attribute sets. """
|
|
162
76
|
for provider in ArtifactAttributeSetRegistry.providers:
|
|
163
77
|
provider().visit(task, artifact, visitor)
|
|
164
78
|
|
|
165
79
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
class ArtifactAttributeSetProvider(object):
|
|
171
|
-
@staticmethod
|
|
172
|
-
def Register(cls):
|
|
173
|
-
ArtifactAttributeSetRegistry.providers.append(cls)
|
|
174
|
-
|
|
175
|
-
def create(self, artifact):
|
|
176
|
-
raise NotImplementedError()
|
|
177
|
-
|
|
178
|
-
def parse(self, artifact, content):
|
|
179
|
-
raise NotImplementedError()
|
|
180
|
-
|
|
181
|
-
def format(self, artifact, content):
|
|
182
|
-
raise NotImplementedError()
|
|
183
|
-
|
|
184
|
-
def apply(self, task, artifact):
|
|
185
|
-
pass
|
|
186
|
-
|
|
187
|
-
def apply_deps(self, task, deps):
|
|
188
|
-
pass
|
|
189
|
-
|
|
190
|
-
def unapply(self, task, artifact):
|
|
191
|
-
pass
|
|
192
|
-
|
|
193
|
-
def unapply_deps(self, task, deps):
|
|
194
|
-
pass
|
|
80
|
+
class ArtifactAttribute(object):
|
|
81
|
+
"""
|
|
82
|
+
An artifact attribute.
|
|
195
83
|
|
|
196
|
-
|
|
197
|
-
|
|
84
|
+
An artifact attribute is a key-value pair that can be set and retrieved
|
|
85
|
+
from an artifact attribute set. Attributes are used to store metadata and other
|
|
86
|
+
information that is associated with an artifact. They communicate information
|
|
87
|
+
between tasks and store information that is used by tasks when they consume an artifact.
|
|
198
88
|
|
|
89
|
+
Artifact attributes can also perform actions when the artifact is consumed.
|
|
199
90
|
|
|
200
|
-
|
|
91
|
+
"""
|
|
201
92
|
def __init__(self, name):
|
|
202
93
|
self._name = name
|
|
203
94
|
|
|
204
95
|
def get_name(self):
|
|
96
|
+
""" Get the name of the attribute. """
|
|
205
97
|
return self._name
|
|
206
98
|
|
|
207
99
|
def set_value(self, value, expand=True):
|
|
100
|
+
"""
|
|
101
|
+
Set the value of the attribute.
|
|
102
|
+
|
|
103
|
+
Must be implemented by subclasses.
|
|
104
|
+
|
|
105
|
+
Args:
|
|
106
|
+
value: The value to set.
|
|
107
|
+
expand: If True, the value is macro expanded using the tools.expand() method.
|
|
108
|
+
"""
|
|
208
109
|
raise NotImplementedError()
|
|
209
110
|
|
|
210
111
|
def get_value(self):
|
|
112
|
+
"""
|
|
113
|
+
Get the value of the attribute.
|
|
114
|
+
|
|
115
|
+
Must be implemented by subclasses.
|
|
116
|
+
"""
|
|
211
117
|
raise NotImplementedError()
|
|
212
118
|
|
|
213
119
|
def apply(self, task, artifact):
|
|
120
|
+
"""
|
|
121
|
+
Perform an action when the artifact is being used.
|
|
122
|
+
|
|
123
|
+
Args:
|
|
124
|
+
task (Task): The task that is using the artifact.
|
|
125
|
+
artifact (Artifact): The artifact that is being used.
|
|
126
|
+
|
|
127
|
+
"""
|
|
214
128
|
pass
|
|
215
129
|
|
|
216
130
|
def unapply(self, task, artifact):
|
|
131
|
+
"""
|
|
132
|
+
Undo an action when the artifact is no longer being used.
|
|
133
|
+
|
|
134
|
+
Args:
|
|
135
|
+
task (Task): The task that is no longer using the artifact.
|
|
136
|
+
artifact (Artifact): The artifact that is no longer being used.
|
|
137
|
+
"""
|
|
217
138
|
pass
|
|
218
139
|
|
|
219
|
-
def __str__(self):
|
|
140
|
+
def __str__(self) -> str:
|
|
141
|
+
"""
|
|
142
|
+
Get a string representation of the attribute.
|
|
143
|
+
|
|
144
|
+
Must be implemented by subclasses.
|
|
145
|
+
"""
|
|
220
146
|
raise NotImplementedError()
|
|
221
147
|
|
|
222
148
|
|
|
223
149
|
class ArtifactStringAttribute(ArtifactAttribute):
|
|
150
|
+
""" An artifact attribute that stores a string value. """
|
|
151
|
+
|
|
224
152
|
def __init__(self, artifact, name):
|
|
225
153
|
self._artifact = artifact
|
|
226
154
|
self._name = name
|
|
@@ -235,17 +163,13 @@ class ArtifactStringAttribute(ArtifactAttribute):
|
|
|
235
163
|
def get_value(self):
|
|
236
164
|
return self._value
|
|
237
165
|
|
|
238
|
-
def
|
|
239
|
-
pass
|
|
240
|
-
|
|
241
|
-
def unapply(self, task, artifact):
|
|
242
|
-
pass
|
|
243
|
-
|
|
244
|
-
def __str__(self):
|
|
166
|
+
def __str__(self) -> str:
|
|
245
167
|
return str(self._value)
|
|
246
168
|
|
|
247
169
|
|
|
248
170
|
class ArtifactListAttribute(ArtifactAttribute):
|
|
171
|
+
""" An artifact attribute that stores a list of values. """
|
|
172
|
+
|
|
249
173
|
def __init__(self, artifact, name):
|
|
250
174
|
self._artifact = artifact
|
|
251
175
|
self._name = name
|
|
@@ -257,6 +181,9 @@ class ArtifactListAttribute(ArtifactAttribute):
|
|
|
257
181
|
def __getslice__(self, i, j):
|
|
258
182
|
return self._value[i:j]
|
|
259
183
|
|
|
184
|
+
def __len__(self):
|
|
185
|
+
return len(self._value)
|
|
186
|
+
|
|
260
187
|
def get_name(self):
|
|
261
188
|
return self._name
|
|
262
189
|
|
|
@@ -287,23 +214,16 @@ class ArtifactListAttribute(ArtifactAttribute):
|
|
|
287
214
|
def count(self):
|
|
288
215
|
return len(self.items())
|
|
289
216
|
|
|
290
|
-
def
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
def unapply(self, task, artifact):
|
|
294
|
-
pass
|
|
217
|
+
def __str__(self) -> str:
|
|
218
|
+
return fs.pathsep.join(str(v) for v in self._value)
|
|
295
219
|
|
|
296
220
|
|
|
297
221
|
class ArtifactFileAttribute(object):
|
|
222
|
+
""" An attribute that stores a list of source and destination path tuples for files collected into the artifact. """
|
|
223
|
+
|
|
298
224
|
def __init__(self):
|
|
299
225
|
self._files = []
|
|
300
226
|
|
|
301
|
-
def apply(self, task, artifact):
|
|
302
|
-
pass
|
|
303
|
-
|
|
304
|
-
def unapply(self, task, artifact):
|
|
305
|
-
pass
|
|
306
|
-
|
|
307
227
|
def append(self, src, dst):
|
|
308
228
|
self._files.append((fs.as_posix(src), fs.as_posix(dst)))
|
|
309
229
|
|
|
@@ -314,8 +234,145 @@ class ArtifactFileAttribute(object):
|
|
|
314
234
|
return self._files
|
|
315
235
|
|
|
316
236
|
|
|
237
|
+
class ArtifactAttributeSet(object):
|
|
238
|
+
"""
|
|
239
|
+
A set of artifact attributes.
|
|
240
|
+
|
|
241
|
+
An attribute set is a collection of attributes. Each attribute is
|
|
242
|
+
accessed using the attribute name as an attribute of the set. For
|
|
243
|
+
example, to access an attribute named 'version' in an attribute set
|
|
244
|
+
named 'strings', you would write:
|
|
245
|
+
|
|
246
|
+
.. code-block:: python
|
|
247
|
+
|
|
248
|
+
artifact.strings.version = "1.0"
|
|
249
|
+
|
|
250
|
+
"""
|
|
251
|
+
|
|
252
|
+
def __init__(self):
|
|
253
|
+
super(ArtifactAttributeSet, self).__setattr__("_attributes", {})
|
|
254
|
+
|
|
255
|
+
def _get_attributes(self):
|
|
256
|
+
return self._attributes
|
|
257
|
+
|
|
258
|
+
def __getattr__(self, name) -> ArtifactAttribute:
|
|
259
|
+
"""
|
|
260
|
+
Get or create an attribute by name.
|
|
261
|
+
|
|
262
|
+
Args:
|
|
263
|
+
name (str): The name of the attribute.
|
|
264
|
+
|
|
265
|
+
Returns:
|
|
266
|
+
An attribute object.
|
|
267
|
+
"""
|
|
268
|
+
attributes = self._get_attributes()
|
|
269
|
+
if name not in attributes:
|
|
270
|
+
attributes[name] = self.create(name)
|
|
271
|
+
return attributes[name]
|
|
272
|
+
|
|
273
|
+
def __setattr__(self, name, value):
|
|
274
|
+
"""
|
|
275
|
+
Set an attribute by name.
|
|
276
|
+
|
|
277
|
+
Args:
|
|
278
|
+
name (str): The name of the attribute.
|
|
279
|
+
value: The value to set.
|
|
280
|
+
"""
|
|
281
|
+
attributes = self._get_attributes()
|
|
282
|
+
if name not in attributes:
|
|
283
|
+
attributes[name] = self.create(name)
|
|
284
|
+
attributes[name].set_value(value)
|
|
285
|
+
return attributes[name]
|
|
286
|
+
|
|
287
|
+
def __dict__(self):
|
|
288
|
+
""" Get a dictionary representation of the attribute set. """
|
|
289
|
+
return {key: str(value) for key, value in self.items()}
|
|
290
|
+
|
|
291
|
+
def __iter__(self):
|
|
292
|
+
""" Iterate over the attribute set. """
|
|
293
|
+
return iter(self.items())
|
|
294
|
+
|
|
295
|
+
def get(self, name, default=None):
|
|
296
|
+
""" Get an attribute by name.
|
|
297
|
+
|
|
298
|
+
Args:
|
|
299
|
+
name (str): The name of the attribute.
|
|
300
|
+
|
|
301
|
+
Returns:
|
|
302
|
+
The attribute object, or None if it does not exist.
|
|
303
|
+
"""
|
|
304
|
+
attributes = self._get_attributes()
|
|
305
|
+
return attributes.get(name, default)
|
|
306
|
+
|
|
307
|
+
def items(self):
|
|
308
|
+
""" Get a list of tuples containing the attribute name and value. """
|
|
309
|
+
return self._get_attributes().items()
|
|
310
|
+
|
|
311
|
+
def apply(self, task, artifact):
|
|
312
|
+
""" Perform attribute actions when the artifact is being used. """
|
|
313
|
+
for _, value in self.items():
|
|
314
|
+
value.apply(task, artifact)
|
|
315
|
+
|
|
316
|
+
def unapply(self, task, artifact):
|
|
317
|
+
""" Undo attribute actions when the artifact is no longer being used. """
|
|
318
|
+
for _, value in self.items():
|
|
319
|
+
value.unapply(task, artifact)
|
|
320
|
+
|
|
321
|
+
def visit(self, task, artifact, visitor):
|
|
322
|
+
""" Visit all attributes in the set. """
|
|
323
|
+
for _, value in self.items():
|
|
324
|
+
value.visit(task, artifact, visitor)
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
class ArtifactAttributeSetProvider(object):
|
|
328
|
+
""" Base class for artifact attribute set providers.
|
|
329
|
+
|
|
330
|
+
An artifact attribute set provider is a factory for creating and managing
|
|
331
|
+
attribute sets in an artifact.
|
|
332
|
+
"""
|
|
333
|
+
|
|
334
|
+
@staticmethod
|
|
335
|
+
def Register(cls):
|
|
336
|
+
""" Decorator for registering a provider class. """
|
|
337
|
+
ArtifactAttributeSetRegistry.providers.append(cls)
|
|
338
|
+
|
|
339
|
+
def create(self, artifact):
|
|
340
|
+
""" Create an attribute set for an artifact. """
|
|
341
|
+
raise NotImplementedError()
|
|
342
|
+
|
|
343
|
+
def parse(self, artifact, content):
|
|
344
|
+
"""
|
|
345
|
+
Parse an attribute set from a dictionary.
|
|
346
|
+
|
|
347
|
+
The dictionary is loaded from a JSON file embedded in the artifact.
|
|
348
|
+
"""
|
|
349
|
+
raise NotImplementedError()
|
|
350
|
+
|
|
351
|
+
def format(self, artifact, content):
|
|
352
|
+
"""
|
|
353
|
+
Format an attribute set to a dictionary.
|
|
354
|
+
|
|
355
|
+
The dictionary is saved to a JSON file embedded in the artifact.
|
|
356
|
+
"""
|
|
357
|
+
raise NotImplementedError()
|
|
358
|
+
|
|
359
|
+
def apply(self, task, artifact):
|
|
360
|
+
""" Perform actions when the artifact is being used. """
|
|
361
|
+
pass
|
|
362
|
+
|
|
363
|
+
def unapply(self, task, artifact):
|
|
364
|
+
""" Undo actions when the artifact is no longer being used. """
|
|
365
|
+
pass
|
|
366
|
+
|
|
367
|
+
def visit(self, task, artifact, visitor):
|
|
368
|
+
""" Visit all attributes in the set. """
|
|
369
|
+
pass
|
|
370
|
+
|
|
371
|
+
|
|
317
372
|
@ArtifactAttributeSetProvider.Register
|
|
318
373
|
class ArtifactFileAttributeProvider(ArtifactAttributeSetProvider):
|
|
374
|
+
""" Provider for the artifact 'files' attribute set. """
|
|
375
|
+
|
|
319
376
|
def create(self, artifact):
|
|
320
377
|
setattr(artifact, "files", ArtifactFileAttribute())
|
|
321
378
|
|
|
@@ -329,22 +386,19 @@ class ArtifactFileAttributeProvider(ArtifactAttributeSetProvider):
|
|
|
329
386
|
def format(self, artifact, content):
|
|
330
387
|
content["files"] = [{"src": src, "dst": dst} for src, dst in artifact.files.items()]
|
|
331
388
|
|
|
332
|
-
def apply(self, task, artifact):
|
|
333
|
-
pass
|
|
334
389
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
def visit(self, task, artifact, visitor):
|
|
339
|
-
pass
|
|
390
|
+
def visit_artifact(task, artifact, visitor):
|
|
391
|
+
ArtifactAttributeSetRegistry.visit_all(task, artifact, visitor)
|
|
340
392
|
|
|
341
393
|
|
|
342
394
|
def json_serializer(obj):
|
|
395
|
+
""" JSON serializer for datetime objects. """
|
|
343
396
|
if isinstance(obj, datetime):
|
|
344
397
|
return dict(type="datetime", value=obj.strftime("%Y-%m-%d %H:%M:%S.%f"))
|
|
345
398
|
|
|
346
399
|
|
|
347
400
|
def json_deserializer(dct):
|
|
401
|
+
""" JSON deserializer for datetime objects. """
|
|
348
402
|
if dct.get("type") == "datetime":
|
|
349
403
|
return datetime.strptime(dct["value"], "%Y-%m-%d %H:%M:%S.%f")
|
|
350
404
|
return dct
|
|
@@ -880,6 +934,16 @@ class Artifact(object):
|
|
|
880
934
|
|
|
881
935
|
|
|
882
936
|
class ArtifactToolsProxy(object):
|
|
937
|
+
"""
|
|
938
|
+
An artifact proxy that uses a specific tools object.
|
|
939
|
+
|
|
940
|
+
Used when artifacts are consumed by tasks. The proxy allows the
|
|
941
|
+
task to access the artifact's methods and attributes using the
|
|
942
|
+
task's own tools object. This is useful when the consumer task
|
|
943
|
+
wishes to copy files, read files, etc, using the current working
|
|
944
|
+
directory and environment of the task.
|
|
945
|
+
"""
|
|
946
|
+
|
|
883
947
|
def __init__(self, artifact, tools):
|
|
884
948
|
self._artifact = artifact
|
|
885
949
|
self._tools = tools
|
|
@@ -945,10 +1009,8 @@ class Context(object):
|
|
|
945
1009
|
self._artifacts_index[artifact.name + "@" + dep.short_qualified_name] = artifact
|
|
946
1010
|
artifact.apply()
|
|
947
1011
|
ArtifactAttributeSetRegistry.apply_all(self._node.task, artifact)
|
|
948
|
-
ArtifactAttributeSetRegistry.apply_all_deps(self._node.task, self)
|
|
949
1012
|
except (Exception, KeyboardInterrupt) as e:
|
|
950
1013
|
# Rollback all attributes/resources except the last failing one
|
|
951
|
-
ArtifactAttributeSetRegistry.unapply_all_deps(self._node.task, self)
|
|
952
1014
|
for name, artifact in reversed(list(self._artifacts.items())[:-1]):
|
|
953
1015
|
with utils.ignore_exception():
|
|
954
1016
|
ArtifactAttributeSetRegistry.unapply_all(self._node.task, artifact)
|
|
@@ -957,7 +1019,6 @@ class Context(object):
|
|
|
957
1019
|
return self
|
|
958
1020
|
|
|
959
1021
|
def __exit__(self, type, value, tb):
|
|
960
|
-
ArtifactAttributeSetRegistry.unapply_all_deps(self._node.task, self)
|
|
961
1022
|
for name, artifact in reversed(self._artifacts.items()):
|
|
962
1023
|
ArtifactAttributeSetRegistry.unapply_all(self._node.task, artifact)
|
|
963
1024
|
artifact.unapply()
|
|
@@ -1025,6 +1086,144 @@ class PidProvider(object):
|
|
|
1025
1086
|
return pid
|
|
1026
1087
|
|
|
1027
1088
|
|
|
1089
|
+
class StorageProvider(object):
|
|
1090
|
+
"""
|
|
1091
|
+
Base class for remote artifact storage providers.
|
|
1092
|
+
|
|
1093
|
+
A storage provider is responsible for uploading and downloading
|
|
1094
|
+
artifacts to and from a remote storage location. The storage
|
|
1095
|
+
location can be a file system path, a cloud storage service, or
|
|
1096
|
+
any other type of storage.
|
|
1097
|
+
|
|
1098
|
+
"""
|
|
1099
|
+
|
|
1100
|
+
def download(self, artifact: Artifact, force: bool = False) -> bool:
|
|
1101
|
+
"""
|
|
1102
|
+
Download an artifact from the storage location.
|
|
1103
|
+
|
|
1104
|
+
The should be downloaded to the path returned by the artifact's
|
|
1105
|
+
:func:`~jolt.Artifact.get_archive_path` method. The downloaded artifact
|
|
1106
|
+
must be in the format specified by DEFAULT_ARCHIVE_TYPE.
|
|
1107
|
+
|
|
1108
|
+
The download should be retried if it fails due to network issues.
|
|
1109
|
+
The method may raise an exception on errors.
|
|
1110
|
+
|
|
1111
|
+
Args:
|
|
1112
|
+
artifact (Artifact): The artifact to download.
|
|
1113
|
+
force (bool, optional): If True, the download should be forced,
|
|
1114
|
+
even if the artifact is already present locally, or if the
|
|
1115
|
+
download is disabled. The default is False.
|
|
1116
|
+
|
|
1117
|
+
Returns:
|
|
1118
|
+
bool: True if the download was successful, False otherwise.
|
|
1119
|
+
|
|
1120
|
+
"""
|
|
1121
|
+
return False
|
|
1122
|
+
|
|
1123
|
+
def download_enabled(self) -> bool:
|
|
1124
|
+
""" Return True if downloading is enabled. Default is True. """
|
|
1125
|
+
return True
|
|
1126
|
+
|
|
1127
|
+
def upload(self, artifact: Artifact, force: bool = False) -> bool:
|
|
1128
|
+
"""
|
|
1129
|
+
Upload an artifact to the storage location.
|
|
1130
|
+
|
|
1131
|
+
The artifact to be uploaded is located at the path returned by
|
|
1132
|
+
the artifact's :func:`~jolt.Artifact.get_archive_path` method. The
|
|
1133
|
+
uploaded artifact is in the format specified by DEFAULT_ARCHIVE_TYPE.
|
|
1134
|
+
The provider may choose to upload the artifact using a different
|
|
1135
|
+
format, but it must be able to download the artifact in the
|
|
1136
|
+
DEFAULT_ARCHIVE_TYPE format.
|
|
1137
|
+
|
|
1138
|
+
The upload should be retried if it fails due to network issues.
|
|
1139
|
+
The method may raise an exception on errors.
|
|
1140
|
+
|
|
1141
|
+
Args:
|
|
1142
|
+
artifact (Artifact): The artifact to upload.
|
|
1143
|
+
force (bool, optional): If True, the upload should be forced,
|
|
1144
|
+
even if the artifact is already present remotely, or if the
|
|
1145
|
+
upload is disabled. The default is False.
|
|
1146
|
+
|
|
1147
|
+
Returns:
|
|
1148
|
+
bool: True if the upload was successful, False otherwise.
|
|
1149
|
+
|
|
1150
|
+
"""
|
|
1151
|
+
return False
|
|
1152
|
+
|
|
1153
|
+
def upload_enabled(self) -> bool:
|
|
1154
|
+
""" Return True if uploading is enabled. Default is True. """
|
|
1155
|
+
return True
|
|
1156
|
+
|
|
1157
|
+
def location(self, artifact) -> str:
|
|
1158
|
+
"""
|
|
1159
|
+
Return the URL of the artifact in the storage location.
|
|
1160
|
+
|
|
1161
|
+
This method is sometimes used to identify if an artifact is
|
|
1162
|
+
present in the storage location. The URL should point to the
|
|
1163
|
+
artifact if present, or an empty string if the artifact is
|
|
1164
|
+
absent.
|
|
1165
|
+
|
|
1166
|
+
Args:
|
|
1167
|
+
artifact (Artifact): The artifact to locate.
|
|
1168
|
+
"""
|
|
1169
|
+
return '' # URL
|
|
1170
|
+
|
|
1171
|
+
def availability(self, artifacts: list) -> tuple:
|
|
1172
|
+
"""
|
|
1173
|
+
Check the availability of a list of artifacts.
|
|
1174
|
+
|
|
1175
|
+
This method is used to determine which artifacts are present in the
|
|
1176
|
+
storage location. The method should return a tuple of two lists:
|
|
1177
|
+
the first list contains the artifacts that are present, and the
|
|
1178
|
+
second list contains the artifacts that are missing.
|
|
1179
|
+
|
|
1180
|
+
The default implementation of this method calls the :func:`~jolt.StorageProvider.location`
|
|
1181
|
+
method for each artifact in the list. Subclasses may override this
|
|
1182
|
+
method to provide a more efficient implementation.
|
|
1183
|
+
|
|
1184
|
+
Args:
|
|
1185
|
+
artifacts (list): A list of artifacts to check.
|
|
1186
|
+
|
|
1187
|
+
Returns:
|
|
1188
|
+
tuple: A tuple of two lists: the first list contains the artifacts
|
|
1189
|
+
that are present, and the second list contains the artifacts
|
|
1190
|
+
that are missing.
|
|
1191
|
+
|
|
1192
|
+
"""
|
|
1193
|
+
# Ensure artifacts is a list
|
|
1194
|
+
artifacts = utils.as_list(artifacts)
|
|
1195
|
+
|
|
1196
|
+
present = set()
|
|
1197
|
+
missing = set()
|
|
1198
|
+
|
|
1199
|
+
for artifact in artifacts:
|
|
1200
|
+
if self.location(artifact):
|
|
1201
|
+
present.add(artifact)
|
|
1202
|
+
else:
|
|
1203
|
+
missing.add(artifact)
|
|
1204
|
+
|
|
1205
|
+
return list(present), list(missing)
|
|
1206
|
+
|
|
1207
|
+
|
|
1208
|
+
class StorageProviderFactory(StorageProvider):
|
|
1209
|
+
""" A factory for store providers. """
|
|
1210
|
+
|
|
1211
|
+
def create(self) -> StorageProvider:
|
|
1212
|
+
"""
|
|
1213
|
+
Create a new storage provider.
|
|
1214
|
+
|
|
1215
|
+
This method should return a new instance of a storage provider,
|
|
1216
|
+
which must be a subclass of :class:`~jolt.StorageProvider`.
|
|
1217
|
+
|
|
1218
|
+
"""
|
|
1219
|
+
pass
|
|
1220
|
+
|
|
1221
|
+
|
|
1222
|
+
def RegisterStorage(cls):
|
|
1223
|
+
""" Decorator used to register a storage provider factory. """
|
|
1224
|
+
ArtifactCache.storage_provider_factories.append(cls)
|
|
1225
|
+
|
|
1226
|
+
|
|
1028
1227
|
@utils.Singleton
|
|
1029
1228
|
class ArtifactCache(StorageProvider):
|
|
1030
1229
|
"""
|
|
@@ -1095,7 +1294,7 @@ class ArtifactCache(StorageProvider):
|
|
|
1095
1294
|
|
|
1096
1295
|
# Read configuration
|
|
1097
1296
|
self._max_size = config.getsize(
|
|
1098
|
-
"jolt", "cachesize", os.environ.get("
|
|
1297
|
+
"jolt", "cachesize", os.environ.get("JOLT_CACHE_SIZE", 1 * 1024 ** 3))
|
|
1099
1298
|
|
|
1100
1299
|
# Create cache directory
|
|
1101
1300
|
self._fs_create_cachedir()
|