Set mtime to get more deterministic builds
This commit is contained in:
parent
560201da66
commit
4e0109f873
@ -752,8 +752,9 @@ rec {
|
|||||||
imageTag="${tag}"
|
imageTag="${tag}"
|
||||||
''}
|
''}
|
||||||
|
|
||||||
if [[ "$created" == "now" ]]; then
|
# convert "created" to iso format
|
||||||
created="$(TZ=utc date --iso-8601="seconds")"
|
if [[ "$created" != "now" ]]; then
|
||||||
|
created="$(date -Iseconds -d "$created")"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Create $maxLayers worth of Docker Layers, one layer per store path
|
# Create $maxLayers worth of Docker Layers, one layer per store path
|
||||||
|
@ -7,11 +7,12 @@ import hashlib
|
|||||||
import tarfile
|
import tarfile
|
||||||
import itertools
|
import itertools
|
||||||
import threading
|
import threading
|
||||||
|
from datetime import datetime
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
|
||||||
|
|
||||||
# Adds the given store paths to as a tar to the given writable stream.
|
# Adds the given store paths to as a tar to the given writable stream.
|
||||||
def archive_paths_to(obj, paths, add_nix, filter=None):
|
def archive_paths_to(obj, paths, created, add_nix, filter=None):
|
||||||
filter = filter if filter else lambda i: i
|
filter = filter if filter else lambda i: i
|
||||||
|
|
||||||
# gettarinfo makes the paths relative, this makes them
|
# gettarinfo makes the paths relative, this makes them
|
||||||
@ -20,6 +21,10 @@ def archive_paths_to(obj, paths, add_nix, filter=None):
|
|||||||
ti.name = "/" + ti.name
|
ti.name = "/" + ti.name
|
||||||
return ti
|
return ti
|
||||||
|
|
||||||
|
def apply_filters(ti):
|
||||||
|
ti.mtime = int(created.timestamp())
|
||||||
|
return filter(ti)
|
||||||
|
|
||||||
def dir(path):
|
def dir(path):
|
||||||
ti = tarfile.TarInfo(path)
|
ti = tarfile.TarInfo(path)
|
||||||
ti.type = tarfile.DIRTYPE
|
ti.type = tarfile.DIRTYPE
|
||||||
@ -27,12 +32,12 @@ def archive_paths_to(obj, paths, add_nix, filter=None):
|
|||||||
|
|
||||||
with tarfile.open(fileobj=obj, mode="w|") as tar:
|
with tarfile.open(fileobj=obj, mode="w|") as tar:
|
||||||
if add_nix:
|
if add_nix:
|
||||||
tar.addfile(dir("/nix"))
|
tar.addfile(apply_filters(dir("/nix")))
|
||||||
tar.addfile(dir("/nix/store"))
|
tar.addfile(apply_filters(dir("/nix/store")))
|
||||||
|
|
||||||
for path in paths:
|
for path in paths:
|
||||||
ti = tar.gettarinfo(os.path.join("/", path))
|
ti = tar.gettarinfo(os.path.join("/", path))
|
||||||
tar.addfile(filter(append_root(ti)))
|
tar.addfile(apply_filters(append_root(ti)))
|
||||||
|
|
||||||
for root, dirs, files in os.walk(path, topdown=True):
|
for root, dirs, files in os.walk(path, topdown=True):
|
||||||
for name in itertools.chain(dirs, files):
|
for name in itertools.chain(dirs, files):
|
||||||
@ -43,7 +48,7 @@ def archive_paths_to(obj, paths, add_nix, filter=None):
|
|||||||
if ti.islnk():
|
if ti.islnk():
|
||||||
ti.type = tarfile.REGTYPE
|
ti.type = tarfile.REGTYPE
|
||||||
|
|
||||||
ti = filter(ti)
|
ti = apply_filters(ti)
|
||||||
if ti.isfile():
|
if ti.isfile():
|
||||||
with open(name, "rb") as f:
|
with open(name, "rb") as f:
|
||||||
tar.addfile(ti, f)
|
tar.addfile(ti, f)
|
||||||
@ -72,11 +77,17 @@ LayerInfo = namedtuple("LayerInfo", ["size", "checksum", "path", "paths"])
|
|||||||
|
|
||||||
# Given a list of store paths 'paths', creates a layer add append it
|
# Given a list of store paths 'paths', creates a layer add append it
|
||||||
# to tarfile 'tar'. Returns some a 'LayerInfo' for the layer.
|
# to tarfile 'tar'. Returns some a 'LayerInfo' for the layer.
|
||||||
def add_layer_dir(tar, paths, add_nix=True, filter=None):
|
def add_layer_dir(tar, paths, created, add_nix=True, filter=None):
|
||||||
assert all(i.startswith("/nix/store/") for i in paths)
|
assert all(i.startswith("/nix/store/") for i in paths)
|
||||||
|
|
||||||
extract_checksum = ExtractChecksum()
|
extract_checksum = ExtractChecksum()
|
||||||
archive_paths_to(extract_checksum, paths, add_nix=add_nix, filter=filter)
|
archive_paths_to(
|
||||||
|
extract_checksum,
|
||||||
|
paths,
|
||||||
|
created=created,
|
||||||
|
add_nix=add_nix,
|
||||||
|
filter=filter
|
||||||
|
)
|
||||||
(checksum, size) = extract_checksum.extract()
|
(checksum, size) = extract_checksum.extract()
|
||||||
|
|
||||||
path = f"{checksum}/layer.tar"
|
path = f"{checksum}/layer.tar"
|
||||||
@ -86,7 +97,13 @@ def add_layer_dir(tar, paths, add_nix=True, filter=None):
|
|||||||
read_fd, write_fd = os.pipe()
|
read_fd, write_fd = os.pipe()
|
||||||
with open(read_fd, "rb") as read, open(write_fd, "wb") as write:
|
with open(read_fd, "rb") as read, open(write_fd, "wb") as write:
|
||||||
def producer():
|
def producer():
|
||||||
archive_paths_to(write, paths, add_nix=add_nix, filter=filter)
|
archive_paths_to(
|
||||||
|
write,
|
||||||
|
paths,
|
||||||
|
created=created,
|
||||||
|
add_nix=add_nix,
|
||||||
|
filter=filter
|
||||||
|
)
|
||||||
write.close()
|
write.close()
|
||||||
threading.Thread(target=producer).start()
|
threading.Thread(target=producer).start()
|
||||||
tar.addfile(ti, read)
|
tar.addfile(ti, read)
|
||||||
@ -94,11 +111,17 @@ def add_layer_dir(tar, paths, add_nix=True, filter=None):
|
|||||||
return LayerInfo(size=size, checksum=checksum, path=path, paths=paths)
|
return LayerInfo(size=size, checksum=checksum, path=path, paths=paths)
|
||||||
|
|
||||||
|
|
||||||
def add_customisation_layer(tar, path):
|
def add_customisation_layer(tar, path, created):
|
||||||
def filter(ti):
|
def filter(ti):
|
||||||
ti.name = re.sub("^/nix/store/[^/]*", "", ti.name)
|
ti.name = re.sub("^/nix/store/[^/]*", "", ti.name)
|
||||||
return ti
|
return ti
|
||||||
return add_layer_dir(tar, [path], add_nix=False, filter=filter)
|
return add_layer_dir(
|
||||||
|
tar,
|
||||||
|
[path],
|
||||||
|
created=created,
|
||||||
|
add_nix=False,
|
||||||
|
filter=filter
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# Adds a file to the tarball with given path and contents.
|
# Adds a file to the tarball with given path and contents.
|
||||||
@ -115,6 +138,12 @@ def add_bytes(tar, path, content):
|
|||||||
with open(sys.argv[1], "r") as f:
|
with open(sys.argv[1], "r") as f:
|
||||||
conf = json.load(f)
|
conf = json.load(f)
|
||||||
|
|
||||||
|
created = (
|
||||||
|
datetime.now(tz=datetime.timezone.utc)
|
||||||
|
if conf["created"] == "now"
|
||||||
|
else datetime.fromisoformat(conf["created"])
|
||||||
|
)
|
||||||
|
|
||||||
with tarfile.open(mode="w|", fileobj=sys.stdout.buffer) as tar:
|
with tarfile.open(mode="w|", fileobj=sys.stdout.buffer) as tar:
|
||||||
layers = []
|
layers = []
|
||||||
for num, store_layer in enumerate(conf["store_layers"]):
|
for num, store_layer in enumerate(conf["store_layers"]):
|
||||||
@ -122,15 +151,22 @@ with tarfile.open(mode="w|", fileobj=sys.stdout.buffer) as tar:
|
|||||||
"Creating layer", num,
|
"Creating layer", num,
|
||||||
"from paths:", store_layer,
|
"from paths:", store_layer,
|
||||||
file=sys.stderr)
|
file=sys.stderr)
|
||||||
info = add_layer_dir(tar, store_layer)
|
info = add_layer_dir(tar, store_layer, created=created)
|
||||||
layers.append(info)
|
layers.append(info)
|
||||||
|
|
||||||
print("Creating the customisation layer...", file=sys.stderr)
|
print("Creating the customisation layer...", file=sys.stderr)
|
||||||
layers.append(add_customisation_layer(tar, conf["customisation_layer"]))
|
layers.append(
|
||||||
|
add_customisation_layer(
|
||||||
|
tar,
|
||||||
|
conf["customisation_layer"],
|
||||||
|
created=created
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
print("Adding manifests...", file=sys.stderr)
|
print("Adding manifests...", file=sys.stderr)
|
||||||
|
|
||||||
image_json = {
|
image_json = {
|
||||||
"created": conf["created"],
|
"created": datetime.isoformat(created),
|
||||||
"architecture": conf["architecture"],
|
"architecture": conf["architecture"],
|
||||||
"os": "linux",
|
"os": "linux",
|
||||||
"config": conf["config"],
|
"config": conf["config"],
|
||||||
|
Loading…
x
Reference in New Issue
Block a user