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/cmake.py CHANGED
@@ -1,3 +1,4 @@
1
+ from jolt import attributes
1
2
  from jolt import influence
2
3
  from jolt import Task
3
4
  from jolt import utils
@@ -6,31 +7,98 @@ from jolt.error import raise_task_error_if
6
7
  import os
7
8
 
8
9
 
10
+ def options(attrib):
11
+ """
12
+ Decorates a CMake task with an alternative ``options`` attribute.
13
+
14
+ The new attribute will be concatenated with the regular
15
+ ``options`` attribute.
16
+
17
+ Args:
18
+ attrib (str): Name of alternative attribute.
19
+ Keywords are expanded.
20
+ """
21
+ return utils.concat_attributes("options", attrib)
22
+
23
+
24
+ def requires(version=None):
25
+ """ Decorator to add CMake requirements to a task. """
26
+
27
+ import jolt.pkgs.cmake
28
+
29
+ def decorate(cls):
30
+ cls = attributes.requires("requires_cmake")(cls)
31
+ cls.requires_cmake = ["cmake" + (f":version={version}" if version else "")]
32
+ return cls
33
+
34
+ return decorate
35
+
36
+
37
+ def use_ninja():
38
+ """
39
+ Decorator to add Ninja dependencies to CMake task.
40
+
41
+ It also selects Ninja as the CMake generator and builder.
42
+ """
43
+
44
+ import jolt.pkgs.ninja
45
+
46
+ def decorate(cls):
47
+ cls = attributes.requires("requires_ninja")(cls)
48
+ cls.generator = "Ninja"
49
+ cls.requires_ninja = ["ninja"]
50
+ return cls
51
+
52
+ return decorate
53
+
54
+
55
+ @attributes.common_metadata()
56
+ @options("options")
9
57
  class CMake(Task):
10
58
  """ Builds and publishes a CMake project """
11
-
12
59
  abstract = True
13
60
 
14
61
  cmakelists = "CMakeLists.txt"
15
62
  """ Path to CMakeLists.txt or directory containing CMakelists.txt """
16
63
 
64
+ config = "Release"
65
+ """ The default build configuration to use """
66
+
17
67
  generator = None
68
+ """ The build file generator that CMake should use """
18
69
 
19
70
  incremental = True
71
+ """ Keep build directories between Jolt invocations """
20
72
 
21
73
  options = []
22
74
  """ List of options and their values (``option[:type]=value``) """
23
75
 
76
+ srcdir = None
77
+ """ Source directory. If not specified, the task working directory is used. """
78
+
79
+ install = ["install"]
80
+ """ List of install build targets. If empty, the default install target is used. """
81
+
82
+ def clean(self, tools):
83
+ cmake = tools.cmake(incremental=self.incremental)
84
+ cmake.clean()
85
+
24
86
  def run(self, deps, tools):
87
+ self.deps = deps
25
88
  raise_task_error_if(not self.cmakelists, self, "cmakelists attribute has not been defined")
26
89
 
27
- cmake = tools.cmake(incremental=self.incremental)
28
- cmake.configure(tools.expand(self.cmakelists), *["-D" + tools.expand(option) for option in self.options], generator=self.generator)
29
- cmake.build()
30
- cmake.install()
90
+ config = tools.expand(str(self.config))
91
+ options = self._options()
92
+ options += ["CMAKE_BUILD_TYPE=" + config]
93
+
94
+ with tools.cwd(self.srcdir or self.joltdir):
95
+ cmake = tools.cmake(deps, incremental=self.incremental)
96
+ cmake.configure(tools.expand(self.cmakelists), *["-D" + tools.expand(option) for option in options], generator=self.generator)
97
+ for target in self.install or ["install"]:
98
+ cmake.install(config=config, target=target)
31
99
 
32
100
  def publish(self, artifact, tools):
33
- cmake = tools.cmake()
101
+ cmake = tools.cmake(incremental=self.incremental)
34
102
  cmake.publish(artifact)
35
103
 
36
104
 
jolt/plugins/cxxinfo.py CHANGED
@@ -1,4 +1,5 @@
1
1
  from jolt.cache import ArtifactListAttribute
2
+ from jolt.cache import ArtifactStringAttribute
2
3
  from jolt.cache import ArtifactAttributeSet
3
4
  from jolt.cache import ArtifactAttributeSetProvider
4
5
 
@@ -7,6 +8,10 @@ class CppInfoListVariable(ArtifactListAttribute):
7
8
  pass
8
9
 
9
10
 
11
+ class CppInfoStringVariable(ArtifactStringAttribute):
12
+ pass
13
+
14
+
10
15
  class CppInfoDictVariable(ArtifactListAttribute):
11
16
  def __init__(self, artifact, name):
12
17
  super(CppInfoDictVariable, self).__init__(artifact, name)
@@ -26,6 +31,8 @@ class CppInfo(ArtifactAttributeSet):
26
31
  return CppInfoListVariable(self._artifact, "asflags")
27
32
  if name == "cflags":
28
33
  return CppInfoListVariable(self._artifact, "cflags")
34
+ if name == "crt":
35
+ return CppInfoStringVariable(self._artifact, "crt")
29
36
  if name == "cxxflags":
30
37
  return CppInfoListVariable(self._artifact, "cxxflags")
31
38
  if name == "incpaths":
jolt/plugins/fetch.py ADDED
@@ -0,0 +1,141 @@
1
+ import hashlib
2
+ from jolt import BooleanParameter, Parameter
3
+ from jolt.plugins.git import ErrorDict
4
+ from jolt.tasks import Resource, TaskRegistry
5
+ from jolt import filesystem as fs
6
+ from jolt import utils
7
+ from jolt.error import raise_error_if
8
+ from jolt.loader import JoltLoader
9
+ from jolt.tools import SUPPORTED_ARCHIVE_TYPES
10
+
11
+
12
+ class Fetch(Resource):
13
+ """
14
+ Fetch a file from a URL and extract it.
15
+
16
+ By default, the fetched file is extracted if it is a supported archive type.
17
+ Extraction may be disable by assigning the `extract` parameter to false.
18
+
19
+ The fetched content is placed in a build directory named after the resource.
20
+ The `path` parameter can be used to specify a different location relative to
21
+ the workspace root.
22
+
23
+ The path of the fetched content is made available to consuming tasks through
24
+ the `fetch` attribute. The `fetch` attribute is a dictionary where the key
25
+ is the name of the fetched file and the value is a path relative to the
26
+ workspace root. You can specify an alias for the filename / key through the
27
+ `alias` parameter.
28
+
29
+ The plugin must be loaded before it can be used. This is done by importing
30
+ the module, or by adding the following line to the configuration file:
31
+
32
+ .. code-block:: ini
33
+
34
+ [fetch]
35
+
36
+
37
+ Example:
38
+
39
+ .. code-block:: python
40
+
41
+ from jolt.plugins import fetch
42
+
43
+ class Example(Task):
44
+ requires = ["fetch:alias=zlib,url=https://zlib.net/zlib-1.3.1.tar.gz"]
45
+
46
+ def run(self, deps, tools):
47
+ self.info("The source tree is located at: {fetch[zlib]}")
48
+ with tools.cwd(self.fetch["zlib"]):
49
+ tools.run("make")
50
+
51
+ """
52
+
53
+ name = "fetch"
54
+ alias = Parameter(required=False, help="Name of the task used when referencing content. Defaults to the filename of the fetched file.")
55
+ extract = BooleanParameter(default=True, help="Whether to extract the fetched file.")
56
+ path = Parameter(required=False, help="Destination directory.")
57
+ url = Parameter(help="URL to fetch from.")
58
+ md5 = Parameter(required=False, help="Expected MD5 hash of the fetched file.")
59
+ sha256 = Parameter(required=False, help="Expected SHA256 hash of the fetched file.")
60
+
61
+ def __init__(self, *args, **kwargs):
62
+ super().__init__(*args, **kwargs)
63
+ self.joltdir = JoltLoader.get().joltdir
64
+
65
+ # Set the path to the extraction directory
66
+ if self.path.is_unset():
67
+ self.abspath = self.tools.builddir(utils.canonical(self.short_qualified_name), incremental="always", unique=False)
68
+ if not self._extract():
69
+ # Join with filename if not extracting
70
+ self.abspath = fs.path.join(self.abspath, self._get_filename())
71
+ else:
72
+ self.abspath = fs.path.join(self.joltdir, str(self.path) or self._get_name())
73
+
74
+ self.relpath = fs.path.relpath(self.abspath, self.tools.wsroot)
75
+
76
+ def _extract(self):
77
+ """ Check if the fetched file should/can be extracted. """
78
+ filename = self._get_filename()
79
+
80
+ if not any([filename.endswith(ext) for ext in SUPPORTED_ARCHIVE_TYPES]):
81
+ return False
82
+
83
+ return bool(self.extract)
84
+
85
+ def _acquire_ws(self):
86
+ # Create the destination directory if it does not exist
87
+ self.tools.rmtree(self.abspath, ignore_errors=True)
88
+ self.tools.mkdir(fs.path.dirname(self.abspath), recursively=True)
89
+
90
+ if self._extract():
91
+ with self.tools.tmpdir() as tmpdir, self.tools.cwd(tmpdir):
92
+ filename = self._get_filename()
93
+ self.tools.download(self.url, filename)
94
+ self._verify_sha256(filename)
95
+ self.tools.extract(filename, self.abspath)
96
+ else:
97
+ self.tools.download(self.url, self.abspath)
98
+ self._verify_sha256(self.abspath)
99
+
100
+ def acquire(self, artifact, deps, tools, owner):
101
+ self._acquire_ws()
102
+ self._assign_fetch(owner)
103
+ artifact.worktree = fs.path.relpath(self.abspath, owner.joltdir)
104
+
105
+ def _assign_fetch(self, task, none=False):
106
+ if not hasattr(task, "fetch"):
107
+ task.fetch = ErrorDict(self)
108
+ if none:
109
+ # None means the git repo is not cloned or checked out
110
+ # and should not be included in the git dictionary
111
+ # of the consuming task yet. If the consuming task
112
+ # requires the git repo for its influence collection,
113
+ # the dict will raise an error. The solution is to
114
+ # assign hash=true to the git requirement which
115
+ # will cause the git repo to be cloned and checked out
116
+ # before the influence collection is performed.
117
+ task.fetch[self._get_name()] = None
118
+ else:
119
+ # Assign the git repo to the consuming task.
120
+ # The git repo is cloned and checked out before
121
+ # any influence collection is performed.
122
+ task.fetch[self._get_name()] = fs.path.relpath(self.abspath, task.joltdir)
123
+
124
+ def _get_name(self):
125
+ return str(self.alias) if self.alias.is_set() else self._get_filename()
126
+
127
+ def _get_filename(self):
128
+ return fs.path.basename(str(self.url))
129
+
130
+ def _verify_sha256(self, filepath):
131
+ if not self.sha256.is_set():
132
+ return
133
+ actual_hash = self.tools.checksum_file(filepath, hashfn=hashlib.sha256)
134
+ expected_hash = str(self.sha256)
135
+ raise_error_if(
136
+ actual_hash != expected_hash,
137
+ f"SHA256 hash mismatch for fetched file '{filepath}': expected {expected_hash}, got {actual_hash}"
138
+ )
139
+
140
+
141
+ TaskRegistry.get().add_task_class(Fetch)
jolt/plugins/git.py CHANGED
@@ -4,7 +4,7 @@ import re
4
4
  from threading import RLock
5
5
  import urllib.parse
6
6
 
7
- from jolt.tasks import BooleanParameter, Export, Parameter, TaskRegistry, WorkspaceResource
7
+ from jolt.tasks import BooleanParameter, Export, IntParameter, Parameter, TaskRegistry, WorkspaceResource
8
8
  from jolt.influence import FileInfluence, HashInfluenceRegistry
9
9
  from jolt.tools import Tools
10
10
  from jolt.loader import JoltLoader, workspace_locked
@@ -37,7 +37,7 @@ class GitRepository(object):
37
37
  self.url = url
38
38
  self.default_refspecs = [
39
39
  '+refs/heads/*:refs/remotes/origin/*',
40
- '+refs/tags/*:refs/remotes/origin/*',
40
+ '+refs/tags/*:refs/tags/*',
41
41
  ]
42
42
  self.refspecs = refspecs or []
43
43
  self._tree_hash = {}
@@ -76,7 +76,7 @@ class GitRepository(object):
76
76
  def is_indexed(self):
77
77
  return self.is_cloned() and fs.path.exists(self._git_index())
78
78
 
79
- def clone(self):
79
+ def clone(self, submodules=False):
80
80
  log.info("Cloning into {0}", self.path)
81
81
 
82
82
  # Get reference repository path
@@ -111,14 +111,14 @@ class GitRepository(object):
111
111
 
112
112
  utils.call_and_catch(self.tools.run, "git remote remove origin", output=False)
113
113
  self.tools.run("git remote add origin {}", self.url, output_on_error=True)
114
- self._fetch_origin()
114
+ self._fetch_origin(submodules=submodules)
115
115
  self.tools.run("git checkout -f FETCH_HEAD", output_on_error=True)
116
116
  else:
117
117
  # Get configurable extra clone options
118
118
  extra_clone_options = config.get("git", "clone_options", "")
119
119
 
120
120
  if refpath and os.path.isdir(refpath):
121
- self.tools.run("git clone --reference-if-able {0} {1} {2} {3}", refpath, extra_clone_options, self.url, self.path, output_on_error=True)
121
+ self.tools.run("git clone --reference-if-able {0} {1} {2} {3}", refpath, extra_clone_options, self.url, self.path, output_on_error=True)
122
122
  else:
123
123
  self.tools.run("git clone {0} {1} {2}", extra_clone_options, self.url, self.path, output_on_error=True)
124
124
 
@@ -128,12 +128,12 @@ class GitRepository(object):
128
128
  "Failed to clone repository '{0}'", self.relpath)
129
129
 
130
130
  @utils.retried.on_exception(JoltCommandError, pattern="Command failed: git fetch", count=6, backoff=[2, 5, 10, 15, 20, 30])
131
- def _fetch_origin(self):
131
+ def _fetch_origin(self, submodules=False):
132
132
  # Get configurable extra clone options
133
133
  extra_fetch_options = config.get("git", "fetch_options", "")
134
134
 
135
135
  with self.tools.cwd(self.path):
136
- self.tools.run("git fetch {0} origin", extra_fetch_options, output_on_error=True)
136
+ self.tools.run("git fetch {0} {1} origin", "", extra_fetch_options, output_on_error=True)
137
137
 
138
138
  @utils.cached.instance
139
139
  def diff_unchecked(self):
@@ -276,7 +276,7 @@ class GitRepository(object):
276
276
  what=commit or refspec or '',
277
277
  output_on_error=True)
278
278
 
279
- def checkout(self, rev, commit=None):
279
+ def checkout(self, rev, commit=None, submodules=False):
280
280
  if rev == self._last_rev:
281
281
  log.debug("Checkout skipped, already @ {}", rev)
282
282
  return False
@@ -284,16 +284,24 @@ class GitRepository(object):
284
284
  with self.tools.cwd(self.path):
285
285
  try:
286
286
  self.tools.run("git checkout -f {rev}", rev=rev, output=False)
287
+ if submodules:
288
+ self._update_submodules()
287
289
  except Exception:
288
290
  self.fetch(commit=commit)
289
291
  try:
290
292
  self.tools.run("git checkout -f {rev}", rev=rev, output_on_error=True)
293
+ if submodules:
294
+ self._update_submodules()
291
295
  except Exception:
292
296
  raise_error("Commit does not exist in remote for '{}': {}", self.relpath, rev)
293
297
  self._original_head = False
294
298
  self._last_rev = rev
295
299
  return True
296
300
 
301
+ def _update_submodules(self):
302
+ with self.tools.cwd(self.path):
303
+ self.tools.run("git submodule update --init --recursive", output_on_error=True)
304
+
297
305
 
298
306
  _gits = {}
299
307
 
@@ -444,6 +452,12 @@ class Git(WorkspaceResource, FileInfluence):
444
452
  path = Parameter(required=False, help="Local path where the repository should be cloned.")
445
453
  """ Alternative path where the repository should be cloned. Relative to ``joltdir``. Optional. """
446
454
 
455
+ submodules = BooleanParameter(default=False, help="Initialize and update git submodules after cloning.")
456
+ """ Initialize and update git submodules after cloning. Default ``False``. Optional. """
457
+
458
+ clean = BooleanParameter(default=False, help="Clean repository after it has been used")
459
+ """ Removes untracked files from the repository. """
460
+
447
461
  _revision = Export(value=lambda t: t._export_revision())
448
462
  """ To worker exported value of the revision to be checked out. """
449
463
 
@@ -463,6 +477,9 @@ class Git(WorkspaceResource, FileInfluence):
463
477
  self.abspath = fs.path.join(self.joltdir, str(self.path) or self._get_name())
464
478
  self.relpath = fs.path.relpath(self.abspath, self.tools.wsroot)
465
479
 
480
+ self.abspath = fs.path.normpath(self.abspath)
481
+ self.relpath = fs.path.normpath(self.relpath)
482
+
466
483
  # Create the git repository
467
484
  self.refspecs = kwargs.get("refspecs", [])
468
485
  self.git = new_git(self.url, self.abspath, self.relpath, self.refspecs)
@@ -507,6 +524,11 @@ class Git(WorkspaceResource, FileInfluence):
507
524
  self._assign_git(owner)
508
525
  artifact.worktree = fs.path.relpath(self.abspath, owner.joltdir)
509
526
 
527
+ def release(self, artifact, deps, tools, owner):
528
+ if self.clean:
529
+ self.git.clean()
530
+ self.git.reset()
531
+
510
532
  def prepare_ws_for(self, task):
511
533
  """ Prepare the workspace for the task.
512
534
 
@@ -531,7 +553,7 @@ class Git(WorkspaceResource, FileInfluence):
531
553
  def _acquire_ws(self):
532
554
  commit = None
533
555
  if not self.git.is_cloned():
534
- self.git.clone()
556
+ self.git.clone(submodules=bool(self.submodules))
535
557
  if not self._revision.is_imported:
536
558
  self.git.diff_unchecked()
537
559
  else:
@@ -544,7 +566,7 @@ class Git(WorkspaceResource, FileInfluence):
544
566
  # Should be safe to do this now
545
567
  rev = self.git.rev_parse(rev)
546
568
  if not self.git.is_head(rev) or self._revision.is_imported:
547
- if self.git.checkout(rev, commit=commit):
569
+ if self.git.checkout(rev, commit=commit, submodules=bool(self.submodules)):
548
570
  self.git.clean()
549
571
  self.git.patch(self._diff.value)
550
572
 
@@ -575,7 +597,7 @@ class Git(WorkspaceResource, FileInfluence):
575
597
  @utils.cached.instance
576
598
  def get_influence(self, task):
577
599
  if not self.git.is_cloned():
578
- self.git.clone()
600
+ self.git.clone(submodules=bool(self.submodules))
579
601
  if not self._revision.is_imported:
580
602
  self.git.diff_unchecked()
581
603
  rev = self._get_revision()
@@ -0,0 +1,63 @@
1
+ from jolt import attributes
2
+
3
+
4
+ class Libtool(object):
5
+ def __init__(self, tools):
6
+ self.tools = tools
7
+
8
+ def relocate(self, artifact, dirs=["lib"], prefix=None):
9
+ prefix = str(artifact.strings.install_prefix) if prefix is None else prefix
10
+ for dir in dirs:
11
+ with self.tools.cwd(artifact.path, dir):
12
+ for file in self.tools.glob("*.la"):
13
+ self.tools.replace_in_file(file, prefix, artifact.final_path)
14
+
15
+
16
+ def relocate(dirs=["lib"]):
17
+ """
18
+ Relocate libtool archive files (.la) published by task.
19
+
20
+ When an artifact is published, all .la files found in the specified
21
+ directories will have their install prefix updated to the artifact's final path.
22
+ The original install prefix is stored in the artifact's strings metadata
23
+ under the key 'libtool_prefix' for use during unpacking.
24
+
25
+ :param dirs: List of directories inside the artifact to relocate .la files in.
26
+
27
+ """
28
+
29
+ def decorate(cls):
30
+ original_publish = cls.publish
31
+ original_unpack = cls.unpack
32
+
33
+ def publish(self, artifact, tools):
34
+ original_publish(self, artifact, tools)
35
+ lt = Libtool(tools)
36
+ lt.relocate(artifact, dirs, prefix=artifact.strings.install_prefix)
37
+ artifact.libtool_prefix = artifact.final_path
38
+
39
+ def unpack(self, artifact, tools):
40
+ original_unpack(self, artifact, tools)
41
+ lt = Libtool(tools)
42
+ lt.relocate(artifact, dirs, prefix=artifact.strings.libtool_prefix)
43
+ artifact.strings.libtool_prefix = None
44
+
45
+ cls.publish = publish
46
+ cls.unpack = unpack
47
+
48
+ return cls
49
+
50
+ return decorate
51
+
52
+
53
+ def requires():
54
+ """ Decorator to add Libtool requirement to a task. """
55
+
56
+ import jolt.pkgs.libtool
57
+
58
+ def decorate(cls):
59
+ cls = attributes.requires("requires_libtool")(cls)
60
+ cls.requires_libtool = ["libtool"]
61
+ return cls
62
+
63
+ return decorate
jolt/plugins/meson.py ADDED
@@ -0,0 +1,61 @@
1
+ from jolt import Task, attributes
2
+
3
+
4
+ @attributes.common_metadata()
5
+ class Meson(Task):
6
+ """ Base class for Meson-based build tasks. """
7
+
8
+ abstract = True
9
+ """ This is an abstract base class that should be inherited by concrete tasks. """
10
+
11
+ incremental = True
12
+ """
13
+ Whether to use incremental builds.
14
+ If True, the build directories are preserved between runs.
15
+ """
16
+
17
+ options = []
18
+ """
19
+ Additional options to pass to the `meson` command.
20
+ """
21
+
22
+ srcdir = None
23
+ """
24
+ Source directory for the Meson project.
25
+
26
+ If None, defaults to the task work directory (joltdir).
27
+ """
28
+
29
+ def clean(self, tools):
30
+ at = tools.meson(incremental=self.incremental)
31
+ at.clean()
32
+
33
+ def run(self, deps, tools):
34
+ self.deps = deps
35
+ options = tools.expand(self.options)
36
+ at = tools.meson(deps, incremental=self.incremental)
37
+ at.configure(self.srcdir or self.joltdir, *options)
38
+ at.build()
39
+ at.install()
40
+
41
+ def publish(self, artifact, tools):
42
+ at = tools.meson(incremental=self.incremental)
43
+ at.publish(artifact)
44
+
45
+
46
+ def requires(meson=True, ninja=True):
47
+ """ Decorator to add Meson and Ninja requirements to a task. """
48
+
49
+ import jolt.pkgs.meson
50
+ import jolt.pkgs.ninja
51
+
52
+ def decorate(cls):
53
+ if meson:
54
+ cls = attributes.requires("requires_meson")(cls)
55
+ cls.requires_meson = ["meson"]
56
+ if ninja:
57
+ cls = attributes.requires("requires_ninja")(cls)
58
+ cls.requires_ninja = ["ninja"]
59
+ return cls
60
+
61
+ return decorate