diff options
author | Anton Ovchinnikov <revolver112@gmail.com> | 2016-07-01 17:35:39 +0200 |
---|---|---|
committer | Anton Ovchinnikov <revolver112@gmail.com> | 2016-08-04 21:47:37 +0200 |
commit | 0a056a9b31e21c468bcbc97eaea5a0a62fa9cb46 (patch) | |
tree | a20b3696a69157ac111615ccb4bfadb70e23027c /python/servo/command_base.py | |
parent | 44ed0f29a41652ff888bedaddb303da8d9187da6 (diff) | |
download | servo-0a056a9b31e21c468bcbc97eaea5a0a62fa9cb46.tar.gz servo-0a056a9b31e21c468bcbc97eaea5a0a62fa9cb46.zip |
Create .tar.gz package deterministically
Fixes #11981.
Diffstat (limited to 'python/servo/command_base.py')
-rw-r--r-- | python/servo/command_base.py | 53 |
1 files changed, 53 insertions, 0 deletions
diff --git a/python/servo/command_base.py b/python/servo/command_base.py index 328d0965b65..a6b6e1abcd2 100644 --- a/python/servo/command_base.py +++ b/python/servo/command_base.py @@ -7,12 +7,16 @@ # option. This file may not be copied, modified, or distributed # except according to those terms. +import gzip +import itertools +import locale import os from os import path import contextlib import subprocess from subprocess import PIPE import sys +import tarfile import platform import toml @@ -33,6 +37,55 @@ def cd(new_path): os.chdir(previous_path) +@contextlib.contextmanager +def setlocale(name): + """Context manager for changing the current locale""" + saved_locale = locale.setlocale(locale.LC_ALL) + try: + yield locale.setlocale(locale.LC_ALL, name) + finally: + locale.setlocale(locale.LC_ALL, saved_locale) + + +def archive_deterministically(dir_to_archive, dest_archive, prepend_path=None): + """Create a .tar.gz archive in a deterministic (reproducible) manner. + + See https://reproducible-builds.org/docs/archives/ for more details.""" + + def reset(tarinfo): + """Helper to reset owner/group and modification time for tar entries""" + tarinfo.uid = tarinfo.gid = 0 + tarinfo.uname = tarinfo.gname = "root" + tarinfo.mtime = 0 + return tarinfo + + dest_archive = os.path.abspath(dest_archive) + with cd(dir_to_archive): + current_dir = "." + file_list = [current_dir] + for root, dirs, files in os.walk(current_dir): + for name in itertools.chain(dirs, files): + file_list.append(os.path.join(root, name)) + + # Sort file entries with the fixed locale + with setlocale('C'): + file_list.sort(cmp=locale.strcoll) + + # Use a temporary file and atomic rename to avoid partially-formed + # packaging (in case of exceptional situations like running out of disk space). + # TODO do this in a temporary folder after #11983 is fixed + temp_file = '{}.temp~'.format(dest_archive) + with os.fdopen(os.open(temp_file, os.O_WRONLY | os.O_CREAT, 0644), 'w') as out_file: + with gzip.GzipFile('wb', fileobj=out_file, mtime=0) as gzip_file: + with tarfile.open(fileobj=gzip_file, mode='w:') as tar_file: + for entry in file_list: + arcname = entry + if prepend_path is not None: + arcname = os.path.normpath(os.path.join(prepend_path, arcname)) + tar_file.add(entry, filter=reset, recursive=False, arcname=arcname) + os.rename(temp_file, dest_archive) + + def host_triple(): os_type = platform.system().lower() if os_type == "linux": |