buildstream-plugins 2.5.0.dev0__tar.gz → 2.8.0.dev0__tar.gz
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.
- {buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0}/.asf.yaml +13 -1
- {buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0}/NEWS +16 -0
- {buildstream-plugins-2.5.0.dev0/src/buildstream_plugins.egg-info → buildstream_plugins-2.8.0.dev0}/PKG-INFO +14 -3
- {buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0}/pyproject.toml +2 -7
- {buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0}/setup.py +1 -1
- {buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0}/src/buildstream_plugins/__init__.py +1 -1
- {buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0}/src/buildstream_plugins/sources/cargo.py +36 -4
- {buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0}/src/buildstream_plugins/sources/docker.py +91 -40
- {buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0/src/buildstream_plugins.egg-info}/PKG-INFO +14 -3
- {buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0}/COMMITTERS.rst +0 -0
- {buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0}/LICENSE +0 -0
- {buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0}/MANIFEST.in +0 -0
- {buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0}/NOTICE +0 -0
- {buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0}/README.rst +0 -0
- {buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0}/project.conf +0 -0
- {buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0}/requirements/mypy-requirements.txt +0 -0
- {buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0}/requirements/plugin-requirements.txt +0 -0
- {buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0}/requirements/test-requirements.txt +0 -0
- {buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0}/setup.cfg +0 -0
- {buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0}/src/buildstream_plugins/elements/__init__.py +0 -0
- {buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0}/src/buildstream_plugins/elements/autotools.py +0 -0
- {buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0}/src/buildstream_plugins/elements/autotools.yaml +0 -0
- {buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0}/src/buildstream_plugins/elements/cmake.py +0 -0
- {buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0}/src/buildstream_plugins/elements/cmake.yaml +0 -0
- {buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0}/src/buildstream_plugins/elements/make.py +0 -0
- {buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0}/src/buildstream_plugins/elements/make.yaml +0 -0
- {buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0}/src/buildstream_plugins/elements/meson.py +0 -0
- {buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0}/src/buildstream_plugins/elements/meson.yaml +0 -0
- {buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0}/src/buildstream_plugins/elements/pip.py +0 -0
- {buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0}/src/buildstream_plugins/elements/pip.yaml +0 -0
- {buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0}/src/buildstream_plugins/elements/setuptools.py +0 -0
- {buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0}/src/buildstream_plugins/elements/setuptools.yaml +0 -0
- {buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0}/src/buildstream_plugins/sourcemirrors/__init__.py +0 -0
- {buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0}/src/buildstream_plugins/sourcemirrors/gitlab_lfs_mirror.py +0 -0
- {buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0}/src/buildstream_plugins/sourcemirrors/simple_mirror.py +0 -0
- {buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0}/src/buildstream_plugins/sources/__init__.py +0 -0
- {buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0}/src/buildstream_plugins/sources/_utils.py +0 -0
- {buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0}/src/buildstream_plugins/sources/bzr.py +0 -0
- {buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0}/src/buildstream_plugins/sources/git.py +0 -0
- {buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0}/src/buildstream_plugins/sources/patch.py +0 -0
- {buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0}/src/buildstream_plugins/sources/pip.py +0 -0
- {buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0}/src/buildstream_plugins.egg-info/SOURCES.txt +0 -0
- {buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0}/src/buildstream_plugins.egg-info/dependency_links.txt +0 -0
- {buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0}/src/buildstream_plugins.egg-info/entry_points.txt +0 -0
- {buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0}/src/buildstream_plugins.egg-info/not-zip-safe +0 -0
- {buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0}/src/buildstream_plugins.egg-info/requires.txt +0 -0
- {buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0}/src/buildstream_plugins.egg-info/top_level.txt +0 -0
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
#
|
|
3
2
|
# Avoid diluting the dev mailing list with meta stuff,
|
|
4
3
|
# redirect it all to the commit list.
|
|
@@ -40,3 +39,16 @@ github:
|
|
|
40
39
|
# Enable pages publishing
|
|
41
40
|
ghp_branch: gh-pages
|
|
42
41
|
ghp_path: /docs
|
|
42
|
+
rulesets:
|
|
43
|
+
- name: "Default Branch Protection"
|
|
44
|
+
type: branch
|
|
45
|
+
branches:
|
|
46
|
+
includes:
|
|
47
|
+
- "~DEFAULT_BRANCH"
|
|
48
|
+
- "release/*"
|
|
49
|
+
- "rel/*"
|
|
50
|
+
excludes: []
|
|
51
|
+
bypass_teams:
|
|
52
|
+
- root
|
|
53
|
+
restrict_deletion: true
|
|
54
|
+
restrict_force_push: true
|
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
=========================
|
|
2
|
+
buildstream-plugins 2.8.0
|
|
3
|
+
=========================
|
|
4
|
+
|
|
5
|
+
o docker: support OCI images (#105)
|
|
6
|
+
|
|
7
|
+
=========================
|
|
8
|
+
buildstream-plugins 2.7.0
|
|
9
|
+
=========================
|
|
10
|
+
|
|
11
|
+
o cargo: Support source provenance (#98)
|
|
12
|
+
|
|
13
|
+
o Fix multiple issues in the Docker source plugin (#96)
|
|
14
|
+
|
|
15
|
+
o Support Python 3.14 and drop support for Python 3.9 (#94, #97)
|
|
16
|
+
|
|
1
17
|
=========================
|
|
2
18
|
buildstream-plugins 2.5.0
|
|
3
19
|
=========================
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: buildstream-plugins
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.8.0.dev0
|
|
4
4
|
Summary: A collection of plugins for BuildStream.
|
|
5
5
|
Home-page: https://buildstream.build
|
|
6
6
|
Author: The Apache Software Foundation
|
|
@@ -15,17 +15,28 @@ Classifier: Intended Audience :: Developers
|
|
|
15
15
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
16
16
|
Classifier: Operating System :: POSIX
|
|
17
17
|
Classifier: Programming Language :: Python :: 3
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
19
18
|
Classifier: Programming Language :: Python :: 3.10
|
|
20
19
|
Classifier: Programming Language :: Python :: 3.11
|
|
21
20
|
Classifier: Programming Language :: Python :: 3.12
|
|
22
21
|
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
23
23
|
Classifier: Topic :: Software Development :: Build Tools
|
|
24
24
|
Description-Content-Type: text/x-rst; charset=UTF-8
|
|
25
25
|
License-File: LICENSE
|
|
26
26
|
License-File: NOTICE
|
|
27
27
|
Provides-Extra: cargo
|
|
28
28
|
Requires-Dist: tomli; python_version < "3.11" and extra == "cargo"
|
|
29
|
+
Dynamic: author
|
|
30
|
+
Dynamic: author-email
|
|
31
|
+
Dynamic: classifier
|
|
32
|
+
Dynamic: description
|
|
33
|
+
Dynamic: description-content-type
|
|
34
|
+
Dynamic: home-page
|
|
35
|
+
Dynamic: license
|
|
36
|
+
Dynamic: license-file
|
|
37
|
+
Dynamic: project-url
|
|
38
|
+
Dynamic: provides-extra
|
|
39
|
+
Dynamic: summary
|
|
29
40
|
|
|
30
41
|
BuildStream Plugins
|
|
31
42
|
===================
|
|
@@ -12,13 +12,8 @@
|
|
|
12
12
|
# limitations under the License.
|
|
13
13
|
#
|
|
14
14
|
[build-system]
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
"setuptools>=36.6.0",
|
|
18
|
-
# In order to build wheels, and as required by PEP 517
|
|
19
|
-
"wheel",
|
|
20
|
-
"Cython"
|
|
21
|
-
]
|
|
15
|
+
# We need at least version 36.6.0 that introduced "build_meta"
|
|
16
|
+
requires = ["setuptools>=36.6.0"]
|
|
22
17
|
build-backend = "setuptools.build_meta"
|
|
23
18
|
|
|
24
19
|
[tool.black]
|
|
@@ -53,11 +53,11 @@ setup(
|
|
|
53
53
|
"License :: OSI Approved :: Apache Software License",
|
|
54
54
|
"Operating System :: POSIX",
|
|
55
55
|
"Programming Language :: Python :: 3",
|
|
56
|
-
"Programming Language :: Python :: 3.9",
|
|
57
56
|
"Programming Language :: Python :: 3.10",
|
|
58
57
|
"Programming Language :: Python :: 3.11",
|
|
59
58
|
"Programming Language :: Python :: 3.12",
|
|
60
59
|
"Programming Language :: Python :: 3.13",
|
|
60
|
+
"Programming Language :: Python :: 3.14",
|
|
61
61
|
"Topic :: Software Development :: Build Tools",
|
|
62
62
|
],
|
|
63
63
|
description="A collection of plugins for BuildStream.",
|
|
@@ -74,6 +74,10 @@ Further, the cargo source reports the `SourceInfoMedium.REMOTE_FILE
|
|
|
74
74
|
*version_type*, for which it reports the checksum of the archive as the *version*.
|
|
75
75
|
|
|
76
76
|
The versions extracted from the Cargo.lock at tracking time are used to report the *guess_version*.
|
|
77
|
+
|
|
78
|
+
Additional source info can be specified using the `provenance` field for each referenced crate as per
|
|
79
|
+
`built-in source provenance documentation
|
|
80
|
+
<https://docs.buildstream.build/master/buildstream.source.html#built-in-functionality>`_.
|
|
77
81
|
"""
|
|
78
82
|
|
|
79
83
|
import json
|
|
@@ -99,7 +103,7 @@ from ._utils import download_file
|
|
|
99
103
|
#
|
|
100
104
|
try:
|
|
101
105
|
from buildstream import SourceInfoMedium, SourceVersionType
|
|
102
|
-
except:
|
|
106
|
+
except ImportError:
|
|
103
107
|
pass
|
|
104
108
|
|
|
105
109
|
|
|
@@ -125,13 +129,14 @@ _default_vendor_config_template = (
|
|
|
125
129
|
# sha (str|None): The sha256 checksum of the downloaded crate
|
|
126
130
|
#
|
|
127
131
|
class Crate(SourceFetcher):
|
|
128
|
-
def __init__(self, cargo, name, version, sha=None):
|
|
132
|
+
def __init__(self, cargo, name, version, sha=None, provenance=None):
|
|
129
133
|
super().__init__()
|
|
130
134
|
|
|
131
135
|
self.cargo = cargo
|
|
132
136
|
self.name = name
|
|
133
137
|
self.version = str(version)
|
|
134
138
|
self.sha = sha
|
|
139
|
+
self.provenance = provenance
|
|
135
140
|
self.mark_download_url(cargo.url)
|
|
136
141
|
|
|
137
142
|
########################################################
|
|
@@ -159,7 +164,12 @@ class Crate(SourceFetcher):
|
|
|
159
164
|
def get_source_info(self):
|
|
160
165
|
url, _ = self._get_url()
|
|
161
166
|
return self.cargo.create_source_info(
|
|
162
|
-
url,
|
|
167
|
+
url,
|
|
168
|
+
SourceInfoMedium.REMOTE_FILE,
|
|
169
|
+
SourceVersionType.SHA256,
|
|
170
|
+
self.sha,
|
|
171
|
+
version_guess=self.version,
|
|
172
|
+
provenance_node=self.provenance,
|
|
163
173
|
)
|
|
164
174
|
|
|
165
175
|
########################################################
|
|
@@ -368,16 +378,29 @@ class CargoSource(Source):
|
|
|
368
378
|
# We need the Cargo.lock file to construct our ref at track time
|
|
369
379
|
BST_REQUIRES_PREVIOUS_SOURCES_TRACK = True
|
|
370
380
|
|
|
381
|
+
BST_CUSTOM_SOURCE_PROVENANCE = True
|
|
382
|
+
|
|
371
383
|
########################################################
|
|
372
384
|
# Plugin/Source API method implementations #
|
|
373
385
|
########################################################
|
|
374
386
|
def configure(self, node):
|
|
375
|
-
|
|
376
387
|
# The url before any aliasing
|
|
377
388
|
#
|
|
378
389
|
self.original_url = node.get_str("url", "https://static.crates.io/crates")
|
|
379
390
|
self.cargo_lock = node.get_str("cargo-lock", "Cargo.lock")
|
|
380
391
|
self.vendor_dir = node.get_str("vendor-dir", "crates")
|
|
392
|
+
self.provenance = {}
|
|
393
|
+
|
|
394
|
+
# Because source provenance info lives in the ref it would be
|
|
395
|
+
# removed upon source track, create a backup here so it is
|
|
396
|
+
# available to be added back in when setting the ref
|
|
397
|
+
ref = node.get_sequence("ref", None)
|
|
398
|
+
if ref is not None:
|
|
399
|
+
for crate in ref:
|
|
400
|
+
if "provenance" in crate:
|
|
401
|
+
crate_name = crate.get_str("name")
|
|
402
|
+
provenance = crate.get_mapping("provenance")
|
|
403
|
+
self.provenance[crate_name] = provenance.strip_node_info()
|
|
381
404
|
|
|
382
405
|
# If the specified URL is just an alias, require the alias to resolve
|
|
383
406
|
# to a URL with a trailing slash. Otherwise, append a trailing slash if
|
|
@@ -413,6 +436,14 @@ class CargoSource(Source):
|
|
|
413
436
|
return self.ref
|
|
414
437
|
|
|
415
438
|
def set_ref(self, ref, node):
|
|
439
|
+
def add_provenance(crate):
|
|
440
|
+
if crate["name"] in self.provenance:
|
|
441
|
+
crate["provenance"] = self.provenance[crate["name"]]
|
|
442
|
+
return crate
|
|
443
|
+
|
|
444
|
+
# add provenance back in
|
|
445
|
+
ref = list(map(add_provenance, ref))
|
|
446
|
+
|
|
416
447
|
node["ref"] = ref
|
|
417
448
|
self._recompute_crates(node.get_sequence("ref"))
|
|
418
449
|
|
|
@@ -513,6 +544,7 @@ class CargoSource(Source):
|
|
|
513
544
|
crate.get_str("name"),
|
|
514
545
|
crate.get_str("version"),
|
|
515
546
|
sha=crate.get_str("sha", None),
|
|
547
|
+
provenance=crate.get_mapping("provenance", None),
|
|
516
548
|
)
|
|
517
549
|
for crate in refs
|
|
518
550
|
]
|
|
@@ -21,8 +21,8 @@
|
|
|
21
21
|
#
|
|
22
22
|
|
|
23
23
|
"""
|
|
24
|
-
docker - stage files from Docker images
|
|
25
|
-
|
|
24
|
+
docker - stage files from Docker/OCI images
|
|
25
|
+
===========================================
|
|
26
26
|
|
|
27
27
|
**Usage:**
|
|
28
28
|
|
|
@@ -107,6 +107,8 @@ import shutil
|
|
|
107
107
|
import tarfile
|
|
108
108
|
import urllib.parse
|
|
109
109
|
|
|
110
|
+
from collections import OrderedDict
|
|
111
|
+
|
|
110
112
|
import requests
|
|
111
113
|
|
|
112
114
|
from buildstream import Source, SourceError
|
|
@@ -115,6 +117,7 @@ from buildstream.utils import (
|
|
|
115
117
|
sha256sum,
|
|
116
118
|
link_files,
|
|
117
119
|
move_atomic,
|
|
120
|
+
get_umask,
|
|
118
121
|
)
|
|
119
122
|
|
|
120
123
|
#
|
|
@@ -279,6 +282,8 @@ class DockerRegistryV2Client:
|
|
|
279
282
|
accept_types = [
|
|
280
283
|
"application/vnd.docker.distribution.manifest.v2+json",
|
|
281
284
|
"application/vnd.docker.distribution.manifest.list.v2+json",
|
|
285
|
+
"application/vnd.oci.image.index.v1+json",
|
|
286
|
+
"application/vnd.oci.image.manifest.v1+json",
|
|
282
287
|
]
|
|
283
288
|
|
|
284
289
|
manifest_url = urljoin(image_path, "manifests", urllib.parse.quote(reference))
|
|
@@ -316,7 +321,10 @@ class DockerRegistryV2Client:
|
|
|
316
321
|
manifest=response.text,
|
|
317
322
|
)
|
|
318
323
|
|
|
319
|
-
if manifest["mediaType"]
|
|
324
|
+
if manifest["mediaType"] in (
|
|
325
|
+
"application/vnd.docker.distribution.manifest.list.v2+json",
|
|
326
|
+
"application/vnd.oci.image.index.v1+json",
|
|
327
|
+
):
|
|
320
328
|
# This is a "fat manifest", we need to narrow down to a specific
|
|
321
329
|
# architecture.
|
|
322
330
|
for sub in manifest["manifests"]:
|
|
@@ -332,7 +340,10 @@ class DockerRegistryV2Client:
|
|
|
332
340
|
"No images found for architecture {}, OS {}".format(architecture, os_),
|
|
333
341
|
manifest=response.text,
|
|
334
342
|
)
|
|
335
|
-
if manifest["mediaType"]
|
|
343
|
+
if manifest["mediaType"] in (
|
|
344
|
+
"application/vnd.docker.distribution.manifest.v2+json",
|
|
345
|
+
"application/vnd.oci.image.manifest.v1+json",
|
|
346
|
+
):
|
|
336
347
|
return response.text, our_digest
|
|
337
348
|
else:
|
|
338
349
|
raise DockerManifestError(
|
|
@@ -363,23 +374,26 @@ class DockerRegistryV2Client:
|
|
|
363
374
|
|
|
364
375
|
class ReadableTarInfo(tarfile.TarInfo):
|
|
365
376
|
"""
|
|
366
|
-
The goal is to override`TarFile`'s `extractall` semantics by ensuring that on extraction, the
|
|
367
|
-
files are readable by the owner of the file. This is done by
|
|
368
|
-
mode` attribute in `TarInfo`, class that encapsulates the internal meta-data of the tarball,
|
|
377
|
+
The goal is to override `TarFile`'s `extractall` semantics by ensuring that on extraction, the
|
|
378
|
+
files are readable by the owner of the file. This is done by overriding the accessor for the
|
|
379
|
+
`mode` attribute in `TarInfo`, the class that encapsulates the internal meta-data of the tarball,
|
|
369
380
|
so that the owner-read bit is always set.
|
|
370
381
|
"""
|
|
371
382
|
|
|
372
|
-
#
|
|
373
|
-
# this trips up the static type checker, mark this as "ignore"
|
|
374
|
-
#
|
|
383
|
+
# https://github.com/python/mypy/issues/4125
|
|
375
384
|
@property # type: ignore
|
|
376
385
|
def mode(self):
|
|
377
|
-
#
|
|
378
|
-
|
|
386
|
+
# Respect umask instead of the file mode stored in the archive.
|
|
387
|
+
# The only bit used from the embedded mode is the executable bit for files.
|
|
388
|
+
umask = get_umask()
|
|
389
|
+
if self.isdir() or bool(self.__permission & 0o100):
|
|
390
|
+
return 0o777 & ~umask
|
|
391
|
+
else:
|
|
392
|
+
return 0o666 & ~umask
|
|
379
393
|
|
|
380
394
|
@mode.setter
|
|
381
395
|
def mode(self, permission):
|
|
382
|
-
self.__permission = permission
|
|
396
|
+
self.__permission = permission # pylint: disable=attribute-defined-outside-init
|
|
383
397
|
|
|
384
398
|
|
|
385
399
|
class DockerSource(Source):
|
|
@@ -570,7 +584,10 @@ class DockerSource(Source):
|
|
|
570
584
|
raise SourceError(e) from e
|
|
571
585
|
|
|
572
586
|
for layer in manifest["layers"]:
|
|
573
|
-
if layer["mediaType"]
|
|
587
|
+
if layer["mediaType"] not in (
|
|
588
|
+
"application/vnd.docker.image.rootfs.diff.tar.gzip",
|
|
589
|
+
"application/vnd.oci.image.layer.v1.tar+gzip",
|
|
590
|
+
):
|
|
574
591
|
raise SourceError("Unsupported layer type: {}".format(layer["mediaType"]))
|
|
575
592
|
|
|
576
593
|
layer_digest = layer["digest"]
|
|
@@ -605,31 +622,54 @@ class DockerSource(Source):
|
|
|
605
622
|
raise SourceError("Unable to load manifest: {}".format(e)) from e
|
|
606
623
|
|
|
607
624
|
try:
|
|
625
|
+
layer_members = []
|
|
626
|
+
|
|
627
|
+
# Create a list of members to extract from each layer
|
|
608
628
|
for layer in manifest["layers"]:
|
|
609
629
|
layer_digest = layer["digest"]
|
|
610
630
|
blob_path = os.path.join(mirror_dir, layer_digest + ".tar.gz")
|
|
611
631
|
|
|
612
632
|
self._verify_blob(blob_path, expected_digest=layer_digest)
|
|
613
|
-
(
|
|
614
|
-
extract_fileset,
|
|
615
|
-
white_out_fileset,
|
|
616
|
-
) = self._get_extract_and_remove_files(blob_path)
|
|
617
|
-
|
|
618
|
-
# remove files associated with whiteouts
|
|
619
|
-
for white_out_file in white_out_fileset:
|
|
620
|
-
white_out_file = os.path.join(directory, white_out_file)
|
|
621
|
-
os.remove(white_out_file)
|
|
622
633
|
|
|
623
|
-
|
|
634
|
+
members_dict, whiteout_paths, opaque_whiteout_dirs = self._get_members_and_whiteout_paths(blob_path)
|
|
635
|
+
|
|
636
|
+
# Process opaque whiteouts: remove members under the corresponding directories from previous layers
|
|
637
|
+
for _, prev_members_dict in layer_members:
|
|
638
|
+
members_to_remove = []
|
|
639
|
+
for member_path in prev_members_dict:
|
|
640
|
+
# Check if this member should be removed by any opaque whiteout
|
|
641
|
+
for opaque_whiteout_dir in opaque_whiteout_dirs:
|
|
642
|
+
if member_path.startswith(opaque_whiteout_dir):
|
|
643
|
+
members_to_remove.append(member_path)
|
|
644
|
+
break
|
|
645
|
+
for member_path in members_to_remove:
|
|
646
|
+
del prev_members_dict[member_path]
|
|
647
|
+
|
|
648
|
+
# Process whiteouts: remove corresponding members from previous layers
|
|
649
|
+
for _, prev_members_dict in layer_members:
|
|
650
|
+
for whiteout_path in whiteout_paths:
|
|
651
|
+
prev_members_dict.pop(whiteout_path, None)
|
|
652
|
+
|
|
653
|
+
layer_members.append((blob_path, members_dict))
|
|
654
|
+
|
|
655
|
+
# Extract files for each layer
|
|
656
|
+
for blob_path, members_dict in layer_members:
|
|
657
|
+
if not members_dict:
|
|
658
|
+
# No files to extract from this layer
|
|
659
|
+
continue
|
|
660
|
+
|
|
661
|
+
# Extract files for the current layer
|
|
624
662
|
with tarfile.open(blob_path, tarinfo=ReadableTarInfo) as tar:
|
|
625
663
|
with self.tempdir() as td:
|
|
664
|
+
members = list(members_dict.values())
|
|
665
|
+
|
|
626
666
|
if hasattr(tarfile, "tar_filter"):
|
|
627
667
|
# Python 3.12+ (and older versions with backports)
|
|
628
668
|
tar.extraction_filter = tarfile.tar_filter
|
|
629
669
|
else:
|
|
630
|
-
for member in
|
|
670
|
+
for member in members:
|
|
631
671
|
self._assert_tarinfo_safe(member, td)
|
|
632
|
-
tar.extractall(path=td, members=
|
|
672
|
+
tar.extractall(path=td, members=members)
|
|
633
673
|
link_files(td, directory)
|
|
634
674
|
|
|
635
675
|
except (OSError, SourceError, tarfile.TarError) as e:
|
|
@@ -658,14 +698,14 @@ class DockerSource(Source):
|
|
|
658
698
|
]
|
|
659
699
|
|
|
660
700
|
@staticmethod
|
|
661
|
-
def
|
|
701
|
+
def _get_members_and_whiteout_paths(layer_tar_path):
|
|
662
702
|
"""Return the set of files to remove and extract for a given layer
|
|
663
703
|
|
|
664
|
-
:param layer_tar_path: The path
|
|
665
|
-
:return: Tuple of
|
|
666
|
-
-
|
|
667
|
-
-
|
|
668
|
-
|
|
704
|
+
:param layer_tar_path: The path to the layer tar.gz file
|
|
705
|
+
:return: Tuple of (members_dict, whiteout_paths, opaque_whiteout_dirs)
|
|
706
|
+
- members_dict: OrderedDict of TarInfo members to extract into staging directory
|
|
707
|
+
- whiteout_paths: list of file paths that should be removed from previous layers
|
|
708
|
+
- opaque_whiteout_dirs: list of directory paths whose contents should be removed from previous layers
|
|
669
709
|
|
|
670
710
|
"""
|
|
671
711
|
|
|
@@ -677,7 +717,7 @@ class DockerSource(Source):
|
|
|
677
717
|
"""
|
|
678
718
|
# whiteout files have the syntax of `*/.wh.*`
|
|
679
719
|
file_name = os.path.basename(white_out_file)
|
|
680
|
-
path = os.path.join(os.path.dirname(white_out_file), file_name.split(".wh.")[1])
|
|
720
|
+
path = os.path.join(os.path.dirname(white_out_file), file_name.split(".wh.", maxsplit=1)[1])
|
|
681
721
|
return path
|
|
682
722
|
|
|
683
723
|
def is_regular_file(info):
|
|
@@ -688,16 +728,27 @@ class DockerSource(Source):
|
|
|
688
728
|
"""
|
|
689
729
|
return not (info.name.startswith("dev/") or info.isdev())
|
|
690
730
|
|
|
691
|
-
with tarfile.open(layer_tar_path) as tar:
|
|
692
|
-
|
|
693
|
-
|
|
731
|
+
with tarfile.open(layer_tar_path, tarinfo=ReadableTarInfo) as tar:
|
|
732
|
+
members_dict = OrderedDict()
|
|
733
|
+
whiteout_paths = []
|
|
734
|
+
opaque_whiteout_dirs = []
|
|
735
|
+
|
|
694
736
|
for member in tar.getmembers():
|
|
695
|
-
|
|
696
|
-
|
|
737
|
+
member_basename = os.path.basename(member.name)
|
|
738
|
+
if member_basename == ".wh..wh..opq":
|
|
739
|
+
# Opaque whiteout file
|
|
740
|
+
opaque_whiteout_dir = os.path.dirname(member.name)
|
|
741
|
+
if opaque_whiteout_dir != "":
|
|
742
|
+
# Add "/" to facilitate path prefix matching
|
|
743
|
+
opaque_whiteout_dir += "/"
|
|
744
|
+
opaque_whiteout_dirs.append(opaque_whiteout_dir)
|
|
745
|
+
elif member_basename.startswith(".wh."):
|
|
746
|
+
# Whiteout file
|
|
747
|
+
whiteout_paths.append(strip_wh(member.name))
|
|
697
748
|
elif is_regular_file(member):
|
|
698
|
-
|
|
749
|
+
members_dict[member.name] = member
|
|
699
750
|
|
|
700
|
-
return
|
|
751
|
+
return members_dict, whiteout_paths, opaque_whiteout_dirs
|
|
701
752
|
|
|
702
753
|
# Assert that a tarfile is safe to extract; specifically, make
|
|
703
754
|
# sure that we don't do anything outside of the target
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: buildstream-plugins
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.8.0.dev0
|
|
4
4
|
Summary: A collection of plugins for BuildStream.
|
|
5
5
|
Home-page: https://buildstream.build
|
|
6
6
|
Author: The Apache Software Foundation
|
|
@@ -15,17 +15,28 @@ Classifier: Intended Audience :: Developers
|
|
|
15
15
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
16
16
|
Classifier: Operating System :: POSIX
|
|
17
17
|
Classifier: Programming Language :: Python :: 3
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
19
18
|
Classifier: Programming Language :: Python :: 3.10
|
|
20
19
|
Classifier: Programming Language :: Python :: 3.11
|
|
21
20
|
Classifier: Programming Language :: Python :: 3.12
|
|
22
21
|
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
23
23
|
Classifier: Topic :: Software Development :: Build Tools
|
|
24
24
|
Description-Content-Type: text/x-rst; charset=UTF-8
|
|
25
25
|
License-File: LICENSE
|
|
26
26
|
License-File: NOTICE
|
|
27
27
|
Provides-Extra: cargo
|
|
28
28
|
Requires-Dist: tomli; python_version < "3.11" and extra == "cargo"
|
|
29
|
+
Dynamic: author
|
|
30
|
+
Dynamic: author-email
|
|
31
|
+
Dynamic: classifier
|
|
32
|
+
Dynamic: description
|
|
33
|
+
Dynamic: description-content-type
|
|
34
|
+
Dynamic: home-page
|
|
35
|
+
Dynamic: license
|
|
36
|
+
Dynamic: license-file
|
|
37
|
+
Dynamic: project-url
|
|
38
|
+
Dynamic: provides-extra
|
|
39
|
+
Dynamic: summary
|
|
29
40
|
|
|
30
41
|
BuildStream Plugins
|
|
31
42
|
===================
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0}/requirements/mypy-requirements.txt
RENAMED
|
File without changes
|
|
File without changes
|
{buildstream-plugins-2.5.0.dev0 → buildstream_plugins-2.8.0.dev0}/requirements/test-requirements.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|