Gentoo Archives: gentoo-portage-dev

From: Zac Medico <zmedico@g.o>
To: gentoo-portage-dev@l.g.o
Cc: Zac Medico <zmedico@g.o>
Subject: [gentoo-portage-dev] [PATCH v2] bin/doins.py: implement install -p option (bug 642632)
Date: Sat, 30 Dec 2017 00:21:30
Message-Id: 20171230001915.153329-1-zmedico@gentoo.org
In Reply to: [gentoo-portage-dev] [PATCH] bin/doins.py: implement install -p option (bug 642632) by Zac Medico
1 Bug: https://bugs.gentoo.org/642632
2 ---
3 [PATCH v2] fix to copy atime, and split out _set_timestamps function
4
5 bin/doins.py | 28 +++++++++++++++++++++++++---
6 pym/portage/tests/bin/test_doins.py | 6 ++++--
7 2 files changed, 29 insertions(+), 5 deletions(-)
8
9 diff --git a/bin/doins.py b/bin/doins.py
10 index 92e450979..0d03d8fb2 100644
11 --- a/bin/doins.py
12 +++ b/bin/doins.py
13 @@ -107,6 +107,7 @@ def _parse_install_options(
14 parser.add_argument('-g', '--group', default=-1, type=_parse_group)
15 parser.add_argument('-o', '--owner', default=-1, type=_parse_user)
16 parser.add_argument('-m', '--mode', default=0o755, type=_parse_mode)
17 + parser.add_argument('-p', '--preserve-timestamps', action='store_true')
18 split_options = shlex.split(options)
19 namespace, remaining = parser.parse_known_args(split_options)
20 # Because parsing '--mode' option is partially supported. If unknown
21 @@ -139,6 +140,24 @@ def _set_attributes(options, path):
22 os.chmod(path, options.mode)
23
24
25 +def _set_timestamps(source_stat, dest):
26 + """Apply timestamps from source_stat to dest.
27 +
28 + Args:
29 + source_stat: stat result for the source file.
30 + dest: path to the dest file.
31 + """
32 + os.utime(dest, (source_stat.st_atime, source_stat.st_mtime))
33 +
34 +
35 +if sys.version_info >= (3, 3):
36 + def _set_timestamps_ns(source_stat, dest):
37 + os.utime(dest, ns=(source_stat.st_atime_ns, source_stat.st_mtime_ns))
38 +
39 + _set_timestamps_ns.__doc__ = _set_timestamps.__doc__
40 + _set_timestamps = _set_timestamps_ns
41 +
42 +
43 class _InsInProcessInstallRunner(object):
44 """Implements `install` command behavior running in a process."""
45
46 @@ -168,7 +187,8 @@ class _InsInProcessInstallRunner(object):
47 True on success, otherwise False.
48 """
49 dest = os.path.join(dest_dir, os.path.basename(source))
50 - if not self._is_install_allowed(source, dest):
51 + sstat = os.stat(source)
52 + if not self._is_install_allowed(source, sstat, dest):
53 return False
54
55 # To emulate the `install` command, remove the dest file in
56 @@ -187,6 +207,8 @@ class _InsInProcessInstallRunner(object):
57 movefile._copyxattr(
58 source, dest,
59 exclude=self._xattr_exclude)
60 + if self._parsed_options.preserve_timestamps:
61 + _set_timestamps(sstat, dest)
62 except Exception:
63 logging.exception(
64 'Failed to copy file: '
65 @@ -195,13 +217,14 @@ class _InsInProcessInstallRunner(object):
66 return False
67 return True
68
69 - def _is_install_allowed(self, source, dest):
70 + def _is_install_allowed(self, source, source_stat, dest):
71 """Returns if installing source into dest should work.
72
73 This is to keep compatibility with the `install` command.
74
75 Args:
76 source: path to the source file.
77 + source_stat: stat result for the source file.
78 dest: path to the dest file.
79
80 Returns:
81 @@ -210,7 +233,6 @@ class _InsInProcessInstallRunner(object):
82 # To match `install` command, use stat() for source, while
83 # lstat() for dest. Raise an exception if stat(source) fails,
84 # intentionally.
85 - source_stat = os.stat(source)
86 try:
87 dest_lstat = os.lstat(dest)
88 except OSError as e:
89 diff --git a/pym/portage/tests/bin/test_doins.py b/pym/portage/tests/bin/test_doins.py
90 index 14d7adfa6..9b6c55d85 100644
91 --- a/pym/portage/tests/bin/test_doins.py
92 +++ b/pym/portage/tests/bin/test_doins.py
93 @@ -38,13 +38,15 @@ class DoIns(setup_env.BinTestCase):
94 self.init()
95 try:
96 env = setup_env.env
97 - env['INSOPTIONS'] = '-m0644'
98 + env['INSOPTIONS'] = '-pm0644'
99 with open(os.path.join(env['S'], 'test'), 'w'):
100 pass
101 doins('test')
102 st = os.lstat(env['D'] + '/test')
103 if stat.S_IMODE(st.st_mode) != 0o644:
104 raise tests.TestCase.failureException
105 + if os.stat(os.path.join(env['S'], 'test')).st_mtime != st.st_mtime:
106 + raise tests.TestCase.failureException
107 finally:
108 self.cleanup()
109
110 @@ -145,7 +147,7 @@ class DoIns(setup_env.BinTestCase):
111 env = setup_env.env
112 # Use an option which doins.py does not know.
113 # Then, fallback to `install` command is expected.
114 - env['INSOPTIONS'] = '-p'
115 + env['INSOPTIONS'] = '-b'
116 with open(os.path.join(env['S'], 'test'), 'w'):
117 pass
118 doins('test')
119 --
120 2.13.6

Replies