jolt 0.9.172__py3-none-any.whl → 0.9.435__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.
- jolt/__init__.py +80 -7
- jolt/__main__.py +9 -1
- jolt/bin/fstree-darwin-x86_64 +0 -0
- jolt/bin/fstree-linux-x86_64 +0 -0
- jolt/cache.py +596 -252
- jolt/chroot.py +36 -11
- jolt/cli.py +143 -130
- jolt/common_pb2.py +45 -45
- jolt/config.py +76 -40
- jolt/error.py +19 -4
- jolt/filesystem.py +2 -6
- jolt/graph.py +400 -82
- jolt/influence.py +110 -3
- jolt/loader.py +338 -174
- jolt/log.py +127 -31
- jolt/manifest.py +13 -46
- jolt/options.py +35 -11
- 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 +24 -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 +87 -0
- jolt/pkgs/zstd.py +33 -0
- jolt/plugins/alias.py +3 -0
- jolt/plugins/allure.py +2 -2
- jolt/plugins/autotools.py +66 -0
- jolt/plugins/cache.py +1 -1
- jolt/plugins/cmake.py +74 -6
- jolt/plugins/conan.py +238 -0
- jolt/plugins/cxxinfo.py +7 -0
- jolt/plugins/docker.py +76 -19
- jolt/plugins/email.xslt +141 -118
- jolt/plugins/environ.py +11 -0
- jolt/plugins/fetch.py +141 -0
- jolt/plugins/gdb.py +33 -14
- jolt/plugins/gerrit.py +0 -13
- jolt/plugins/git.py +248 -66
- jolt/plugins/googletest.py +1 -1
- jolt/plugins/http.py +1 -1
- jolt/plugins/libtool.py +63 -0
- jolt/plugins/linux.py +990 -0
- jolt/plugins/logstash.py +4 -4
- jolt/plugins/meson.py +61 -0
- jolt/plugins/ninja-compdb.py +96 -28
- jolt/plugins/ninja.py +424 -150
- jolt/plugins/paths.py +11 -1
- jolt/plugins/pkgconfig.py +219 -0
- jolt/plugins/podman.py +131 -87
- jolt/plugins/python.py +137 -0
- jolt/plugins/remote_execution/administration_pb2.py +27 -19
- jolt/plugins/remote_execution/log_pb2.py +12 -12
- jolt/plugins/remote_execution/scheduler_pb2.py +23 -23
- jolt/plugins/remote_execution/worker_pb2.py +19 -19
- jolt/plugins/report.py +7 -2
- jolt/plugins/rust.py +25 -0
- jolt/plugins/scheduler.py +135 -86
- jolt/plugins/selfdeploy/setup.py +6 -6
- jolt/plugins/selfdeploy.py +49 -31
- jolt/plugins/strings.py +35 -22
- jolt/plugins/symlinks.py +11 -4
- jolt/plugins/telemetry.py +1 -2
- jolt/plugins/timeline.py +13 -3
- jolt/scheduler.py +467 -165
- jolt/tasks.py +427 -111
- jolt/templates/timeline.html.template +44 -47
- jolt/timer.py +22 -0
- jolt/tools.py +527 -188
- jolt/utils.py +183 -3
- jolt/version.py +1 -1
- jolt/xmldom.py +12 -2
- {jolt-0.9.172.dist-info → jolt-0.9.435.dist-info}/METADATA +97 -41
- jolt-0.9.435.dist-info/RECORD +207 -0
- {jolt-0.9.172.dist-info → jolt-0.9.435.dist-info}/WHEEL +1 -1
- jolt/plugins/amqp.py +0 -855
- jolt/plugins/debian.py +0 -338
- jolt/plugins/repo.py +0 -253
- jolt/plugins/snap.py +0 -122
- jolt-0.9.172.dist-info/RECORD +0 -92
- {jolt-0.9.172.dist-info → jolt-0.9.435.dist-info}/entry_points.txt +0 -0
- {jolt-0.9.172.dist-info → jolt-0.9.435.dist-info}/top_level.txt +0 -0
jolt/plugins/git.py
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import pygit2
|
|
3
3
|
import re
|
|
4
|
+
from threading import RLock
|
|
5
|
+
import urllib.parse
|
|
4
6
|
|
|
5
|
-
from jolt.tasks import BooleanParameter, Export, Parameter, TaskRegistry, WorkspaceResource
|
|
7
|
+
from jolt.tasks import BooleanParameter, Export, IntParameter, Parameter, TaskRegistry, WorkspaceResource
|
|
6
8
|
from jolt.influence import FileInfluence, HashInfluenceRegistry
|
|
7
9
|
from jolt.tools import Tools
|
|
8
|
-
from jolt.loader import JoltLoader
|
|
10
|
+
from jolt.loader import JoltLoader, workspace_locked
|
|
9
11
|
from jolt import config
|
|
10
12
|
from jolt import filesystem as fs
|
|
11
13
|
from jolt import log
|
|
@@ -19,6 +21,13 @@ from jolt.error import raise_task_error_if
|
|
|
19
21
|
log.verbose("[Git] Loaded")
|
|
20
22
|
|
|
21
23
|
|
|
24
|
+
def locked(func):
|
|
25
|
+
def _f(self, *args, **kwargs):
|
|
26
|
+
with self._lock:
|
|
27
|
+
return func(self, *args, **kwargs)
|
|
28
|
+
return _f
|
|
29
|
+
|
|
30
|
+
|
|
22
31
|
class GitRepository(object):
|
|
23
32
|
def __init__(self, url, path, relpath, refspecs=None):
|
|
24
33
|
self.path = path
|
|
@@ -28,7 +37,7 @@ class GitRepository(object):
|
|
|
28
37
|
self.url = url
|
|
29
38
|
self.default_refspecs = [
|
|
30
39
|
'+refs/heads/*:refs/remotes/origin/*',
|
|
31
|
-
'+refs/tags/*:refs/
|
|
40
|
+
'+refs/tags/*:refs/tags/*',
|
|
32
41
|
]
|
|
33
42
|
self.refspecs = refspecs or []
|
|
34
43
|
self._tree_hash = {}
|
|
@@ -67,19 +76,65 @@ class GitRepository(object):
|
|
|
67
76
|
def is_indexed(self):
|
|
68
77
|
return self.is_cloned() and fs.path.exists(self._git_index())
|
|
69
78
|
|
|
70
|
-
def clone(self):
|
|
79
|
+
def clone(self, submodules=False):
|
|
71
80
|
log.info("Cloning into {0}", self.path)
|
|
81
|
+
|
|
82
|
+
# Get reference repository path
|
|
83
|
+
refroot = config.get("git", "reference", None)
|
|
84
|
+
refpath = None
|
|
85
|
+
if refroot:
|
|
86
|
+
# Append <host>/<path> to the reference root
|
|
87
|
+
url = urllib.parse.urlparse(str(self.url))
|
|
88
|
+
refpath = fs.path.join(refroot, url.hostname, url.path.lstrip("/"))
|
|
89
|
+
refpath = fs.path.abspath(refpath)
|
|
90
|
+
|
|
91
|
+
# If the directory exists, initialize the repository instead of cloning
|
|
72
92
|
if fs.path.exists(self.path):
|
|
73
93
|
with self.tools.cwd(self.path):
|
|
74
|
-
self.tools.run("git init
|
|
75
|
-
|
|
94
|
+
self.tools.run("git init", output_on_error=True)
|
|
95
|
+
|
|
96
|
+
# Set the reference repository if available
|
|
97
|
+
if refpath:
|
|
98
|
+
# Check if the reference repository is a git repository
|
|
99
|
+
objpath = os.path.join(refpath, ".git", "objects")
|
|
100
|
+
objpath_bare = os.path.join(refpath, "objects")
|
|
101
|
+
if os.path.isdir(objpath):
|
|
102
|
+
refpath = objpath
|
|
103
|
+
elif os.path.isdir(objpath_bare):
|
|
104
|
+
refpath = objpath_bare
|
|
105
|
+
else:
|
|
106
|
+
refpath = None
|
|
107
|
+
|
|
108
|
+
if refpath:
|
|
109
|
+
self.tools.mkdir(".git/objects/info")
|
|
110
|
+
self.tools.write_file(".git/objects/info/alternates", refpath)
|
|
111
|
+
|
|
112
|
+
utils.call_and_catch(self.tools.run, "git remote remove origin", output=False)
|
|
113
|
+
self.tools.run("git remote add origin {}", self.url, output_on_error=True)
|
|
114
|
+
self._fetch_origin(submodules=submodules)
|
|
115
|
+
self.tools.run("git checkout -f FETCH_HEAD", output_on_error=True)
|
|
76
116
|
else:
|
|
77
|
-
|
|
117
|
+
# Get configurable extra clone options
|
|
118
|
+
extra_clone_options = config.get("git", "clone_options", "")
|
|
119
|
+
|
|
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)
|
|
122
|
+
else:
|
|
123
|
+
self.tools.run("git clone {0} {1} {2}", extra_clone_options, self.url, self.path, output_on_error=True)
|
|
124
|
+
|
|
78
125
|
self._init_repo()
|
|
79
126
|
raise_error_if(
|
|
80
127
|
self.repository is None,
|
|
81
128
|
"Failed to clone repository '{0}'", self.relpath)
|
|
82
129
|
|
|
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, submodules=False):
|
|
132
|
+
# Get configurable extra clone options
|
|
133
|
+
extra_fetch_options = config.get("git", "fetch_options", "")
|
|
134
|
+
|
|
135
|
+
with self.tools.cwd(self.path):
|
|
136
|
+
self.tools.run("git fetch {0} {1} origin", "", extra_fetch_options, output_on_error=True)
|
|
137
|
+
|
|
83
138
|
@utils.cached.instance
|
|
84
139
|
def diff_unchecked(self):
|
|
85
140
|
if not self.is_indexed():
|
|
@@ -96,7 +151,7 @@ class GitRepository(object):
|
|
|
96
151
|
|
|
97
152
|
def diff(self):
|
|
98
153
|
diff = self.diff_unchecked()
|
|
99
|
-
dlim = config.getsize("git", "maxdiffsize", "
|
|
154
|
+
dlim = config.getsize("git", "maxdiffsize", "1 MiB")
|
|
100
155
|
raise_error_if(
|
|
101
156
|
len(diff) > dlim,
|
|
102
157
|
"Repository '{}' has uncommitted changes. Size of patch exceeds configured transfer limit ({} > {} bytes)."
|
|
@@ -106,8 +161,8 @@ class GitRepository(object):
|
|
|
106
161
|
def patch(self, patch):
|
|
107
162
|
if not patch:
|
|
108
163
|
return
|
|
109
|
-
with self.tools.cwd(self.path), self.tools.tmpdir("git") as
|
|
110
|
-
patchfile = fs.path.join(
|
|
164
|
+
with self.tools.cwd(self.path), self.tools.tmpdir("git") as tmp:
|
|
165
|
+
patchfile = fs.path.join(tmp, "jolt.diff")
|
|
111
166
|
with open(patchfile, "wb") as f:
|
|
112
167
|
f.write(patch.encode())
|
|
113
168
|
log.info("Applying patch to {0}", self.path)
|
|
@@ -145,6 +200,7 @@ class GitRepository(object):
|
|
|
145
200
|
return str(commit)
|
|
146
201
|
|
|
147
202
|
@utils.cached.instance
|
|
203
|
+
@workspace_locked
|
|
148
204
|
def write_tree(self):
|
|
149
205
|
tools = Tools()
|
|
150
206
|
with tools.cwd(self._git_folder()):
|
|
@@ -155,30 +211,30 @@ class GitRepository(object):
|
|
|
155
211
|
output_on_error=True)
|
|
156
212
|
return tree
|
|
157
213
|
|
|
158
|
-
def tree_hash(self,
|
|
159
|
-
# When
|
|
214
|
+
def tree_hash(self, rev=None, path="/"):
|
|
215
|
+
# When rev is None, the caller want the tree hash of the repository's
|
|
160
216
|
# current workspace state. If no checkout has been made, that would be the
|
|
161
217
|
# tree that was written upon initialization of the repository as it
|
|
162
218
|
# includes any uncommitted changes. If a checkout has been made since
|
|
163
219
|
# the repo was initialized, make this an explicit request for the current
|
|
164
220
|
# head - there can be no local changes.
|
|
165
|
-
if
|
|
221
|
+
if rev is None:
|
|
166
222
|
if self.is_original_head():
|
|
167
223
|
tree = self.repository.get(self.write_tree())
|
|
168
224
|
else:
|
|
169
|
-
|
|
225
|
+
rev = self.head()
|
|
170
226
|
|
|
171
227
|
path = fs.path.normpath(path)
|
|
172
228
|
full_path = fs.path.join(self.path, path) if path != "/" else self.path
|
|
173
229
|
|
|
174
230
|
# Lookup tree hash value in cache
|
|
175
|
-
value = self._tree_hash.get((full_path,
|
|
231
|
+
value = self._tree_hash.get((full_path, rev))
|
|
176
232
|
if value is not None:
|
|
177
233
|
return value
|
|
178
234
|
|
|
179
|
-
# Translate explicit
|
|
180
|
-
if
|
|
181
|
-
commit = self.rev_parse(
|
|
235
|
+
# Translate explicit rev to tree
|
|
236
|
+
if rev is not None:
|
|
237
|
+
commit = self.rev_parse(rev)
|
|
182
238
|
obj = self.repository.get(commit)
|
|
183
239
|
try:
|
|
184
240
|
tree = obj.tree
|
|
@@ -190,7 +246,7 @@ class GitRepository(object):
|
|
|
190
246
|
tree = tree[fs.as_posix(path)]
|
|
191
247
|
|
|
192
248
|
# Update tree hash cache
|
|
193
|
-
self._tree_hash[(full_path,
|
|
249
|
+
self._tree_hash[(full_path, rev)] = value = tree.id
|
|
194
250
|
|
|
195
251
|
return value
|
|
196
252
|
|
|
@@ -202,37 +258,50 @@ class GitRepository(object):
|
|
|
202
258
|
with self.tools.cwd(self.path):
|
|
203
259
|
return self.tools.run("git reset --hard", output_on_error=True)
|
|
204
260
|
|
|
261
|
+
@utils.retried.on_exception(JoltCommandError, pattern="Command failed: git fetch", count=6, backoff=[2, 5, 10, 15, 20, 30])
|
|
205
262
|
def fetch(self, commit=None):
|
|
206
263
|
if commit and not self.is_valid_sha(commit):
|
|
207
264
|
commit = None
|
|
208
265
|
|
|
266
|
+
# Get configurable extra clone options
|
|
267
|
+
extra_fetch_options = config.get("git", "fetch_options", "")
|
|
268
|
+
|
|
209
269
|
refspec = " ".join(self.default_refspecs + self.refspecs)
|
|
210
270
|
with self.tools.cwd(self.path):
|
|
211
271
|
log.info("Fetching {0} from {1}", commit or refspec or 'commits', self.url)
|
|
212
272
|
self.tools.run(
|
|
213
|
-
"git fetch {url} {what}",
|
|
273
|
+
"git fetch --force --prune {extra_fetch_options} {url} {what}",
|
|
274
|
+
extra_fetch_options=extra_fetch_options,
|
|
214
275
|
url=self.url,
|
|
215
276
|
what=commit or refspec or '',
|
|
216
277
|
output_on_error=True)
|
|
217
278
|
|
|
218
|
-
def checkout(self, rev, commit=None):
|
|
279
|
+
def checkout(self, rev, commit=None, submodules=False):
|
|
219
280
|
if rev == self._last_rev:
|
|
220
281
|
log.debug("Checkout skipped, already @ {}", rev)
|
|
221
282
|
return False
|
|
222
|
-
log.
|
|
283
|
+
log.verbose("Checking out {0} in {1}", rev, self.path)
|
|
223
284
|
with self.tools.cwd(self.path):
|
|
224
285
|
try:
|
|
225
286
|
self.tools.run("git checkout -f {rev}", rev=rev, output=False)
|
|
287
|
+
if submodules:
|
|
288
|
+
self._update_submodules()
|
|
226
289
|
except Exception:
|
|
227
290
|
self.fetch(commit=commit)
|
|
228
291
|
try:
|
|
229
292
|
self.tools.run("git checkout -f {rev}", rev=rev, output_on_error=True)
|
|
293
|
+
if submodules:
|
|
294
|
+
self._update_submodules()
|
|
230
295
|
except Exception:
|
|
231
296
|
raise_error("Commit does not exist in remote for '{}': {}", self.relpath, rev)
|
|
232
297
|
self._original_head = False
|
|
233
298
|
self._last_rev = rev
|
|
234
299
|
return True
|
|
235
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
|
+
|
|
236
305
|
|
|
237
306
|
_gits = {}
|
|
238
307
|
|
|
@@ -317,23 +386,101 @@ def influence(path, git_cls=GitInfluenceProvider):
|
|
|
317
386
|
return _decorate
|
|
318
387
|
|
|
319
388
|
|
|
320
|
-
class
|
|
321
|
-
"""
|
|
389
|
+
class ErrorDict(dict):
|
|
390
|
+
""" A dict that raises an error if the value of a key is None. """
|
|
391
|
+
|
|
392
|
+
def __init__(self, repo):
|
|
393
|
+
self.repo = repo
|
|
394
|
+
|
|
395
|
+
def __getitem__(self, key):
|
|
396
|
+
value = super().__getitem__(key)
|
|
397
|
+
raise_task_error_if(value is None, self.repo, "Git repository '{0}' referenced in influence collection before being cloned/checked out. Assign hash=true to the git requirement.", key)
|
|
398
|
+
return value
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
class Git(WorkspaceResource, FileInfluence):
|
|
402
|
+
"""
|
|
403
|
+
Resource that clones and monitors a Git repo.
|
|
404
|
+
|
|
405
|
+
By default, the repo is cloned into a build directory named after
|
|
406
|
+
the resource. The 'path' parameter can be used to specify a different
|
|
407
|
+
location relative to the workspace root.
|
|
408
|
+
|
|
409
|
+
The path of the cloned repo is made available to consuming tasks
|
|
410
|
+
through their 'git' attribute. The 'git' attribute is a dictionary
|
|
411
|
+
where the key is the name of the git repository and the value is
|
|
412
|
+
the relative path to the repository from the consuming task's
|
|
413
|
+
workspace.
|
|
414
|
+
|
|
415
|
+
The resource influences the hash of consuming tasks, causing tasks
|
|
416
|
+
to be re-executed if the cloned repo is modified.
|
|
417
|
+
|
|
418
|
+
The plugin must be loaded before it can be used. This is done by
|
|
419
|
+
importing the module, or by adding the following line to the
|
|
420
|
+
configuration file:
|
|
421
|
+
|
|
422
|
+
.. code-block:: ini
|
|
423
|
+
|
|
424
|
+
[git]
|
|
425
|
+
|
|
426
|
+
Example:
|
|
427
|
+
|
|
428
|
+
.. code-block:: python
|
|
429
|
+
|
|
430
|
+
from jolt.plugins import git
|
|
431
|
+
|
|
432
|
+
class Example(Task):
|
|
433
|
+
requires = ["git:url=https://github.com/user/repo.git"]
|
|
434
|
+
|
|
435
|
+
def run(self, deps, tools):
|
|
436
|
+
self.info("The git repo is located at: {git[repo]}")
|
|
437
|
+
with tools.cwd(self.git["repo"]):
|
|
438
|
+
tools.run("make")
|
|
439
|
+
|
|
322
440
|
"""
|
|
441
|
+
name = "git"
|
|
323
442
|
|
|
324
|
-
name = "git-src"
|
|
325
443
|
url = Parameter(help="URL to the git repo to be cloned. Required.")
|
|
326
|
-
|
|
444
|
+
""" URL to the git repo to be cloned. Required. """
|
|
445
|
+
|
|
446
|
+
rev = Parameter(required=False, help="Specific commit or tag to be checked out. Optional.")
|
|
447
|
+
""" Specific commit or tag to be checked out. Optional. """
|
|
448
|
+
|
|
449
|
+
hash = BooleanParameter(required=False, help="Let repo content influence the hash of consuming tasks.")
|
|
450
|
+
""" Let repo content influence the hash of consuming tasks. Default ``True``. Optional. """
|
|
451
|
+
|
|
327
452
|
path = Parameter(required=False, help="Local path where the repository should be cloned.")
|
|
328
|
-
|
|
453
|
+
""" Alternative path where the repository should be cloned. Relative to ``joltdir``. Optional. """
|
|
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
|
+
|
|
329
461
|
_revision = Export(value=lambda t: t._export_revision())
|
|
462
|
+
""" To worker exported value of the revision to be checked out. """
|
|
463
|
+
|
|
330
464
|
_diff = Export(value=lambda t: t.git.diff(), encoded=True)
|
|
465
|
+
""" To worker exported value of the diff of the repo. """
|
|
331
466
|
|
|
332
467
|
def __init__(self, *args, **kwargs):
|
|
333
468
|
super().__init__(*args, **kwargs)
|
|
469
|
+
self._lock = RLock()
|
|
334
470
|
self.joltdir = JoltLoader.get().joltdir
|
|
335
|
-
|
|
336
|
-
|
|
471
|
+
|
|
472
|
+
# Set the path to the repo
|
|
473
|
+
if self.path.is_unset():
|
|
474
|
+
self.abspath = self.tools.builddir(utils.canonical(self.short_qualified_name), incremental="always", unique=False)
|
|
475
|
+
self.relpath = fs.path.relpath(self.abspath, self.tools.wsroot)
|
|
476
|
+
else:
|
|
477
|
+
self.abspath = fs.path.join(self.joltdir, str(self.path) or self._get_name())
|
|
478
|
+
self.relpath = fs.path.relpath(self.abspath, self.tools.wsroot)
|
|
479
|
+
|
|
480
|
+
self.abspath = fs.path.normpath(self.abspath)
|
|
481
|
+
self.relpath = fs.path.normpath(self.relpath)
|
|
482
|
+
|
|
483
|
+
# Create the git repository
|
|
337
484
|
self.refspecs = kwargs.get("refspecs", [])
|
|
338
485
|
self.git = new_git(self.url, self.abspath, self.relpath, self.refspecs)
|
|
339
486
|
|
|
@@ -344,26 +491,69 @@ class GitSrc(WorkspaceResource, FileInfluence):
|
|
|
344
491
|
return name
|
|
345
492
|
|
|
346
493
|
def _export_revision(self):
|
|
347
|
-
return self.
|
|
494
|
+
return self.rev.value or self.git.head()
|
|
348
495
|
|
|
349
496
|
def _get_revision(self):
|
|
350
497
|
if self._revision.is_imported:
|
|
351
498
|
return self._revision.value
|
|
352
|
-
if not self.
|
|
353
|
-
return self.
|
|
499
|
+
if not self.rev.is_unset():
|
|
500
|
+
return self.rev.get_value()
|
|
354
501
|
return None
|
|
355
502
|
|
|
356
|
-
def
|
|
503
|
+
def _assign_git(self, task, none=False):
|
|
504
|
+
if not hasattr(task, "git"):
|
|
505
|
+
task.git = ErrorDict(self)
|
|
506
|
+
if none:
|
|
507
|
+
# None means the git repo is not cloned or checked out
|
|
508
|
+
# and should not be included in the git dictionary
|
|
509
|
+
# of the consuming task yet. If the consuming task
|
|
510
|
+
# requires the git repo for its influence collection,
|
|
511
|
+
# the dict will raise an error. The solution is to
|
|
512
|
+
# assign hash=true to the git requirement which
|
|
513
|
+
# will cause the git repo to be cloned and checked out
|
|
514
|
+
# before the influence collection is performed.
|
|
515
|
+
task.git[self._get_name()] = None
|
|
516
|
+
else:
|
|
517
|
+
# Assign the git repo to the consuming task.
|
|
518
|
+
# The git repo is cloned and checked out before
|
|
519
|
+
# any influence collection is performed.
|
|
520
|
+
task.git[self._get_name()] = fs.path.relpath(self.abspath, task.joltdir)
|
|
521
|
+
|
|
522
|
+
def acquire(self, artifact, deps, tools, owner):
|
|
357
523
|
self._acquire_ws()
|
|
524
|
+
self._assign_git(owner)
|
|
525
|
+
artifact.worktree = fs.path.relpath(self.abspath, owner.joltdir)
|
|
526
|
+
|
|
527
|
+
def release(self, artifact, deps, tools, owner):
|
|
528
|
+
if self.clean:
|
|
529
|
+
self.git.clean()
|
|
530
|
+
self.git.reset()
|
|
531
|
+
|
|
532
|
+
def prepare_ws_for(self, task):
|
|
533
|
+
""" Prepare the workspace for the task.
|
|
534
|
+
|
|
535
|
+
:param task: The task to prepare the workspace for.
|
|
536
|
+
"""
|
|
537
|
+
if not self._must_influence():
|
|
538
|
+
# The content of the git repo is not required to influence the hash of the
|
|
539
|
+
# consumer task. The repo is therefore not cloned or checked out
|
|
540
|
+
# until the consumer is executed. Raise an error if the git repo
|
|
541
|
+
# is required for the influence collection of the consumer task.
|
|
542
|
+
self._assign_git(task, none=True)
|
|
543
|
+
return
|
|
544
|
+
# The content of the git repo is required to influence the hash of the consumer task.
|
|
545
|
+
self._assign_git(task)
|
|
358
546
|
|
|
359
|
-
def acquire_ws(self):
|
|
360
|
-
|
|
547
|
+
def acquire_ws(self, force=False):
|
|
548
|
+
""" Clone and/or checkout the git repo if required """
|
|
549
|
+
if force or self._must_influence() or self._revision.is_imported:
|
|
361
550
|
self._acquire_ws()
|
|
362
551
|
|
|
552
|
+
@locked
|
|
363
553
|
def _acquire_ws(self):
|
|
364
554
|
commit = None
|
|
365
555
|
if not self.git.is_cloned():
|
|
366
|
-
self.git.clone()
|
|
556
|
+
self.git.clone(submodules=bool(self.submodules))
|
|
367
557
|
if not self._revision.is_imported:
|
|
368
558
|
self.git.diff_unchecked()
|
|
369
559
|
else:
|
|
@@ -371,48 +561,43 @@ class GitSrc(WorkspaceResource, FileInfluence):
|
|
|
371
561
|
rev = self._get_revision()
|
|
372
562
|
if rev is not None:
|
|
373
563
|
raise_task_error_if(
|
|
374
|
-
not self._revision.is_imported and not self.
|
|
375
|
-
"
|
|
564
|
+
not self._revision.is_imported and not self.rev.is_unset() and self.git.diff(), self,
|
|
565
|
+
"Explicit revision requested but git repo '{0}' has local changes, refusing checkout", self.git.relpath)
|
|
376
566
|
# Should be safe to do this now
|
|
377
567
|
rev = self.git.rev_parse(rev)
|
|
378
568
|
if not self.git.is_head(rev) or self._revision.is_imported:
|
|
379
|
-
if self.git.checkout(rev, commit=commit):
|
|
569
|
+
if self.git.checkout(rev, commit=commit, submodules=bool(self.submodules)):
|
|
380
570
|
self.git.clean()
|
|
381
571
|
self.git.patch(self._diff.value)
|
|
382
572
|
|
|
383
|
-
def
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
def is_influenced_by(self, task, path):
|
|
387
|
-
return fs.is_relative_to(path, self.abspath) and self.sha.is_set()
|
|
388
|
-
|
|
573
|
+
def _must_influence(self):
|
|
574
|
+
""" Check if the git repo must influence the hash of the consumer task."""
|
|
389
575
|
|
|
390
|
-
|
|
576
|
+
# If the hash parameter is set, honor it
|
|
577
|
+
if self.hash.is_set():
|
|
578
|
+
return self.hash
|
|
391
579
|
|
|
580
|
+
# If the revision parameter is not set, the git repo must influence the hash
|
|
581
|
+
if self.rev.is_unset():
|
|
582
|
+
return True
|
|
392
583
|
|
|
393
|
-
|
|
394
|
-
|
|
584
|
+
# If the revision parameter is set, no influence is needed since the
|
|
585
|
+
# revision is fixed and repository content will not change.
|
|
586
|
+
return False
|
|
395
587
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
"""
|
|
400
|
-
name = "git"
|
|
401
|
-
url = Parameter(help="URL to the git repo to be cloned. Required.")
|
|
402
|
-
sha = Parameter(required=False, help="Specific commit or tag to be checked out. Optional.")
|
|
403
|
-
path = Parameter(required=False, help="Local path where the repository should be cloned.")
|
|
404
|
-
defer = None
|
|
405
|
-
_revision = Export(value=lambda t: t._export_revision())
|
|
406
|
-
_diff = Export(value=lambda t: t.git.diff(), encoded=True)
|
|
588
|
+
def is_influenced_by(self, task, path):
|
|
589
|
+
influencing = self._must_influence() or self.rev.is_set()
|
|
590
|
+
return influencing and fs.is_relative_to(path, self.abspath)
|
|
407
591
|
|
|
408
|
-
def
|
|
409
|
-
super().
|
|
410
|
-
self.
|
|
592
|
+
def _influence(self):
|
|
593
|
+
influence = super()._influence()
|
|
594
|
+
return influence + [self] if self._must_influence() else influence
|
|
411
595
|
|
|
596
|
+
@locked
|
|
412
597
|
@utils.cached.instance
|
|
413
598
|
def get_influence(self, task):
|
|
414
599
|
if not self.git.is_cloned():
|
|
415
|
-
self.git.clone()
|
|
600
|
+
self.git.clone(submodules=bool(self.submodules))
|
|
416
601
|
if not self._revision.is_imported:
|
|
417
602
|
self.git.diff_unchecked()
|
|
418
603
|
rev = self._get_revision()
|
|
@@ -427,8 +612,5 @@ class Git(GitSrc):
|
|
|
427
612
|
|
|
428
613
|
return "{0}: {1}".format(self.git.relpath, th)
|
|
429
614
|
|
|
430
|
-
def is_influenced_by(self, task, path):
|
|
431
|
-
return path.startswith(self.abspath + fs.sep)
|
|
432
|
-
|
|
433
615
|
|
|
434
616
|
TaskRegistry.get().add_task_class(Git)
|
jolt/plugins/googletest.py
CHANGED
|
@@ -212,7 +212,7 @@ def filter(default: str = "*", param: bool = True, attr: str = "filter"):
|
|
|
212
212
|
Task class decorator controlling the GTEST_FILTER environment variable.
|
|
213
213
|
|
|
214
214
|
The variable instructs test applications to only run test-cases that matches
|
|
215
|
-
a wildcard filter string (default:
|
|
215
|
+
a wildcard filter string (default: ``*``).
|
|
216
216
|
|
|
217
217
|
The value is taken from the parameter ``filter`` which is created
|
|
218
218
|
by default. If no parameter is created, the value is instead taken from the class
|
jolt/plugins/http.py
CHANGED
|
@@ -23,7 +23,7 @@ class Http(cache.StorageProvider):
|
|
|
23
23
|
def __init__(self, cache):
|
|
24
24
|
super(Http, self).__init__()
|
|
25
25
|
self._cache = cache
|
|
26
|
-
self._uri = config.get(NAME, "uri", "http://cache
|
|
26
|
+
self._uri = config.get(NAME, "uri", "http://cache")
|
|
27
27
|
self._uri = self._uri.rstrip("/")
|
|
28
28
|
raise_error_if(not self._uri, "HTTP URI not configured")
|
|
29
29
|
self._upload = config.getboolean(NAME, "upload", True)
|
jolt/plugins/libtool.py
ADDED
|
@@ -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
|