jolt 0.9.123__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 +832 -362
- jolt/chroot.py +156 -0
- jolt/cli.py +281 -162
- jolt/common_pb2.py +63 -0
- jolt/common_pb2_grpc.py +4 -0
- jolt/config.py +98 -41
- jolt/error.py +19 -4
- jolt/filesystem.py +2 -6
- jolt/graph.py +705 -117
- jolt/hooks.py +43 -0
- jolt/influence.py +122 -3
- jolt/loader.py +369 -121
- jolt/log.py +225 -63
- jolt/manifest.py +28 -38
- jolt/options.py +35 -10
- 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 +5 -2
- jolt/plugins/autotools.py +66 -0
- jolt/plugins/cache.py +133 -0
- jolt/plugins/cmake.py +74 -6
- jolt/plugins/conan.py +238 -0
- jolt/plugins/cxx.py +698 -0
- jolt/plugins/cxxinfo.py +7 -0
- jolt/plugins/dashboard.py +1 -1
- jolt/plugins/docker.py +80 -23
- jolt/plugins/email.py +2 -2
- jolt/plugins/email.xslt +144 -101
- jolt/plugins/environ.py +11 -0
- jolt/plugins/fetch.py +141 -0
- jolt/plugins/gdb.py +39 -19
- jolt/plugins/gerrit.py +1 -14
- jolt/plugins/git.py +283 -85
- jolt/plugins/googletest.py +2 -1
- jolt/plugins/http.py +36 -38
- 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 +99 -30
- jolt/plugins/ninja.py +468 -166
- jolt/plugins/paths.py +11 -1
- jolt/plugins/pkgconfig.py +219 -0
- jolt/plugins/podman.py +136 -92
- jolt/plugins/python.py +137 -0
- jolt/plugins/remote_execution/__init__.py +0 -0
- jolt/plugins/remote_execution/administration_pb2.py +46 -0
- jolt/plugins/remote_execution/administration_pb2_grpc.py +170 -0
- jolt/plugins/remote_execution/log_pb2.py +32 -0
- jolt/plugins/remote_execution/log_pb2_grpc.py +68 -0
- jolt/plugins/remote_execution/scheduler_pb2.py +41 -0
- jolt/plugins/remote_execution/scheduler_pb2_grpc.py +141 -0
- jolt/plugins/remote_execution/worker_pb2.py +38 -0
- jolt/plugins/remote_execution/worker_pb2_grpc.py +112 -0
- jolt/plugins/report.py +12 -2
- jolt/plugins/rust.py +25 -0
- jolt/plugins/scheduler.py +710 -0
- jolt/plugins/selfdeploy/setup.py +8 -4
- jolt/plugins/selfdeploy.py +138 -88
- jolt/plugins/strings.py +35 -22
- jolt/plugins/symlinks.py +26 -11
- jolt/plugins/telemetry.py +5 -2
- jolt/plugins/timeline.py +13 -3
- jolt/plugins/volume.py +46 -48
- jolt/scheduler.py +589 -192
- jolt/tasks.py +625 -121
- jolt/templates/timeline.html.template +44 -47
- jolt/timer.py +22 -0
- jolt/tools.py +638 -282
- jolt/utils.py +211 -7
- jolt/version.py +1 -1
- jolt/xmldom.py +12 -2
- {jolt-0.9.123.dist-info → jolt-0.9.435.dist-info}/METADATA +97 -38
- jolt-0.9.435.dist-info/RECORD +207 -0
- {jolt-0.9.123.dist-info → jolt-0.9.435.dist-info}/WHEEL +1 -1
- jolt/plugins/amqp.py +0 -834
- jolt/plugins/debian.py +0 -338
- jolt/plugins/ftp.py +0 -181
- jolt/plugins/repo.py +0 -253
- jolt-0.9.123.dist-info/RECORD +0 -77
- {jolt-0.9.123.dist-info → jolt-0.9.435.dist-info}/entry_points.txt +0 -0
- {jolt-0.9.123.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,11 +37,12 @@ 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 = {}
|
|
35
44
|
self._original_head = True
|
|
45
|
+
self._last_rev = None
|
|
36
46
|
self._init_repo()
|
|
37
47
|
|
|
38
48
|
def _init_repo(self):
|
|
@@ -66,18 +76,64 @@ class GitRepository(object):
|
|
|
66
76
|
def is_indexed(self):
|
|
67
77
|
return self.is_cloned() and fs.path.exists(self._git_index())
|
|
68
78
|
|
|
69
|
-
def clone(self):
|
|
79
|
+
def clone(self, submodules=False):
|
|
70
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
|
|
71
92
|
if fs.path.exists(self.path):
|
|
72
93
|
with self.tools.cwd(self.path):
|
|
73
|
-
self.tools.run("git init
|
|
74
|
-
|
|
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)
|
|
75
116
|
else:
|
|
76
|
-
|
|
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
|
+
|
|
77
125
|
self._init_repo()
|
|
78
126
|
raise_error_if(
|
|
79
127
|
self.repository is None,
|
|
80
|
-
"
|
|
128
|
+
"Failed to clone repository '{0}'", self.relpath)
|
|
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)
|
|
81
137
|
|
|
82
138
|
@utils.cached.instance
|
|
83
139
|
def diff_unchecked(self):
|
|
@@ -95,7 +151,7 @@ class GitRepository(object):
|
|
|
95
151
|
|
|
96
152
|
def diff(self):
|
|
97
153
|
diff = self.diff_unchecked()
|
|
98
|
-
dlim = config.getsize("git", "maxdiffsize", "
|
|
154
|
+
dlim = config.getsize("git", "maxdiffsize", "1 MiB")
|
|
99
155
|
raise_error_if(
|
|
100
156
|
len(diff) > dlim,
|
|
101
157
|
"Repository '{}' has uncommitted changes. Size of patch exceeds configured transfer limit ({} > {} bytes)."
|
|
@@ -105,8 +161,8 @@ class GitRepository(object):
|
|
|
105
161
|
def patch(self, patch):
|
|
106
162
|
if not patch:
|
|
107
163
|
return
|
|
108
|
-
with self.tools.cwd(self.path), self.tools.tmpdir("git") as
|
|
109
|
-
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")
|
|
110
166
|
with open(patchfile, "wb") as f:
|
|
111
167
|
f.write(patch.encode())
|
|
112
168
|
log.info("Applying patch to {0}", self.path)
|
|
@@ -133,17 +189,18 @@ class GitRepository(object):
|
|
|
133
189
|
try:
|
|
134
190
|
commit = self.repository.revparse_single(rev)
|
|
135
191
|
except KeyError:
|
|
136
|
-
self.fetch()
|
|
192
|
+
self.fetch(commit=rev)
|
|
137
193
|
try:
|
|
138
194
|
commit = self.repository.revparse_single(rev)
|
|
139
195
|
except Exception:
|
|
140
|
-
raise_error("
|
|
196
|
+
raise_error("Invalid git reference: {}", rev)
|
|
141
197
|
try:
|
|
142
198
|
return str(commit.id)
|
|
143
199
|
except Exception:
|
|
144
200
|
return str(commit)
|
|
145
201
|
|
|
146
202
|
@utils.cached.instance
|
|
203
|
+
@workspace_locked
|
|
147
204
|
def write_tree(self):
|
|
148
205
|
tools = Tools()
|
|
149
206
|
with tools.cwd(self._git_folder()):
|
|
@@ -154,30 +211,30 @@ class GitRepository(object):
|
|
|
154
211
|
output_on_error=True)
|
|
155
212
|
return tree
|
|
156
213
|
|
|
157
|
-
def tree_hash(self,
|
|
158
|
-
# When
|
|
214
|
+
def tree_hash(self, rev=None, path="/"):
|
|
215
|
+
# When rev is None, the caller want the tree hash of the repository's
|
|
159
216
|
# current workspace state. If no checkout has been made, that would be the
|
|
160
217
|
# tree that was written upon initialization of the repository as it
|
|
161
218
|
# includes any uncommitted changes. If a checkout has been made since
|
|
162
219
|
# the repo was initialized, make this an explicit request for the current
|
|
163
220
|
# head - there can be no local changes.
|
|
164
|
-
if
|
|
221
|
+
if rev is None:
|
|
165
222
|
if self.is_original_head():
|
|
166
223
|
tree = self.repository.get(self.write_tree())
|
|
167
224
|
else:
|
|
168
|
-
|
|
225
|
+
rev = self.head()
|
|
169
226
|
|
|
170
227
|
path = fs.path.normpath(path)
|
|
171
228
|
full_path = fs.path.join(self.path, path) if path != "/" else self.path
|
|
172
229
|
|
|
173
230
|
# Lookup tree hash value in cache
|
|
174
|
-
value = self._tree_hash.get((full_path,
|
|
231
|
+
value = self._tree_hash.get((full_path, rev))
|
|
175
232
|
if value is not None:
|
|
176
233
|
return value
|
|
177
234
|
|
|
178
|
-
# Translate explicit
|
|
179
|
-
if
|
|
180
|
-
commit = self.rev_parse(
|
|
235
|
+
# Translate explicit rev to tree
|
|
236
|
+
if rev is not None:
|
|
237
|
+
commit = self.rev_parse(rev)
|
|
181
238
|
obj = self.repository.get(commit)
|
|
182
239
|
try:
|
|
183
240
|
tree = obj.tree
|
|
@@ -189,7 +246,7 @@ class GitRepository(object):
|
|
|
189
246
|
tree = tree[fs.as_posix(path)]
|
|
190
247
|
|
|
191
248
|
# Update tree hash cache
|
|
192
|
-
self._tree_hash[(full_path,
|
|
249
|
+
self._tree_hash[(full_path, rev)] = value = tree.id
|
|
193
250
|
|
|
194
251
|
return value
|
|
195
252
|
|
|
@@ -201,24 +258,49 @@ class GitRepository(object):
|
|
|
201
258
|
with self.tools.cwd(self.path):
|
|
202
259
|
return self.tools.run("git reset --hard", output_on_error=True)
|
|
203
260
|
|
|
204
|
-
|
|
261
|
+
@utils.retried.on_exception(JoltCommandError, pattern="Command failed: git fetch", count=6, backoff=[2, 5, 10, 15, 20, 30])
|
|
262
|
+
def fetch(self, commit=None):
|
|
263
|
+
if commit and not self.is_valid_sha(commit):
|
|
264
|
+
commit = None
|
|
265
|
+
|
|
266
|
+
# Get configurable extra clone options
|
|
267
|
+
extra_fetch_options = config.get("git", "fetch_options", "")
|
|
268
|
+
|
|
205
269
|
refspec = " ".join(self.default_refspecs + self.refspecs)
|
|
206
270
|
with self.tools.cwd(self.path):
|
|
207
|
-
log.info("Fetching {0} from {1}", refspec or 'commits', self.url)
|
|
208
|
-
self.tools.run(
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
271
|
+
log.info("Fetching {0} from {1}", commit or refspec or 'commits', self.url)
|
|
272
|
+
self.tools.run(
|
|
273
|
+
"git fetch --force --prune {extra_fetch_options} {url} {what}",
|
|
274
|
+
extra_fetch_options=extra_fetch_options,
|
|
275
|
+
url=self.url,
|
|
276
|
+
what=commit or refspec or '',
|
|
277
|
+
output_on_error=True)
|
|
278
|
+
|
|
279
|
+
def checkout(self, rev, commit=None, submodules=False):
|
|
280
|
+
if rev == self._last_rev:
|
|
281
|
+
log.debug("Checkout skipped, already @ {}", rev)
|
|
282
|
+
return False
|
|
283
|
+
log.verbose("Checking out {0} in {1}", rev, self.path)
|
|
215
284
|
with self.tools.cwd(self.path):
|
|
216
285
|
try:
|
|
217
|
-
|
|
286
|
+
self.tools.run("git checkout -f {rev}", rev=rev, output=False)
|
|
287
|
+
if submodules:
|
|
288
|
+
self._update_submodules()
|
|
218
289
|
except Exception:
|
|
219
|
-
self.fetch()
|
|
220
|
-
|
|
290
|
+
self.fetch(commit=commit)
|
|
291
|
+
try:
|
|
292
|
+
self.tools.run("git checkout -f {rev}", rev=rev, output_on_error=True)
|
|
293
|
+
if submodules:
|
|
294
|
+
self._update_submodules()
|
|
295
|
+
except Exception:
|
|
296
|
+
raise_error("Commit does not exist in remote for '{}': {}", self.relpath, rev)
|
|
221
297
|
self._original_head = False
|
|
298
|
+
self._last_rev = rev
|
|
299
|
+
return True
|
|
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)
|
|
222
304
|
|
|
223
305
|
|
|
224
306
|
_gits = {}
|
|
@@ -228,9 +310,9 @@ def new_git(url, path, relpath, refspecs=None):
|
|
|
228
310
|
refspecs = utils.as_list(refspecs or [])
|
|
229
311
|
try:
|
|
230
312
|
git = _gits[path]
|
|
231
|
-
raise_error_if(git.url != url, "
|
|
313
|
+
raise_error_if(git.url != url, "Multiple git repositories required at {}", relpath)
|
|
232
314
|
raise_error_if(git.refspecs != refspecs,
|
|
233
|
-
"
|
|
315
|
+
"Conflicting refspecs detected for git repository at {}", relpath)
|
|
234
316
|
return git
|
|
235
317
|
except Exception:
|
|
236
318
|
git = _gits[path] = GitRepository(url, path, relpath, refspecs)
|
|
@@ -241,7 +323,7 @@ class GitInfluenceProvider(FileInfluence):
|
|
|
241
323
|
name = "Git"
|
|
242
324
|
|
|
243
325
|
def __init__(self, path):
|
|
244
|
-
super(
|
|
326
|
+
super().__init__(path)
|
|
245
327
|
self.path = path.rstrip(fs.sep)
|
|
246
328
|
self.name = GitInfluenceProvider.name
|
|
247
329
|
|
|
@@ -256,7 +338,7 @@ class GitInfluenceProvider(FileInfluence):
|
|
|
256
338
|
return path
|
|
257
339
|
ppath = path
|
|
258
340
|
path = fs.path.dirname(path)
|
|
259
|
-
raise_error("
|
|
341
|
+
raise_error("No git repository found at '{}'", self.path)
|
|
260
342
|
|
|
261
343
|
@utils.cached.instance
|
|
262
344
|
def get_influence(self, task):
|
|
@@ -304,23 +386,101 @@ def influence(path, git_cls=GitInfluenceProvider):
|
|
|
304
386
|
return _decorate
|
|
305
387
|
|
|
306
388
|
|
|
307
|
-
class
|
|
308
|
-
"""
|
|
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):
|
|
309
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
|
+
|
|
440
|
+
"""
|
|
441
|
+
name = "git"
|
|
310
442
|
|
|
311
|
-
name = "git-src"
|
|
312
443
|
url = Parameter(help="URL to the git repo to be cloned. Required.")
|
|
313
|
-
|
|
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
|
+
|
|
314
452
|
path = Parameter(required=False, help="Local path where the repository should be cloned.")
|
|
315
|
-
|
|
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
|
+
|
|
316
461
|
_revision = Export(value=lambda t: t._export_revision())
|
|
462
|
+
""" To worker exported value of the revision to be checked out. """
|
|
463
|
+
|
|
317
464
|
_diff = Export(value=lambda t: t.git.diff(), encoded=True)
|
|
465
|
+
""" To worker exported value of the diff of the repo. """
|
|
318
466
|
|
|
319
467
|
def __init__(self, *args, **kwargs):
|
|
320
|
-
super(
|
|
468
|
+
super().__init__(*args, **kwargs)
|
|
469
|
+
self._lock = RLock()
|
|
321
470
|
self.joltdir = JoltLoader.get().joltdir
|
|
322
|
-
|
|
323
|
-
|
|
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
|
|
324
484
|
self.refspecs = kwargs.get("refspecs", [])
|
|
325
485
|
self.git = new_git(self.url, self.abspath, self.relpath, self.refspecs)
|
|
326
486
|
|
|
@@ -331,72 +491,113 @@ class GitSrc(WorkspaceResource, FileInfluence):
|
|
|
331
491
|
return name
|
|
332
492
|
|
|
333
493
|
def _export_revision(self):
|
|
334
|
-
return self.
|
|
494
|
+
return self.rev.value or self.git.head()
|
|
335
495
|
|
|
336
496
|
def _get_revision(self):
|
|
337
497
|
if self._revision.is_imported:
|
|
338
498
|
return self._revision.value
|
|
339
|
-
if not self.
|
|
340
|
-
return self.
|
|
499
|
+
if not self.rev.is_unset():
|
|
500
|
+
return self.rev.get_value()
|
|
341
501
|
return None
|
|
342
502
|
|
|
343
|
-
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):
|
|
344
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)
|
|
345
546
|
|
|
346
|
-
def acquire_ws(self):
|
|
347
|
-
|
|
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:
|
|
348
550
|
self._acquire_ws()
|
|
349
551
|
|
|
552
|
+
@locked
|
|
350
553
|
def _acquire_ws(self):
|
|
554
|
+
commit = None
|
|
351
555
|
if not self.git.is_cloned():
|
|
352
|
-
self.git.clone()
|
|
556
|
+
self.git.clone(submodules=bool(self.submodules))
|
|
353
557
|
if not self._revision.is_imported:
|
|
354
558
|
self.git.diff_unchecked()
|
|
559
|
+
else:
|
|
560
|
+
commit = self._revision.value
|
|
355
561
|
rev = self._get_revision()
|
|
356
562
|
if rev is not None:
|
|
357
563
|
raise_task_error_if(
|
|
358
|
-
not self._revision.is_imported and not self.
|
|
359
|
-
"
|
|
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)
|
|
360
566
|
# Should be safe to do this now
|
|
361
567
|
rev = self.git.rev_parse(rev)
|
|
362
568
|
if not self.git.is_head(rev) or self._revision.is_imported:
|
|
363
|
-
self.git.checkout(rev)
|
|
364
|
-
|
|
365
|
-
|
|
569
|
+
if self.git.checkout(rev, commit=commit, submodules=bool(self.submodules)):
|
|
570
|
+
self.git.clean()
|
|
571
|
+
self.git.patch(self._diff.value)
|
|
366
572
|
|
|
367
|
-
def
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
def is_influenced_by(self, task, path):
|
|
371
|
-
return fs.is_relative_to(path, self.abspath) and self.sha.is_set()
|
|
573
|
+
def _must_influence(self):
|
|
574
|
+
""" Check if the git repo must influence the hash of the consumer task."""
|
|
372
575
|
|
|
576
|
+
# If the hash parameter is set, honor it
|
|
577
|
+
if self.hash.is_set():
|
|
578
|
+
return self.hash
|
|
373
579
|
|
|
374
|
-
|
|
580
|
+
# If the revision parameter is not set, the git repo must influence the hash
|
|
581
|
+
if self.rev.is_unset():
|
|
582
|
+
return True
|
|
375
583
|
|
|
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
|
|
376
587
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
Also influences the hash of consuming tasks, causing tasks to
|
|
381
|
-
be re-executed if the cloned repo is modified.
|
|
382
|
-
|
|
383
|
-
"""
|
|
384
|
-
name = "git"
|
|
385
|
-
url = Parameter(help="URL to the git repo to be cloned. Required.")
|
|
386
|
-
sha = Parameter(required=False, help="Specific commit or tag to be checked out. Optional.")
|
|
387
|
-
path = Parameter(required=False, help="Local path where the repository should be cloned.")
|
|
388
|
-
defer = None
|
|
389
|
-
_revision = Export(value=lambda t: t._export_revision())
|
|
390
|
-
_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)
|
|
391
591
|
|
|
392
|
-
def
|
|
393
|
-
super(
|
|
394
|
-
self.
|
|
592
|
+
def _influence(self):
|
|
593
|
+
influence = super()._influence()
|
|
594
|
+
return influence + [self] if self._must_influence() else influence
|
|
395
595
|
|
|
596
|
+
@locked
|
|
396
597
|
@utils.cached.instance
|
|
397
598
|
def get_influence(self, task):
|
|
398
599
|
if not self.git.is_cloned():
|
|
399
|
-
self.git.clone()
|
|
600
|
+
self.git.clone(submodules=bool(self.submodules))
|
|
400
601
|
if not self._revision.is_imported:
|
|
401
602
|
self.git.diff_unchecked()
|
|
402
603
|
rev = self._get_revision()
|
|
@@ -411,8 +612,5 @@ class Git(GitSrc):
|
|
|
411
612
|
|
|
412
613
|
return "{0}: {1}".format(self.git.relpath, th)
|
|
413
614
|
|
|
414
|
-
def is_influenced_by(self, task, path):
|
|
415
|
-
return path.startswith(self.abspath + fs.sep)
|
|
416
|
-
|
|
417
615
|
|
|
418
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
|
|
@@ -473,6 +473,7 @@ def shuffle(default: bool = False, param: bool = True, attr: str = "shuffle"):
|
|
|
473
473
|
@brief()
|
|
474
474
|
@disabled()
|
|
475
475
|
@fail_fast()
|
|
476
|
+
@filter()
|
|
476
477
|
@junit_report()
|
|
477
478
|
@repeat()
|
|
478
479
|
@seed()
|