📦 Conditionally preserve file mtime when archiving through pkg_tar (#974)
* preserve file mtime through an option
* add tests
* delete debug comment
* wrap long line
* buildifier
---------
Co-authored-by: rnascimento <rnascimento@salesforce.com>
diff --git a/pkg/private/tar/build_tar.py b/pkg/private/tar/build_tar.py
index be74bc9..5fd5bcf 100644
--- a/pkg/private/tar/build_tar.py
+++ b/pkg/private/tar/build_tar.py
@@ -44,7 +44,8 @@
pass
def __init__(self, output, directory, compression, compressor, create_parents,
- allow_dups_from_deps, default_mtime, compression_level, preserve_mode):
+ allow_dups_from_deps, default_mtime, compression_level, preserve_mode,
+ preserve_mtime):
# Directory prefix on all output paths
d = directory.strip('/')
self.directory = (d + '/') if d else None
@@ -56,6 +57,7 @@
self.allow_dups_from_deps = allow_dups_from_deps
self.compression_level = compression_level
self.preserve_mode = preserve_mode
+ self.preserve_mtime = preserve_mtime
def __enter__(self):
self.tarfile = tar_writer.TarFileWriter(
@@ -90,7 +92,7 @@
dest = self.directory + dest
return dest
- def add_file(self, f, destfile, mode=None, ids=None, names=None):
+ def add_file(self, f, destfile, mode=None, ids=None, names=None, mtime=None):
"""Add a file to the tar file.
Args:
@@ -110,6 +112,8 @@
mode = stat.S_IMODE(os.stat(f).st_mode)
elif mode is None:
mode = 0o755 if os.access(f, os.X_OK) else 0o644
+ if self.preserve_mtime is True:
+ mtime = os.stat(f).st_mtime
if ids is None:
ids = (0, 0)
if names is None:
@@ -121,7 +125,8 @@
uid=ids[0],
gid=ids[1],
uname=names[0],
- gname=names[1])
+ gname=names[1],
+ mtime=mtime)
def add_empty_file(self,
destfile,
@@ -413,6 +418,10 @@
action='store_true',
help='Preserve original file permissions in the archive. Mode argument is ignored.')
parser.add_argument(
+ '--preserve_mtime', default='False',
+ action='store_true',
+ help='Preserve original file mtime in the archive. mtime argument is ignored.')
+ parser.add_argument(
'--compression_level', default=-1,
help='Specify the numeric compress level in gzip mode; may be 0-9 or -1 (default to 6).')
options = parser.parse_args()
@@ -472,7 +481,8 @@
create_parents=options.create_parents,
allow_dups_from_deps=options.allow_dups_from_deps,
compression_level = compression_level,
- preserve_mode = options.preserve_mode) as output:
+ preserve_mode = options.preserve_mode,
+ preserve_mtime = options.preserve_mtime) as output:
def file_attributes(filename):
if filename.startswith('/'):
diff --git a/pkg/private/tar/tar.bzl b/pkg/private/tar/tar.bzl
index 75876b8..d61a462 100644
--- a/pkg/private/tar/tar.bzl
+++ b/pkg/private/tar/tar.bzl
@@ -184,6 +184,9 @@
if ctx.attr.preserve_mode:
args.add("--preserve_mode")
+ if ctx.attr.preserve_mtime:
+ args.add("--preserve_mtime")
+
inputs = depset(
direct = ctx.files.deps + files,
transitive = mapping_context.file_deps,
@@ -301,6 +304,10 @@
default = False,
doc = """If true, will add file to archive with preserved file permissions.""",
),
+ "preserve_mtime": attr.bool(
+ default = False,
+ doc = """If true, will add file to archive with preserved file mtime.""",
+ ),
"stamp": attr.int(
doc = """Enable file time stamping. Possible values:
<li>stamp = 1: Use the time of the build as the modification time of each file in the archive.
diff --git a/tests/tar/BUILD b/tests/tar/BUILD
index 3164162..dec1006 100644
--- a/tests/tar/BUILD
+++ b/tests/tar/BUILD
@@ -476,6 +476,8 @@
":test-tar-mtime.tar",
":test-tar-preserve_mode-False.tar",
":test-tar-preserve_mode-True.tar",
+ ":test-tar-preserve_mtime-False.tar",
+ ":test-tar-preserve_mtime-True.tar",
":test-tar-repackaging-long-filename.tar",
":test-tar-strip_prefix-dot.tar",
":test-tar-strip_prefix-empty.tar",
@@ -814,3 +816,14 @@
True,
False,
]]
+
+[pkg_tar(
+ name = "test-tar-preserve_mtime-%s" % state,
+ srcs = [
+ "//tests:testdata/hello.txt",
+ ],
+ preserve_mtime = state,
+) for state in [
+ True,
+ False,
+]]
diff --git a/tests/tar/pkg_tar_test.py b/tests/tar/pkg_tar_test.py
index 245bb79..c3ba4f2 100644
--- a/tests/tar/pkg_tar_test.py
+++ b/tests/tar/pkg_tar_test.py
@@ -324,5 +324,21 @@
self.assertEqual(member.name, "hello.txt", "unexpected file name for " + file_name)
self.assertEqual(member.mode, int(expected_mode, 0), 'file mode not preserved for ' + file_name)
+ def test_preserve_mtime(self):
+ test_cases = [
+ # tar file name, mtime should be equal to PORTABLE_MTIME?
+ ('test-tar-preserve_mtime-False.tar', True),
+ ('test-tar-preserve_mtime-True.tar', False),
+ ]
+ for file_name, should_be_equal_to_portable_mtime in test_cases:
+ file_path = runfiles.Create().Rlocation('rules_pkg/tests/tar/' + file_name)
+ with tarfile.open(file_path, 'r') as f:
+ for member in f.getmembers():
+ self.assertEqual(member.name, "hello.txt", "unexpected file name for " + file_name)
+ if should_be_equal_to_portable_mtime:
+ self.assertEqual(member.mtime, PORTABLE_MTIME, "unexpected mtime for " + file_name)
+ else:
+ self.assertNotEqual(member.mtime, PORTABLE_MTIME, "file mtime not preserved for " + file_name)
+
if __name__ == '__main__':
unittest.main()