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.
Files changed (158) hide show
  1. jolt/__init__.py +47 -0
  2. jolt/cache.py +358 -159
  3. jolt/cli.py +71 -104
  4. jolt/config.py +14 -26
  5. jolt/filesystem.py +2 -2
  6. jolt/graph.py +56 -28
  7. jolt/influence.py +67 -2
  8. jolt/loader.py +150 -186
  9. jolt/log.py +12 -2
  10. jolt/manifest.py +0 -46
  11. jolt/options.py +35 -12
  12. jolt/pkgs/abseil.py +42 -0
  13. jolt/pkgs/asio.py +25 -0
  14. jolt/pkgs/autoconf.py +41 -0
  15. jolt/pkgs/automake.py +41 -0
  16. jolt/pkgs/b2.py +31 -0
  17. jolt/pkgs/boost.py +111 -0
  18. jolt/pkgs/boringssl.py +32 -0
  19. jolt/pkgs/busybox.py +39 -0
  20. jolt/pkgs/bzip2.py +43 -0
  21. jolt/pkgs/cares.py +29 -0
  22. jolt/pkgs/catch2.py +36 -0
  23. jolt/pkgs/cbindgen.py +17 -0
  24. jolt/pkgs/cista.py +19 -0
  25. jolt/pkgs/clang.py +44 -0
  26. jolt/pkgs/cli11.py +23 -0
  27. jolt/pkgs/cmake.py +48 -0
  28. jolt/pkgs/cpython.py +196 -0
  29. jolt/pkgs/crun.py +29 -0
  30. jolt/pkgs/curl.py +38 -0
  31. jolt/pkgs/dbus.py +18 -0
  32. jolt/pkgs/double_conversion.py +24 -0
  33. jolt/pkgs/fastfloat.py +21 -0
  34. jolt/pkgs/ffmpeg.py +28 -0
  35. jolt/pkgs/flatbuffers.py +29 -0
  36. jolt/pkgs/fmt.py +27 -0
  37. jolt/pkgs/fstree.py +20 -0
  38. jolt/pkgs/gflags.py +18 -0
  39. jolt/pkgs/glib.py +18 -0
  40. jolt/pkgs/glog.py +25 -0
  41. jolt/pkgs/glslang.py +21 -0
  42. jolt/pkgs/golang.py +16 -11
  43. jolt/pkgs/googlebenchmark.py +18 -0
  44. jolt/pkgs/googletest.py +46 -0
  45. jolt/pkgs/gperf.py +15 -0
  46. jolt/pkgs/grpc.py +73 -0
  47. jolt/pkgs/hdf5.py +19 -0
  48. jolt/pkgs/help2man.py +14 -0
  49. jolt/pkgs/inja.py +28 -0
  50. jolt/pkgs/jsoncpp.py +31 -0
  51. jolt/pkgs/libarchive.py +43 -0
  52. jolt/pkgs/libcap.py +44 -0
  53. jolt/pkgs/libdrm.py +44 -0
  54. jolt/pkgs/libedit.py +42 -0
  55. jolt/pkgs/libevent.py +31 -0
  56. jolt/pkgs/libexpat.py +27 -0
  57. jolt/pkgs/libfastjson.py +21 -0
  58. jolt/pkgs/libffi.py +16 -0
  59. jolt/pkgs/libglvnd.py +30 -0
  60. jolt/pkgs/libogg.py +28 -0
  61. jolt/pkgs/libpciaccess.py +18 -0
  62. jolt/pkgs/libseccomp.py +21 -0
  63. jolt/pkgs/libtirpc.py +24 -0
  64. jolt/pkgs/libtool.py +42 -0
  65. jolt/pkgs/libunwind.py +35 -0
  66. jolt/pkgs/libva.py +18 -0
  67. jolt/pkgs/libvorbis.py +33 -0
  68. jolt/pkgs/libxml2.py +35 -0
  69. jolt/pkgs/libxslt.py +17 -0
  70. jolt/pkgs/libyajl.py +16 -0
  71. jolt/pkgs/llvm.py +81 -0
  72. jolt/pkgs/lua.py +54 -0
  73. jolt/pkgs/lz4.py +26 -0
  74. jolt/pkgs/m4.py +14 -0
  75. jolt/pkgs/make.py +17 -0
  76. jolt/pkgs/mesa.py +81 -0
  77. jolt/pkgs/meson.py +17 -0
  78. jolt/pkgs/mstch.py +28 -0
  79. jolt/pkgs/mysql.py +60 -0
  80. jolt/pkgs/nasm.py +49 -0
  81. jolt/pkgs/ncurses.py +30 -0
  82. jolt/pkgs/ng_log.py +25 -0
  83. jolt/pkgs/ninja.py +45 -0
  84. jolt/pkgs/nlohmann_json.py +25 -0
  85. jolt/pkgs/nodejs.py +19 -11
  86. jolt/pkgs/opencv.py +24 -0
  87. jolt/pkgs/openjdk.py +26 -0
  88. jolt/pkgs/openssl.py +103 -0
  89. jolt/pkgs/paho.py +76 -0
  90. jolt/pkgs/patchelf.py +16 -0
  91. jolt/pkgs/perl.py +42 -0
  92. jolt/pkgs/pkgconfig.py +64 -0
  93. jolt/pkgs/poco.py +39 -0
  94. jolt/pkgs/protobuf.py +77 -0
  95. jolt/pkgs/pugixml.py +27 -0
  96. jolt/pkgs/python.py +19 -0
  97. jolt/pkgs/qt.py +35 -0
  98. jolt/pkgs/rapidjson.py +26 -0
  99. jolt/pkgs/rapidyaml.py +28 -0
  100. jolt/pkgs/re2.py +30 -0
  101. jolt/pkgs/re2c.py +17 -0
  102. jolt/pkgs/readline.py +15 -0
  103. jolt/pkgs/rust.py +41 -0
  104. jolt/pkgs/sdl.py +28 -0
  105. jolt/pkgs/simdjson.py +27 -0
  106. jolt/pkgs/soci.py +46 -0
  107. jolt/pkgs/spdlog.py +29 -0
  108. jolt/pkgs/spirv_llvm.py +21 -0
  109. jolt/pkgs/spirv_tools.py +24 -0
  110. jolt/pkgs/sqlite.py +83 -0
  111. jolt/pkgs/ssl.py +12 -0
  112. jolt/pkgs/texinfo.py +15 -0
  113. jolt/pkgs/tomlplusplus.py +22 -0
  114. jolt/pkgs/wayland.py +26 -0
  115. jolt/pkgs/x11.py +58 -0
  116. jolt/pkgs/xerces_c.py +20 -0
  117. jolt/pkgs/xorg.py +360 -0
  118. jolt/pkgs/xz.py +29 -0
  119. jolt/pkgs/yamlcpp.py +30 -0
  120. jolt/pkgs/zeromq.py +47 -0
  121. jolt/pkgs/zlib.py +69 -0
  122. jolt/pkgs/zstd.py +33 -0
  123. jolt/plugins/autotools.py +66 -0
  124. jolt/plugins/cmake.py +74 -6
  125. jolt/plugins/conan.py +238 -0
  126. jolt/plugins/cxxinfo.py +7 -0
  127. jolt/plugins/docker.py +3 -3
  128. jolt/plugins/environ.py +11 -0
  129. jolt/plugins/fetch.py +141 -0
  130. jolt/plugins/gdb.py +10 -6
  131. jolt/plugins/git.py +60 -11
  132. jolt/plugins/libtool.py +63 -0
  133. jolt/plugins/linux.py +990 -0
  134. jolt/plugins/meson.py +61 -0
  135. jolt/plugins/ninja-compdb.py +11 -7
  136. jolt/plugins/ninja.py +245 -26
  137. jolt/plugins/paths.py +11 -1
  138. jolt/plugins/pkgconfig.py +219 -0
  139. jolt/plugins/podman.py +15 -41
  140. jolt/plugins/python.py +137 -0
  141. jolt/plugins/rust.py +25 -0
  142. jolt/plugins/scheduler.py +18 -14
  143. jolt/plugins/selfdeploy/setup.py +2 -1
  144. jolt/plugins/selfdeploy.py +21 -30
  145. jolt/plugins/strings.py +19 -10
  146. jolt/scheduler.py +428 -138
  147. jolt/tasks.py +159 -7
  148. jolt/tools.py +105 -51
  149. jolt/utils.py +16 -1
  150. jolt/version.py +1 -1
  151. {jolt-0.9.342.dist-info → jolt-0.9.429.dist-info}/METADATA +64 -9
  152. jolt-0.9.429.dist-info/RECORD +207 -0
  153. {jolt-0.9.342.dist-info → jolt-0.9.429.dist-info}/WHEEL +1 -1
  154. jolt/plugins/debian.py +0 -338
  155. jolt/plugins/repo.py +0 -253
  156. jolt-0.9.342.dist-info/RECORD +0 -93
  157. {jolt-0.9.342.dist-info → jolt-0.9.429.dist-info}/entry_points.txt +0 -0
  158. {jolt-0.9.342.dist-info → jolt-0.9.429.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,219 @@
1
+ from jolt import attributes
2
+ from jolt import filesystem as fs
3
+ from jolt import log
4
+ from jolt import utils
5
+ from jolt.error import raise_error_if
6
+
7
+
8
+ class PkgConfigHelper(object):
9
+
10
+ TEMPLATE_PKGCONFIG = """
11
+ prefix={{ artifact.final_path }}
12
+
13
+ Name: {{ pkgname }}
14
+ Description: {{ pkgname }} package
15
+ Version: {{ artifact.identity }}
16
+
17
+ Cflags: {% for flag in cxxflags %}{{ flag }} {% endfor %}{% for inc in incpaths %}-I${prefix}/{{ inc }} {% endfor %}{% for macro in macros %}-D{{ macro }} {% endfor %}
18
+
19
+ Libs: {% for flag in ldflags %}{{ flag }} {% endfor %}{% for libpath in libpaths %}-L${prefix}/{{ libpath }} {% endfor %}{% for library in libraries %}-l{{ library }} {% endfor %}
20
+
21
+ """
22
+
23
+ def __init__(self, artifact, tools):
24
+ self.artifact = artifact
25
+ self.tools = tools
26
+
27
+ def _mkpath(self, path):
28
+ if fs.path.commonpath([path, self.artifact.path]) != self.artifact.path:
29
+ return path
30
+ return fs.path.relpath(path, self.artifact.path)
31
+
32
+ def cflags(self, package):
33
+ package = " ".join(utils.as_list(package))
34
+ try:
35
+ with self.tools.environ(**self.environ):
36
+ output = self.tools.run("{} --maximum-traverse-depth=1 --cflags-only-other {}", self.pkgconfig, package, output=False)
37
+ return output.strip().split()
38
+ except Exception as e:
39
+ log.debug("PkgConfig.cflags: {}", str(e))
40
+ return []
41
+
42
+ def incpaths(self, package):
43
+ package = " ".join(utils.as_list(package))
44
+ try:
45
+ with self.tools.environ(**self.environ):
46
+ output = self.tools.run("{} --maximum-traverse-depth=1 --cflags-only-I {}", self.pkgconfig, package, output=False)
47
+ return [self._mkpath(inc[2:]) for inc in output.strip().split()]
48
+ except Exception as e:
49
+ log.debug("PkgConfig.incpaths: {}", str(e))
50
+ return []
51
+
52
+ def linkflags(self, package):
53
+ package = " ".join(utils.as_list(package))
54
+ try:
55
+ with self.tools.environ(**self.environ):
56
+ output = self.tools.run("{} --maximum-traverse-depth=1 --libs-only-other {}", self.pkgconfig, package, output=False)
57
+ return output.strip().split()
58
+ except Exception as e:
59
+ log.debug("PkgConfig.linkflags: {}", str(e))
60
+ return []
61
+
62
+ def libpaths(self, package):
63
+ package = " ".join(utils.as_list(package))
64
+ try:
65
+ with self.tools.environ(**self.environ):
66
+ output = self.tools.run("{} --maximum-traverse-depth=1 --libs-only-L {}", self.pkgconfig, package, output=False)
67
+ return [self._mkpath(lib[2:]) for lib in output.strip().split()]
68
+ except Exception as e:
69
+ log.debug("PkgConfig.libpaths: {}", str(e))
70
+ return []
71
+
72
+ def libraries(self, package):
73
+ package = " ".join(utils.as_list(package))
74
+ try:
75
+ with self.tools.environ(**self.environ):
76
+ output = self.tools.run("{} --maximum-traverse-depth=1 --libs-only-l {}", self.pkgconfig, package, output=False)
77
+ return [lib[2:] for lib in output.strip().split()]
78
+ except Exception as e:
79
+ log.debug("PkgConfig.libraries: {}", str(e))
80
+ return []
81
+
82
+ def write_pc(self, package):
83
+ with self.tools.tmpdir() as tmpdir, self.tools.cwd(tmpdir):
84
+ content = self.tools.render(
85
+ self.TEMPLATE_PKGCONFIG,
86
+ artifact=self.artifact,
87
+ pkgname=package,
88
+ macros=list(self.artifact.cxxinfo.macros),
89
+ incpaths=list(self.artifact.cxxinfo.incpaths),
90
+ libpaths=list(self.artifact.cxxinfo.libpaths),
91
+ libraries=list(self.artifact.cxxinfo.libraries),
92
+ )
93
+ print(content)
94
+ self.tools.write_file(f"{package}.pc", content, expand=False)
95
+ self.artifact.collect(f"{package}.pc", "lib/pkgconfig/")
96
+
97
+ @property
98
+ def pkgconfig(self):
99
+ pkgconf = self.tools.which(self.tools.getenv("PKG_CONFIG", "pkg-config"))
100
+ raise_error_if(not pkgconf, "No pkg-config tool found in PATH")
101
+ return pkgconf
102
+
103
+ @property
104
+ def environ(self):
105
+ path = self.artifact.environ.get("PKG_CONFIG_PATH")
106
+ if path is None:
107
+ self.tools._task.verbose("No PKG_CONFIG_PATH in artifact environment")
108
+
109
+ # Path from the artifact environment
110
+ path = str(path).split(fs.pathsep)
111
+ path = fs.pathsep.join(fs.path.join(self.artifact.path, p) for p in path)
112
+
113
+ # Append existing PKG_CONFIG_PATH from the tools environment
114
+ if self.tools.getenv("PKG_CONFIG_PATH"):
115
+ path = path + fs.pathsep + self.tools.getenv("PKG_CONFIG_PATH")
116
+
117
+ return {"PKG_CONFIG_PATH": path}
118
+
119
+
120
+ def to_cxxinfo(
121
+ pkg: list | str,
122
+ cflags: bool = True,
123
+ cxxflags: bool = True,
124
+ incpaths: bool = True,
125
+ ldflags: bool = True,
126
+ libpaths: bool = True,
127
+ libraries: bool = True,
128
+ ):
129
+ """
130
+ Decorator to add pkg-config information to cxxinfo metadata of an artifact.
131
+
132
+ The decorator enables interoperability between libraries built with Jolt's
133
+ Ninja plugin and external packages that provide pkg-config files.
134
+
135
+ It uses the pkg-config tool to query for compiler and linker flags,
136
+ include paths, library paths, and libraries associated with a given package.
137
+ If the relevant flags are found, they are appended to the corresponding fields
138
+ in the artifact's cxxinfo metadata.
139
+
140
+ Args:
141
+ pkg (str): The name of the pkg-config package to be added to cxxinfo.
142
+ cflags (bool): Whether to add C compiler flags from pkg-config.
143
+ cxxflags (bool): Whether to add C++ compiler flags from pkg-config.
144
+ incpaths (bool): Whether to add include paths from pkg-config.
145
+ ldflags (bool): Whether to add linker flags from pkg-config.
146
+ libpaths (bool): Whether to add library paths from pkg-config.
147
+ libraries (bool): Whether to add libraries from pkg-config.
148
+ """
149
+
150
+ def decorate(cls):
151
+ original_publish = cls.publish
152
+
153
+ def publish(self, artifact, tools):
154
+ original_publish(self, artifact, tools)
155
+
156
+ pc = PkgConfigHelper(artifact, tools)
157
+ if not pc.environ:
158
+ self.verbose("Skipping pkg-config cxxinfo addition due to missing PKG_CONFIG_PATH.")
159
+ return
160
+
161
+ if cflags:
162
+ artifact.cxxinfo.cflags.extend(pc.cflags(pkg))
163
+ if cxxflags:
164
+ artifact.cxxinfo.cxxflags.extend(pc.cflags(pkg))
165
+ if incpaths:
166
+ artifact.cxxinfo.incpaths.extend(pc.incpaths(pkg))
167
+ if ldflags:
168
+ artifact.cxxinfo.ldflags.extend(pc.linkflags(pkg))
169
+ if libpaths:
170
+ artifact.cxxinfo.libpaths.extend(pc.libpaths(pkg))
171
+ if libraries:
172
+ artifact.cxxinfo.libraries.extend(pc.libraries(pkg))
173
+
174
+ cls.publish = publish
175
+ return cls
176
+
177
+ return decorate
178
+
179
+
180
+ def from_cxxinfo(package):
181
+ """
182
+ Decorator to write a pkg-config file for the given package
183
+ based on the cxxinfo metadata of the artifact.
184
+ """
185
+
186
+ def decorate(cls):
187
+ original_publish = cls.publish
188
+ original_unpack = cls.unpack
189
+
190
+ def publish(self, artifact, tools):
191
+ original_publish(self, artifact, tools)
192
+
193
+ pc = PkgConfigHelper(artifact, tools)
194
+ pc.write_pc(package)
195
+
196
+ def unpack(self, artifact, tools):
197
+ original_unpack(self, artifact, tools)
198
+
199
+ pc = PkgConfigHelper(artifact, tools)
200
+ pc.write_pc(package)
201
+
202
+ cls.publish = publish
203
+ cls.unpack = unpack
204
+ return cls
205
+
206
+ return decorate
207
+
208
+
209
+ def requires():
210
+ """ Decorator to add pkg-config requirements to a task. """
211
+
212
+ import jolt.pkgs.pkgconfig
213
+
214
+ def decorate(cls):
215
+ cls = attributes.requires("requires_pkgconf")(cls)
216
+ cls.requires_pkgconf = ["pkgconf"]
217
+ return cls
218
+
219
+ return decorate
jolt/plugins/podman.py CHANGED
@@ -1,4 +1,4 @@
1
- from jolt import Download, Parameter, Resource, Task
1
+ from jolt import Parameter, Resource, Task
2
2
  from jolt.error import raise_task_error_if
3
3
  from jolt.tasks import TaskRegistry
4
4
  from jolt import attributes
@@ -15,7 +15,6 @@ from jolt.cache import ArtifactAttributeSetProvider
15
15
  import contextlib
16
16
  import json
17
17
  from os import path
18
- from platform import system
19
18
  import tarfile
20
19
 
21
20
 
@@ -100,35 +99,6 @@ class PodmanAttributeProvider(ArtifactAttributeSetProvider):
100
99
  artifact.podman.unapply(task, artifact)
101
100
 
102
101
 
103
- class PodmanClient(Download):
104
- """ Task: Downloads and publishes the Podman command line client.
105
-
106
- The task will be automatically made available after importing
107
- ``jolt.plugins.podman``.
108
- """
109
-
110
- name = "podman/cli"
111
- """ Name of the task """
112
-
113
- arch = Parameter("x86_64", help="Host architecture")
114
- """ Host architecture [x86_64] """
115
-
116
- collect = ["podman/podman"]
117
-
118
- host = Parameter(system().lower(), help="Host operating system")
119
- """ Host operating system [autodetected] """
120
-
121
- url = "https://download.podman.com/{host}/static/stable/{arch}/podman-{version}.tgz"
122
- """ URL of binaries """
123
-
124
- version = Parameter("20.10.13", help="Podman version")
125
- """ Podman version [20.10.13] """
126
-
127
- def publish(self, artifact, tools):
128
- super().publish(artifact, tools)
129
- artifact.environ.PATH.append("podman")
130
-
131
-
132
102
  @attributes.requires("_image")
133
103
  class Container(Resource):
134
104
  """
@@ -206,8 +176,8 @@ class Container(Resource):
206
176
  """
207
177
 
208
178
  volumes_default = [
209
- "{joltdir}:{joltdir}",
210
- "{joltcachedir}:{joltcachedir}",
179
+ "{joltdir}",
180
+ "{joltcachedir}",
211
181
  ]
212
182
  """
213
183
  A list of default volumes to mount.
@@ -247,7 +217,7 @@ class Container(Resource):
247
217
  def _image(self):
248
218
  registry = TaskRegistry.get()
249
219
  tool = tools.Tools(self)
250
- if registry.get_task_class(tool.expand(self.image)):
220
+ if registry.has_task(tool.expand(self.image)):
251
221
  return [self.image]
252
222
  return []
253
223
 
@@ -284,7 +254,7 @@ class Container(Resource):
284
254
 
285
255
  @property
286
256
  def _volumes(self):
287
- return " ".join([utils.option("-v ", self.tools.expand(vol))
257
+ return " ".join([utils.option("-v ", self.tools.expand_path(vol))
288
258
  for vol in self.volumes_default + self.volumes])
289
259
 
290
260
  def acquire(self, artifact, deps, tools, owner):
@@ -344,8 +314,6 @@ class PodmanLogin(Resource):
344
314
  name = "podman/login"
345
315
  """ Name of the resource """
346
316
 
347
- requires = ["podman/cli"]
348
-
349
317
  user = Parameter("", help="Podman Registry username")
350
318
  """
351
319
  Podman Registry username.
@@ -385,7 +353,6 @@ class PodmanLogin(Resource):
385
353
  tools.run("podman logout {server}")
386
354
 
387
355
 
388
- TaskRegistry.get().add_task_class(PodmanClient)
389
356
  TaskRegistry.get().add_task_class(PodmanLogin)
390
357
 
391
358
 
@@ -445,7 +412,6 @@ class ContainerImage(Task):
445
412
 
446
413
  Optionally add requirements to:
447
414
 
448
- - ``podman/cli`` to provision the Podman client, if none is available on the host.
449
415
  - ``podman/login`` to automatically login to the Podman registry.
450
416
 
451
417
  This class must be subclassed.
@@ -468,7 +434,6 @@ class ContainerImage(Task):
468
434
  class Busybox(ContainerImage):
469
435
  \"\"\" Publishes Busybox image as gzip-compressed tarball \"\"\"
470
436
  compression = "gz"
471
- requires = ["podman/cli"]
472
437
  tags = ["busybox:{identity}"]
473
438
 
474
439
  """
@@ -518,6 +483,7 @@ class ContainerImage(Task):
518
483
  - custom
519
484
  - directory
520
485
  - docker-archive
486
+ - ext4
521
487
  - oci-archive
522
488
  - oci-directory
523
489
  - squashfs
@@ -551,6 +517,9 @@ class ContainerImage(Task):
551
517
  The ``podman/login`` Jolt resource can be used for that purpose.
552
518
  """
553
519
 
520
+ size = None
521
+ """ Size of the image, e.g. "64M" (for certain output formats). """
522
+
554
523
  squash = False
555
524
  """ Squash image layers """
556
525
 
@@ -629,7 +598,7 @@ class ContainerImage(Task):
629
598
  tools.run("podman image save --format={output} {} -o {}", self.tags[0], "image.tar")
630
599
  if output == "oci-directory":
631
600
  tools.run("podman image save --format=oci-dir {} -o {}", self.tags[0], "image.dir")
632
- if output in ["archive", "cpio", "custom", "directory", "squashfs"]:
601
+ if output in ["archive", "cpio", "custom", "directory", "ext4", "squashfs"]:
633
602
  ctr = tools.run("podman create {}", self.tags[0])
634
603
  try:
635
604
  with tools.runprefix("podman unshare "):
@@ -641,6 +610,9 @@ class ContainerImage(Task):
641
610
  elif output == "cpio":
642
611
  with tools.cwd(mount_path):
643
612
  tools.run("find | podman unshare cpio -o -F {}/image.cpio -H newc", outdir, output_on_error=True)
613
+ elif output == "ext4":
614
+ assert self.size, "Size must be set for ext4 output"
615
+ tools.run("mke2fs -t ext4 -F -L rootfs -d {} image.ext4 {size}", mount_path, output_on_error=True)
644
616
  elif output == "squashfs":
645
617
  tools.run("mksquashfs {} image.squashfs", mount_path, output_on_error=True)
646
618
  else:
@@ -695,6 +667,8 @@ class ContainerImage(Task):
695
667
  self.publish_custom(artifact, tools)
696
668
  if output in ["directory"]:
697
669
  artifact.paths.rootfs = output
670
+ if output in ["ext4"]:
671
+ artifact.collect("image.ext4", output + "/{_imagefile}.ext4")
698
672
  if output in ["squashfs"]:
699
673
  artifact.collect("image.squashfs", output + "/{_imagefile}.squashfs")
700
674
 
jolt/plugins/python.py CHANGED
@@ -1,9 +1,12 @@
1
1
  import sys
2
2
 
3
+ from jolt import Task
4
+ from jolt import attributes
3
5
  from jolt import filesystem as fs
4
6
  from jolt.cache import ArtifactStringAttribute
5
7
  from jolt.cache import ArtifactAttributeSet
6
8
  from jolt.cache import ArtifactAttributeSetProvider
9
+ from jolt.error import raise_task_error_if
7
10
 
8
11
 
9
12
  class PythonVariable(ArtifactStringAttribute):
@@ -98,3 +101,137 @@ class PythonProvider(ArtifactAttributeSetProvider):
98
101
 
99
102
  def unapply(self, task, artifact):
100
103
  artifact.python.unapply(task, artifact)
104
+
105
+
106
+ @attributes.system
107
+ @attributes.requires("requires_python")
108
+ class PythonEnv(Task):
109
+ """
110
+ Base class for Python virtual environment tasks.
111
+
112
+ Builds a Python virtual environment and installs specified packages.
113
+
114
+ The venv module from the Python standard library must be available in the
115
+ Python installation used to run the task.
116
+ """
117
+
118
+ abstract = True
119
+ """ This is an abstract base class that should be inherited by concrete tasks. """
120
+
121
+ executable = "python3"
122
+ """ Python executable to use for creating the virtual environment. """
123
+
124
+ requirements = []
125
+ """
126
+ List of Python packages to install in the virtual environment.
127
+
128
+ Each entry should be a string suitable for pip, e.g., "package==version".
129
+ """
130
+
131
+ def _verify_influence(self, deps, artifact, tools, sources=None):
132
+ # No influence to verify
133
+ return
134
+
135
+ def relocate_scripts(self, artifact, tools, frompath, topath):
136
+ bindir = "Scripts" if self.system == "windows" else "bin"
137
+
138
+ with tools.cwd(artifact.path, bindir):
139
+ for script in tools.glob("*"):
140
+ if script.startswith("python"):
141
+ continue
142
+ tools.replace_in_file(script, frompath, topath)
143
+
144
+ with tools.cwd(artifact.path):
145
+ if not tools.exists("local/bin"):
146
+ return
147
+ with tools.cwd("local", "bin"):
148
+ for script in tools.glob("*"):
149
+ tools.replace_in_file(script, frompath, topath)
150
+
151
+ def publish(self, artifact, tools):
152
+ # Create a parallel installation by copying a Python installation
153
+
154
+ # First locate the Python executable to copy
155
+ py_exe = tools.which(self.executable)
156
+ raise_task_error_if(
157
+ py_exe is None, self,
158
+ f"Python executable '{self.executable}' not found in PATH.",
159
+ )
160
+
161
+ # Follow symlinks to get the real executable
162
+ py_exe = fs.path.realpath(py_exe)
163
+
164
+ # Determine the Python home directory
165
+ py_home = fs.path.dirname(fs.path.dirname(py_exe))
166
+
167
+ # Determine the Python version
168
+ self.version_major = tools.run(
169
+ [py_exe, "-c", "import sys; print(\"{{}}.{{}}\".format(sys.version_info[0], sys.version_info[1]))"],
170
+ shell=False,
171
+ output_on_error=True).strip()
172
+
173
+ self.info("Python executable: {0}", py_exe)
174
+ self.info("Python home: {0}", py_home)
175
+ self.info("Python version: {0}", self.version_major)
176
+
177
+ # Copy the Python installation to the artifact path
178
+ with tools.cwd(py_home):
179
+ artifact.collect(py_exe, "bin/python3")
180
+ artifact.collect("lib/python3")
181
+ artifact.collect("lib/python{version_major}")
182
+ artifact.collect("lib/libpython{version_major}.*")
183
+
184
+ # Create common symlinks
185
+ if self.system != "windows":
186
+ with tools.cwd(artifact.path, "bin"):
187
+ tools.symlink("python3", "python")
188
+ tools.symlink("python3", "python{version_major}")
189
+
190
+ # Install required packages into the artifact using pip
191
+ with tools.environ(PYTHONHOME=artifact.path):
192
+ py_exe = fs.path.join(artifact.path, "bin", "python3")
193
+ with tools.tmpdir() as tmp, tools.cwd(tmp):
194
+ tools.write_file(
195
+ "requirements.txt",
196
+ "\n".join(self.requirements) + "\n"
197
+ )
198
+
199
+ pip_cmd = [
200
+ py_exe,
201
+ "-m",
202
+ "pip",
203
+ "--isolated",
204
+ "--no-cache-dir",
205
+ "install",
206
+ "-r",
207
+ "requirements.txt",
208
+ "--break-system-packages",
209
+ ]
210
+ tools.run(pip_cmd, shell=False)
211
+
212
+ artifact.environ.PATH.append("bin")
213
+ artifact.environ.PATH.append("local/bin")
214
+ artifact.strings.install_prefix = artifact.path
215
+
216
+ def unpack(self, artifact, tools):
217
+ # Relocate the virtual environment by adjusting script paths
218
+ frompath = artifact.strings.install_prefix
219
+ topath = artifact.final_path
220
+ self.relocate_scripts(artifact, tools, frompath, topath)
221
+
222
+ artifact.strings.install_prefix = artifact.final_path
223
+
224
+
225
+ def requires(python=True):
226
+ """ Decorator to add Python requirements to a task. """
227
+
228
+ import jolt.pkgs.cpython
229
+
230
+ def decorate(cls):
231
+ if python:
232
+ cls = attributes.requires("requires_python")(cls)
233
+ cls.requires_python = ["cpython"]
234
+
235
+ return cls
236
+
237
+ return decorate
jolt/plugins/rust.py ADDED
@@ -0,0 +1,25 @@
1
+ from jolt import attributes, Task
2
+
3
+
4
+ @attributes.common_metadata()
5
+ class Rust(Task):
6
+ """ Base class for Rust-based build tasks. """
7
+
8
+ abstract = True
9
+
10
+ srcdir = None
11
+ """
12
+ Source directory for the Rust project.
13
+
14
+ If None, defaults to the task work directory (joltdir).
15
+ """
16
+
17
+ def run(self, deps, tools):
18
+ self.builddir = tools.builddir(incremental=True)
19
+ self.installdir = tools.builddir("install")
20
+ with tools.cwd(self.srcdir or self.joltdir):
21
+ tools.run("cargo install --path . --target-dir={builddir} --root={installdir}")
22
+
23
+ def publish(self, artifact, tools):
24
+ with tools.cwd(self.installdir):
25
+ artifact.collect("*", symlinks=True)
jolt/plugins/scheduler.py CHANGED
@@ -13,7 +13,6 @@ from jolt import config
13
13
  from jolt import hooks
14
14
  from jolt import loader
15
15
  from jolt import log
16
- from jolt import manifest
17
16
  from jolt import common_pb2 as common_pb
18
17
  from jolt import scheduler
19
18
  from jolt import utils
@@ -145,6 +144,15 @@ class RemoteExecutor(NetworkExecutor):
145
144
  self.session = session
146
145
  self.task = task
147
146
 
147
+ def schedule(self, env):
148
+ """
149
+ Schedule the task for execution.
150
+
151
+ The task is marked as in progress before scheduling.
152
+ """
153
+ self.task.set_in_progress()
154
+ return super().schedule(env)
155
+
148
156
  def cancel(self):
149
157
  """
150
158
  Cancel the build session.
@@ -436,21 +444,11 @@ class RemoteSession(object):
436
444
  if self.build:
437
445
  return
438
446
 
439
- registry = ExecutorRegistry.get()
440
-
441
447
  if not self.buildenv:
442
- # Create a list of parameters to send to the scheduler.
443
- parameters = []
444
- for key, value in registry.get_network_parameters(None).items():
445
- parameters.append(common_pb.Property(key=key, value=value))
446
-
447
- # Add parameters from the config / command line (-c params.key).
448
- parameters.extend(config.export_params())
449
-
450
448
  # Create the build environment.
451
449
  self.buildenv = common_pb.BuildEnvironment(
452
450
  client=selfdeploy.get_client(),
453
- parameters=parameters,
451
+ parameters=config.export_params(),
454
452
  task_default_parameters=scheduler.export_task_default_params(self.tasks),
455
453
  tasks=scheduler.export_tasks(self.tasks + self.pruned),
456
454
  workspace=loader.export_workspace(self.tasks),
@@ -580,8 +578,14 @@ def executor(ctx, worker, build, request):
580
578
  loglevel = request.environment.loglevel
581
579
  log.set_level_pb(loglevel)
582
580
 
583
- # Import protobuf build description
584
- manifest.ManifestExtensionRegistry.import_protobuf(request.environment)
581
+ # Import workspace
582
+ loader.import_workspace(request.environment)
583
+
584
+ # Import configuration snippet
585
+ config.import_config(request.environment.config)
586
+
587
+ # Import configuration parameters (-c params.key)
588
+ config.import_params({param.key: param.value for param in request.environment.parameters})
585
589
 
586
590
  options = JoltOptions(
587
591
  network=True,
@@ -85,6 +85,7 @@ setup(
85
85
  "protobuf",
86
86
  "psutil",
87
87
  "pygit2",
88
+ "py7zr",
88
89
  "requests",
89
90
  "zstandard",
90
91
  "tqdm",
@@ -92,7 +93,7 @@ setup(
92
93
  dependency_links=[],
93
94
  extras_require={
94
95
  "allure": ["allure-python-commons"],
95
- "conan": ["conan<2.0"],
96
+ "conan": ["conan>=2.0"],
96
97
  "dev": ["check-manifest"],
97
98
  "doc": ["sphinx-click", "sphinx-rtd-theme"],
98
99
  "test": ["coverage"],