diff options
author | Sergey Kosukhin <sergey.kosukhin@mpimet.mpg.de> | 2021-01-27 20:41:07 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-01-27 11:41:07 -0800 |
commit | 4d7a9df810af4f0f7cae8424e1f8b2579aa90b58 (patch) | |
tree | e027a517f9f3cfca3f636ddc0baa69bb8a279b35 /lib | |
parent | f2c98a853748b2a80b1d17eae00aa5f40a584c7d (diff) | |
download | spack-4d7a9df810af4f0f7cae8424e1f8b2579aa90b58.tar.gz spack-4d7a9df810af4f0f7cae8424e1f8b2579aa90b58.tar.bz2 spack-4d7a9df810af4f0f7cae8424e1f8b2579aa90b58.tar.xz spack-4d7a9df810af4f0f7cae8424e1f8b2579aa90b58.zip |
Add a context wrapper for mtime preservation (#21258)
Sometimes we need to patch a file that is a dependency for some other
automatically generated file that comes in a release tarball. As a
result, make tries to regenerate the dependent file using additional
tools (e.g. help2man), which would not be needed otherwise.
In some cases, it's preferable to avoid that (e.g. see #21255). A way
to do that is to save the modification timestamps before patching and
restoring them afterwards. This PR introduces a context wrapper that
does that.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/spack/llnl/util/filesystem.py | 24 | ||||
-rw-r--r-- | lib/spack/spack/test/llnl/util/filesystem.py | 21 |
2 files changed, 44 insertions, 1 deletions
diff --git a/lib/spack/llnl/util/filesystem.py b/lib/spack/llnl/util/filesystem.py index 0e9708a3c3..a116e2bed2 100644 --- a/lib/spack/llnl/util/filesystem.py +++ b/lib/spack/llnl/util/filesystem.py @@ -63,7 +63,8 @@ __all__ = [ 'touchp', 'traverse_tree', 'unset_executable_mode', - 'working_dir' + 'working_dir', + 'keep_modification_time' ] @@ -1819,3 +1820,24 @@ def remove_directory_contents(dir): os.unlink(entry) else: shutil.rmtree(entry) + + +@contextmanager +def keep_modification_time(*filenames): + """ + Context manager to keep the modification timestamps of the input files. + Tolerates and has no effect on non-existent files and files that are + deleted by the nested code. + + Parameters: + *filenames: one or more files that must have their modification + timestamps unchanged + """ + mtimes = {} + for f in filenames: + if os.path.exists(f): + mtimes[f] = os.path.getmtime(f) + yield + for f, mtime in mtimes.items(): + if os.path.exists(f): + os.utime(f, (os.path.getatime(f), mtime)) diff --git a/lib/spack/spack/test/llnl/util/filesystem.py b/lib/spack/spack/test/llnl/util/filesystem.py index 8f64c0907f..5733be6b59 100644 --- a/lib/spack/spack/test/llnl/util/filesystem.py +++ b/lib/spack/spack/test/llnl/util/filesystem.py @@ -588,3 +588,24 @@ def test_content_of_files_with_same_name(tmpdir): # and have not been mixed assert file1.read().strip() == 'file1' assert file2.read().strip() == 'file2' + + +def test_keep_modification_time(tmpdir): + file1 = tmpdir.ensure('file1') + file2 = tmpdir.ensure('file2') + + # Shift the modification time of the file 10 seconds back: + mtime1 = file1.mtime() - 10 + file1.setmtime(mtime1) + + with fs.keep_modification_time(file1.strpath, + file2.strpath, + 'non-existing-file'): + file1.write('file1') + file2.remove() + + # Assert that the modifications took place the modification time has not + # changed; + assert file1.read().strip() == 'file1' + assert not file2.exists() + assert int(mtime1) == int(file1.mtime()) |