jolt 0.9.419__py3-none-any.whl → 0.9.430__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 (137) hide show
  1. jolt/cache.py +19 -0
  2. jolt/cli.py +3 -2
  3. jolt/filesystem.py +2 -2
  4. jolt/log.py +12 -2
  5. jolt/pkgs/abseil.py +42 -0
  6. jolt/pkgs/asio.py +25 -0
  7. jolt/pkgs/autoconf.py +41 -0
  8. jolt/pkgs/automake.py +41 -0
  9. jolt/pkgs/b2.py +31 -0
  10. jolt/pkgs/boost.py +111 -0
  11. jolt/pkgs/boringssl.py +32 -0
  12. jolt/pkgs/busybox.py +39 -0
  13. jolt/pkgs/bzip2.py +43 -0
  14. jolt/pkgs/cares.py +29 -0
  15. jolt/pkgs/catch2.py +36 -0
  16. jolt/pkgs/cbindgen.py +17 -0
  17. jolt/pkgs/cista.py +19 -0
  18. jolt/pkgs/clang.py +44 -0
  19. jolt/pkgs/cli11.py +23 -0
  20. jolt/pkgs/cmake.py +48 -0
  21. jolt/pkgs/cpython.py +196 -0
  22. jolt/pkgs/crun.py +29 -0
  23. jolt/pkgs/curl.py +38 -0
  24. jolt/pkgs/dbus.py +18 -0
  25. jolt/pkgs/double_conversion.py +24 -0
  26. jolt/pkgs/fastfloat.py +21 -0
  27. jolt/pkgs/ffmpeg.py +28 -0
  28. jolt/pkgs/flatbuffers.py +29 -0
  29. jolt/pkgs/fmt.py +27 -0
  30. jolt/pkgs/fstree.py +20 -0
  31. jolt/pkgs/gflags.py +18 -0
  32. jolt/pkgs/glib.py +18 -0
  33. jolt/pkgs/glog.py +25 -0
  34. jolt/pkgs/glslang.py +21 -0
  35. jolt/pkgs/golang.py +16 -11
  36. jolt/pkgs/googlebenchmark.py +18 -0
  37. jolt/pkgs/googletest.py +46 -0
  38. jolt/pkgs/gperf.py +15 -0
  39. jolt/pkgs/grpc.py +73 -0
  40. jolt/pkgs/hdf5.py +19 -0
  41. jolt/pkgs/help2man.py +14 -0
  42. jolt/pkgs/inja.py +28 -0
  43. jolt/pkgs/jsoncpp.py +31 -0
  44. jolt/pkgs/libarchive.py +43 -0
  45. jolt/pkgs/libcap.py +44 -0
  46. jolt/pkgs/libdrm.py +44 -0
  47. jolt/pkgs/libedit.py +42 -0
  48. jolt/pkgs/libevent.py +31 -0
  49. jolt/pkgs/libexpat.py +27 -0
  50. jolt/pkgs/libfastjson.py +21 -0
  51. jolt/pkgs/libffi.py +16 -0
  52. jolt/pkgs/libglvnd.py +30 -0
  53. jolt/pkgs/libogg.py +28 -0
  54. jolt/pkgs/libpciaccess.py +18 -0
  55. jolt/pkgs/libseccomp.py +21 -0
  56. jolt/pkgs/libtirpc.py +24 -0
  57. jolt/pkgs/libtool.py +42 -0
  58. jolt/pkgs/libunwind.py +35 -0
  59. jolt/pkgs/libva.py +18 -0
  60. jolt/pkgs/libvorbis.py +33 -0
  61. jolt/pkgs/libxml2.py +35 -0
  62. jolt/pkgs/libxslt.py +17 -0
  63. jolt/pkgs/libyajl.py +16 -0
  64. jolt/pkgs/llvm.py +81 -0
  65. jolt/pkgs/lua.py +54 -0
  66. jolt/pkgs/lz4.py +26 -0
  67. jolt/pkgs/m4.py +14 -0
  68. jolt/pkgs/make.py +17 -0
  69. jolt/pkgs/mesa.py +81 -0
  70. jolt/pkgs/meson.py +17 -0
  71. jolt/pkgs/mstch.py +28 -0
  72. jolt/pkgs/mysql.py +60 -0
  73. jolt/pkgs/nasm.py +49 -0
  74. jolt/pkgs/ncurses.py +30 -0
  75. jolt/pkgs/ng_log.py +25 -0
  76. jolt/pkgs/ninja.py +45 -0
  77. jolt/pkgs/nlohmann_json.py +25 -0
  78. jolt/pkgs/nodejs.py +19 -11
  79. jolt/pkgs/opencv.py +24 -0
  80. jolt/pkgs/openjdk.py +26 -0
  81. jolt/pkgs/openssl.py +103 -0
  82. jolt/pkgs/paho.py +76 -0
  83. jolt/pkgs/patchelf.py +16 -0
  84. jolt/pkgs/perl.py +42 -0
  85. jolt/pkgs/pkgconfig.py +64 -0
  86. jolt/pkgs/poco.py +39 -0
  87. jolt/pkgs/protobuf.py +77 -0
  88. jolt/pkgs/pugixml.py +27 -0
  89. jolt/pkgs/python.py +19 -0
  90. jolt/pkgs/qt.py +35 -0
  91. jolt/pkgs/rapidjson.py +26 -0
  92. jolt/pkgs/rapidyaml.py +28 -0
  93. jolt/pkgs/re2.py +30 -0
  94. jolt/pkgs/re2c.py +17 -0
  95. jolt/pkgs/readline.py +15 -0
  96. jolt/pkgs/rust.py +41 -0
  97. jolt/pkgs/sdl.py +28 -0
  98. jolt/pkgs/simdjson.py +27 -0
  99. jolt/pkgs/soci.py +46 -0
  100. jolt/pkgs/spdlog.py +29 -0
  101. jolt/pkgs/spirv_llvm.py +21 -0
  102. jolt/pkgs/spirv_tools.py +24 -0
  103. jolt/pkgs/sqlite.py +83 -0
  104. jolt/pkgs/ssl.py +12 -0
  105. jolt/pkgs/texinfo.py +15 -0
  106. jolt/pkgs/tomlplusplus.py +22 -0
  107. jolt/pkgs/wayland.py +26 -0
  108. jolt/pkgs/x11.py +58 -0
  109. jolt/pkgs/xerces_c.py +20 -0
  110. jolt/pkgs/xorg.py +360 -0
  111. jolt/pkgs/xz.py +29 -0
  112. jolt/pkgs/yamlcpp.py +30 -0
  113. jolt/pkgs/zeromq.py +47 -0
  114. jolt/pkgs/zlib.py +69 -0
  115. jolt/pkgs/zstd.py +33 -0
  116. jolt/plugins/autotools.py +66 -0
  117. jolt/plugins/cmake.py +74 -6
  118. jolt/plugins/cxxinfo.py +7 -0
  119. jolt/plugins/fetch.py +141 -0
  120. jolt/plugins/git.py +33 -11
  121. jolt/plugins/libtool.py +63 -0
  122. jolt/plugins/meson.py +61 -0
  123. jolt/plugins/ninja.py +236 -17
  124. jolt/plugins/pkgconfig.py +219 -0
  125. jolt/plugins/python.py +137 -0
  126. jolt/plugins/rust.py +25 -0
  127. jolt/plugins/selfdeploy/setup.py +1 -0
  128. jolt/tasks.py +79 -14
  129. jolt/tools.py +86 -42
  130. jolt/utils.py +6 -0
  131. jolt/version.py +1 -1
  132. {jolt-0.9.419.dist-info → jolt-0.9.430.dist-info}/METADATA +19 -2
  133. jolt-0.9.430.dist-info/RECORD +207 -0
  134. jolt-0.9.419.dist-info/RECORD +0 -92
  135. {jolt-0.9.419.dist-info → jolt-0.9.430.dist-info}/WHEEL +0 -0
  136. {jolt-0.9.419.dist-info → jolt-0.9.430.dist-info}/entry_points.txt +0 -0
  137. {jolt-0.9.419.dist-info → jolt-0.9.430.dist-info}/top_level.txt +0 -0
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)
@@ -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",
jolt/tasks.py CHANGED
@@ -197,7 +197,7 @@ class Parameter(object):
197
197
  def highlight(value):
198
198
  return colors.bright(value) if self._is_default(value) else colors.dim(value)
199
199
 
200
- return "[{}]".format(", ".join([highlight(value) for value in accepted])) if accepted else ""
200
+ return "[{}]".format(", ".join([highlight(str(value)) for value in accepted])) if accepted else ""
201
201
 
202
202
  def __str__(self):
203
203
  """ Returns the parameter value as a string """
@@ -923,6 +923,14 @@ class TaskGenerator(object):
923
923
 
924
924
 
925
925
  class attributes:
926
+ @staticmethod
927
+ def arch(cls):
928
+ """ Return the architecture name (x86_64, arm64, etc.). """
929
+
930
+ cls._arch = Export(lambda t: platform.machine().lower().replace("amd64", "x86_64"))
931
+ cls.arch = property(lambda t: t._arch.value)
932
+ return cls
933
+
926
934
  @staticmethod
927
935
  def artifact(name, session=False):
928
936
  """Decorator adding an additional artifact to a task.
@@ -1208,6 +1216,65 @@ class attributes:
1208
1216
  return utils.concat_attributes("_publish_files", attrib)(cls)
1209
1217
  return decorate
1210
1218
 
1219
+ @staticmethod
1220
+ def common_metadata(aclocal=True, cmake=True, cxxinfo=True, path=True, pkgconfig=True):
1221
+ """
1222
+ Decorator adding common metadata to published artifacts.
1223
+
1224
+ The decorator adds common environment variables and C/C++ build information
1225
+ to the published artifact:
1226
+
1227
+ - Adds `bin/` to `PATH` environment variable if it exists.
1228
+ - Adds `lib/` and `lib64/` to C++ library paths if they exist.
1229
+ - Adds `include/` to C++ include paths if it exists.
1230
+ - Adds `lib/pkgconfig/`, `lib64/pkgconfig/` and `share/pkgconfig/` to
1231
+ `PKG_CONFIG_PATH` environment variable if `.pc` files are found.
1232
+ The `prefix` variable in `.pc` files is relocated to allow
1233
+ installation in arbitrary locations.
1234
+ - Adds `lib/cmake/`, `lib64/cmake/` and `share/cmake/` to
1235
+ `CMAKE_PREFIX_PATH` environment variable if they exist.
1236
+ - Adds `share/aclocal/` to `ACLOCAL_PATH` environment variable if it exists.
1237
+
1238
+ """
1239
+ def decorate(cls):
1240
+ _old_publish = cls.publish
1241
+
1242
+ @functools.wraps(cls.publish)
1243
+ def publish(self, artifact, tools):
1244
+ _old_publish(self, artifact, tools)
1245
+
1246
+ with tools.cwd(artifact.path):
1247
+ if path and tools.exists("bin"):
1248
+ artifact.environ.PATH.append("bin")
1249
+
1250
+ pcdirs = set()
1251
+
1252
+ for pcpath in tools.glob("lib/pkgconfig/*.pc") + tools.glob("lib64/pkgconfig/*.pc") + tools.glob("share/pkgconfig/*.pc"):
1253
+ pcdirs.add(fs.path.dirname(pcpath))
1254
+ tools.replace_in_file(pcpath, artifact.strings.install_prefix, "${{pcfiledir}}/../..")
1255
+ for pcpath in tools.glob("lib/*/pkgconfig/*.pc") + tools.glob("lib64/*/pkgconfig/*.pc"):
1256
+ pcdirs.add(fs.path.dirname(pcpath))
1257
+ tools.replace_in_file(pcpath, artifact.strings.install_prefix, "${{pcfiledir}}/../../..")
1258
+
1259
+ for pcdir in pcdirs:
1260
+ artifact.environ.PKG_CONFIG_PATH.append(pcdir)
1261
+
1262
+ if cmake and tools.exists("lib/cmake"):
1263
+ artifact.environ.CMAKE_PREFIX_PATH.append(".")
1264
+ if cmake and tools.exists("lib64/cmake"):
1265
+ artifact.environ.CMAKE_PREFIX_PATH.append(".")
1266
+ if cmake and tools.exists("share/cmake"):
1267
+ artifact.environ.CMAKE_PREFIX_PATH.append(".")
1268
+
1269
+ if aclocal and tools.exists("share/aclocal"):
1270
+ artifact.environ.ACLOCAL_PATH.append("share/aclocal")
1271
+
1272
+ cls.publish = publish
1273
+
1274
+ return cls
1275
+
1276
+ return decorate
1277
+
1211
1278
  @staticmethod
1212
1279
  def requires(attrib):
1213
1280
  """
@@ -2689,7 +2756,7 @@ class ReportProxy(object):
2689
2756
  if not filterfn(error):
2690
2757
  continue
2691
2758
  if error["location"] not in errors_by_location:
2692
- errors_by_location[error["location"]] = (error, [error["message"]], error["details"])
2759
+ errors_by_location[error["location"]] = (error, [error["message"]], error.get("details", ""))
2693
2760
  else:
2694
2761
  errors_by_location[error["location"]][1].append(error["message"])
2695
2762
 
@@ -2976,6 +3043,7 @@ class Download(Task):
2976
3043
  Once downloaded, archives are extracted and all of their files are published.
2977
3044
  If the file is not an archive it is published as is. Recognized archive extensions are:
2978
3045
 
3046
+ - .7z
2979
3047
  - .tar
2980
3048
  - .tar.bz2
2981
3049
  - .tar.gz
@@ -3038,7 +3106,7 @@ class Download(Task):
3038
3106
  return fs.posixpath.basename(url.path) or "file"
3039
3107
 
3040
3108
  def run(self, deps, tools):
3041
- supported_formats = [".tar", ".tar.bz2", ".tar.gz", ".tar.xz", ".tgz", ".zip"]
3109
+ supported_formats = [".7z", ".tar", ".tar.bz2", ".tar.gz", ".tar.xz", ".tgz", ".zip"]
3042
3110
 
3043
3111
  raise_task_error_if(not self.url, self, "No URL(s) specified")
3044
3112
 
@@ -3292,24 +3360,21 @@ class Test(Task):
3292
3360
  """
3293
3361
  raise_error_if(type(args) is not list, "Test.parameterized() expects a list as argument")
3294
3362
 
3295
- class partialmethod(functools.partialmethod):
3296
- def __init__(self, index, func, *args):
3297
- super().__init__(func, *args)
3298
- self.__index = index
3299
-
3300
- def __get__(self, obj, cls=None):
3301
- retval = super().__get__(obj, cls)
3302
- retval.__name__ = f"{self.func.__name__}[{self.__index}]"
3303
- retval.__doc__ = self.func.__doc__
3304
- return retval
3363
+ def make_method(index, func, *args):
3364
+ def testmethod(self):
3365
+ return func(self, *args)
3366
+ testmethod.__name__ = f"{func.__name__}[{index}]"
3367
+ testmethod.__doc__ = func.__doc__
3368
+ return testmethod
3305
3369
 
3306
3370
  def decorate(method):
3307
3371
  frame = sys._getframe().f_back.f_locals
3308
3372
  for index, arg in enumerate(args):
3309
- testmethod = partialmethod(index, method, *utils.as_list(arg))
3373
+ testmethod = make_method(index, method, *utils.as_list(arg))
3310
3374
  name = f"{method.__name__}[{index}]"
3311
3375
  frame[name] = testmethod
3312
3376
  return None
3377
+
3313
3378
  return decorate
3314
3379
 
3315
3380
  def setup(self, deps, tools):
jolt/tools.py CHANGED
@@ -1,3 +1,4 @@
1
+ import py7zr
1
2
  import bz2
2
3
  import copy
3
4
  import getpass
@@ -42,6 +43,9 @@ from jolt.error import raise_error_if
42
43
  from jolt.error import raise_task_error, raise_task_error_if
43
44
 
44
45
 
46
+ SUPPORTED_ARCHIVE_TYPES = [".tar", ".tar.bz2", ".tar.gz", ".tgz", ".tar.xz", ".tar.zst", ".zip"]
47
+
48
+
45
49
  http_session = Session()
46
50
 
47
51
 
@@ -257,6 +261,10 @@ class _CMake(object):
257
261
  self.builddir = self.tools.builddir(incremental=incremental)
258
262
  self.installdir = self.tools.builddir("install", incremental=False)
259
263
 
264
+ def clean(self):
265
+ self.tools.rmtree(self.builddir, ignore_errors=True)
266
+ self.tools.rmtree(self.installdir, ignore_errors=True)
267
+
260
268
  def configure(self, sourcedir, *args, generator=None, **kwargs):
261
269
  sourcedir = self.tools.expand_path(sourcedir)
262
270
 
@@ -267,74 +275,85 @@ class _CMake(object):
267
275
 
268
276
  with self.tools.cwd(self.builddir):
269
277
  self.tools.run(
270
- "cmake {0} -B{1} -DCMAKE_INSTALL_PREFIX={2} {3} {4}",
278
+ "cmake {0} {1} -DCMAKE_INSTALL_PREFIX=/jolt-prefix {1} {2} {3}",
271
279
  sourcedir,
272
- self.builddir,
273
- self.installdir,
280
+ utils.option("-B", self.builddir),
274
281
  utils.option("-G", generator),
275
282
  extra_args,
276
283
  output=True)
277
284
 
278
- def build(self, release=True, *args, **kwargs):
285
+ def build(self, *args, config="Release", **kwargs):
279
286
  threading_args = ' -j {}'.format(kwargs.get("threads", self.tools.thread_count()))
280
287
  with self.tools.cwd(self.builddir):
281
- release = "--config Release" if release else ""
282
- self.tools.run("cmake --build . {0}{1}", release, threading_args, output=True)
288
+ self.tools.run("cmake --build . --config {0} {1}", config, threading_args, output=True)
283
289
 
284
- def install(self, release=True, *args, **kwargs):
285
- with self.tools.cwd(self.builddir):
286
- release = "--config Release" if release else ""
287
- self.tools.run("cmake --build . --target install {0}", release, output=True)
290
+ def install(self, target="install", config="Release", **kwargs):
291
+ with self.tools.cwd(self.builddir), self.tools.environ(DESTDIR=self.installdir):
292
+ self.tools.run("cmake --build . --config {0} --target {1}", config, target, output=True)
288
293
 
289
- def publish(self, artifact, files='*', *args, **kwargs):
290
- with self.tools.cwd(self.installdir):
291
- artifact.collect(files, *args, **kwargs)
294
+ def publish(self, artifact, files='*', symlinks=True, *args, **kwargs):
295
+ with self.tools.cwd(self.installdir, "jolt-prefix"):
296
+ artifact.collect(files, *args, symlinks=symlinks, **kwargs)
297
+ artifact.strings.install_prefix = "/jolt-prefix"
292
298
 
293
299
 
294
300
  class _Meson(object):
295
- def __init__(self, deps, tools):
301
+ def __init__(self, deps, tools, incremental=False):
296
302
  self.deps = deps
297
303
  self.tools = tools
298
- self.builddir = self.tools.builddir()
299
- self.installdir = self.tools.builddir("install")
304
+ self.builddir = self.tools.builddir(incremental=incremental)
305
+ self.installdir = self.tools.builddir("install", incremental=False)
306
+ self.prefix = "/jolt-prefix" if os.name != "nt" else "C:\\jolt-prefix"
307
+
308
+ def clean(self):
309
+ self.tools.rmtree(self.builddir, ignore_errors=True)
310
+ self.tools.rmtree(self.installdir, ignore_errors=True)
300
311
 
301
312
  def configure(self, sourcedir, *args, **kwargs):
302
313
  sourcedir = self.tools.expand_path(sourcedir)
303
- self.tools.run("meson --prefix=/ {0} {1}", sourcedir, self.builddir,
314
+ options = " ".join([f"-D{arg}" for arg in args]) + " "
315
+ options += " ".join(["-D{0}={1}".format(key, self.tools.expand(val)) for key, val in kwargs.items()])
316
+ self.tools.run("meson setup --prefix={0} {1} {2} {3}", self.prefix, sourcedir, self.builddir, options,
304
317
  output=True)
305
318
 
306
319
  def build(self, *args, **kwargs):
307
320
  self.tools.run("ninja -C {0} ", self.builddir, output=True)
308
321
 
309
322
  def install(self, *args, **kwargs):
310
- self.tools.run("DESTDIR={0} ninja -C {1} install",
311
- self.installdir, self.builddir,
312
- output=True)
323
+ with self.tools.environ(DESTDIR=self.installdir):
324
+ self.tools.run("ninja -C {0} install", self.builddir, output=True)
313
325
 
314
- def publish(self, artifact, files='*', *args, **kwargs):
315
- with self.tools.cwd(self.installdir):
316
- artifact.collect(files, *args, **kwargs)
326
+ def publish(self, artifact, files='*', symlinks=True, *args, **kwargs):
327
+ with self.tools.cwd(self.installdir, "jolt-prefix"):
328
+ artifact.collect(files, *args, symlinks=symlinks, **kwargs)
329
+ artifact.strings.install_prefix = self.prefix
317
330
 
318
331
 
319
332
  class _AutoTools(object):
320
- def __init__(self, deps, tools):
333
+ def __init__(self, deps, tools, incremental=False):
321
334
  self.deps = deps
322
335
  self.tools = tools
323
- self.builddir = self.tools.builddir()
324
- self.installdir = self.tools.builddir("install")
336
+ self.builddir = self.tools.builddir(incremental=incremental)
337
+ self.installdir = self.tools.builddir("install", incremental=False)
338
+ self.prefix = "jolt-prefix"
325
339
 
326
- def configure(self, sourcedir, *args, **kwargs):
340
+ def clean(self):
341
+ self.tools.rmtree(self.builddir, ignore_errors=True)
342
+ self.tools.rmtree(self.installdir, ignore_errors=True)
343
+
344
+ def configure(self, sourcedir, *args):
327
345
  sourcedir = self.tools.expand_path(sourcedir)
328
- prefix = kwargs.get("prefix", "/")
329
346
 
330
347
  if not fs.path.exists(fs.path.join(sourcedir, "configure")):
331
348
  with self.tools.cwd(sourcedir):
332
349
  self.tools.run("autoreconf -visf", output=True)
333
350
 
334
351
  with self.tools.cwd(self.builddir), self.tools.environ(DESTDIR=self.installdir):
335
- self.tools.run("{0}/configure --prefix={1} {2}",
336
- sourcedir, prefix,
352
+ self.tools.run("{0}/configure --prefix=/{1} {2} {3}",
353
+ sourcedir,
354
+ self.prefix,
337
355
  self.tools.getenv("CONFIGURE_FLAGS", ""),
356
+ " ".join(args),
338
357
  output=True)
339
358
 
340
359
  def build(self, *args, **kwargs):
@@ -342,13 +361,14 @@ class _AutoTools(object):
342
361
  self.tools.run("make VERBOSE=yes Q= V=1 -j{0}",
343
362
  self.tools.cpu_count(), output=True)
344
363
 
345
- def install(self, target="install", **kwargs):
346
- with self.tools.cwd(self.builddir), self.tools.environ(DESTDIR=self.installdir):
347
- self.tools.run("make {}", target, output=True)
364
+ def install(self, target="install"):
365
+ with self.tools.cwd(self.builddir):
366
+ self.tools.run("make DESTDIR={} {}", self.installdir, target, output=True)
348
367
 
349
- def publish(self, artifact, files='*', *args, **kwargs):
350
- with self.tools.cwd(self.installdir):
351
- artifact.collect(files, *args, **kwargs)
368
+ def publish(self, artifact, files='*', symlinks=True, *args, **kwargs):
369
+ with self.tools.cwd(self.installdir, self.prefix):
370
+ artifact.collect(files, *args, symlinks=symlinks, **kwargs)
371
+ artifact.strings.install_prefix = "/" + self.prefix
352
372
 
353
373
 
354
374
  class ZipFile(zipfile.ZipFile):
@@ -527,6 +547,12 @@ class Tools(object):
527
547
  zf.write(path, zippath)
528
548
  return filename
529
549
 
550
+ def _make_7zfile(self, filename, fmt, rootdir):
551
+ self.mkdirname(filename)
552
+ with py7zr.SevenZipFile(filename, 'w') as archive:
553
+ archive.writeall(rootdir, ".")
554
+ return filename
555
+
530
556
  def _make_tarfile(self, filename, fmt, rootdir):
531
557
  self.mkdirname(filename)
532
558
  with tarfile.open(filename, 'w|%s' % fmt) as tar:
@@ -559,6 +585,7 @@ class Tools(object):
559
585
  The type of archive to create is determined by the filename extension.
560
586
  Supported formats are:
561
587
 
588
+ - 7z
562
589
  - tar
563
590
  - tar.bz2
564
591
  - tar.gz
@@ -594,12 +621,16 @@ class Tools(object):
594
621
  fmt = "tarbz2"
595
622
  elif filename.endswith(".tar.xz"):
596
623
  fmt = "tarxz"
624
+ elif filename.endswith(".7z"):
625
+ fmt = "7z"
597
626
  raise_task_error_if(
598
627
  not fmt, self._task,
599
628
  "unknown archive type '{0}'", fs.path.basename(filename))
600
629
  try:
601
630
  if fmt == "zip":
602
631
  outfile = self._make_zipfile(filename, fmt, rootdir=pathname)
632
+ elif fmt == "7z":
633
+ outfile = self._make_7zfile(filename, fmt, rootdir=pathname)
603
634
  else:
604
635
  outfile = self._make_tarfile(filename, fmt[3:], rootdir=pathname)
605
636
  if outfile != filename:
@@ -608,9 +639,9 @@ class Tools(object):
608
639
  except Exception:
609
640
  raise_task_error(self._task, "failed to create archive from directory '{0}'", pathname)
610
641
 
611
- def autotools(self, deps=None):
642
+ def autotools(self, deps=None, incremental=False):
612
643
  """ Creates an AutoTools invokation helper """
613
- return _AutoTools(deps, self)
644
+ return _AutoTools(deps, self, incremental=incremental)
614
645
 
615
646
  @utils.locked(lock='_builddir_lock')
616
647
  def builddir(self, name=None, incremental=False, unique=True):
@@ -895,7 +926,7 @@ class Tools(object):
895
926
  pbar.update(len(data))
896
927
  actual_size = self.file_size(pathname)
897
928
  raise_error_if(
898
- size != 0 and size != actual_size,
929
+ size != 0 and size > actual_size,
899
930
  f"Downloaded file was truncated to {actual_size}/{size} bytes: {name}")
900
931
 
901
932
  return response.status_code == 200
@@ -1054,6 +1085,7 @@ class Tools(object):
1054
1085
 
1055
1086
  Supported formats are:
1056
1087
 
1088
+ - 7z
1057
1089
  - tar
1058
1090
  - tar.bz2
1059
1091
  - tar.gz
@@ -1117,6 +1149,13 @@ class Tools(object):
1117
1149
  self._extract_tarzstd(filename, filepath, files)
1118
1150
  except tarfile.StreamError as e:
1119
1151
  raise_task_error(self._task, "failed to extract archive '{0}': {1}", filename, str(e))
1152
+ elif filename.endswith(".7z"):
1153
+ with py7zr.SevenZipFile(filename, 'r') as archive:
1154
+ if files:
1155
+ for file in files:
1156
+ archive.extract(file, filepath)
1157
+ else:
1158
+ archive.extractall(filepath)
1120
1159
  else:
1121
1160
  raise_task_error(self._task, "unknown archive type '{0}'", fs.path.basename(filename))
1122
1161
  except Exception:
@@ -1268,9 +1307,9 @@ class Tools(object):
1268
1307
  """
1269
1308
  return utils.map_concurrent(callable, iterable, max_workers)
1270
1309
 
1271
- def meson(self, deps=None):
1310
+ def meson(self, deps=None, incremental=False):
1272
1311
  """ Creates a Meson invokation helper """
1273
- return _Meson(deps, self)
1312
+ return _Meson(deps, self, incremental=incremental)
1274
1313
 
1275
1314
  @contextmanager
1276
1315
  def nixpkgs(self, nixfile=None, packages=None, pure=False, path=None, options=None):
@@ -1702,11 +1741,15 @@ class Tools(object):
1702
1741
  fs.makedirs(path)
1703
1742
  for relsrcpath, reldstpath in artifact.files.items():
1704
1743
  srcpath = fs.path.normpath(fs.path.join(artifact.task.joltdir, relsrcpath))
1744
+ srcpath = self.expand_path(srcpath)
1705
1745
  dstpath = fs.path.normpath(fs.path.join(path, reldstpath))
1746
+ dstpath = self.expand_path(dstpath)
1747
+
1706
1748
  if dstpath != fs.path.realpath(dstpath):
1707
1749
  log.debug("Cannot symlink '{} -> {}', parent directory already symlinked",
1708
1750
  srcpath, dstpath)
1709
1751
  continue
1752
+
1710
1753
  if fs.path.isdir(dstpath):
1711
1754
  files = fs.scandir(srcpath)
1712
1755
  for file in files:
@@ -1716,7 +1759,8 @@ class Tools(object):
1716
1759
  self.symlink(srcpath, dstpath)
1717
1760
 
1718
1761
  # Restore missing srcfiles if they resided in a build directory
1719
- if srcpath.startswith(artifact.tools.buildroot) and \
1762
+ buildroot_abs = self.expand_path(artifact.tools.buildroot)
1763
+ if srcpath.startswith(buildroot_abs) and \
1720
1764
  not fs.path.exists(srcpath):
1721
1765
  fs.copy(fs.path.join(artifact.path, reldstpath), srcpath, symlinks=True)
1722
1766
  self.write_file(meta, artifact.path)
jolt/utils.py CHANGED
@@ -219,6 +219,10 @@ class _SafeDict(object):
219
219
  value = self.values.get(key)
220
220
  if value is None:
221
221
  value = call_and_catch(getattr, self.values.get("_instance", object()), key)
222
+ if value is None and key == "buildroot":
223
+ tools = getattr(self.values.get("_instance", object()), "tools", None)
224
+ if tools:
225
+ value = tools.buildroot
222
226
  if value is None:
223
227
  value = self._envget(key)
224
228
  if type(value) is list:
@@ -238,6 +242,8 @@ class JoltFormatter(Formatter):
238
242
  return str(value).lower()
239
243
  elif conversion == "c":
240
244
  return value()
245
+ elif conversion == "t":
246
+ return str(value).title()
241
247
  elif conversion == "j":
242
248
  return " ".join(value)
243
249
  return super().convert_field(value, conversion)
jolt/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.9.419"
1
+ __version__ = "0.9.430"