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] repos.conf: support sync-hooks-only-on-change attribute (bug 565172)
Date: Mon, 09 Nov 2015 08:12:11
Message-Id: 1447056678-10842-1-git-send-email-zmedico@gentoo.org
In Reply to: [gentoo-portage-dev] [PATCH] repos.conf: support sync-hooks-lazy attribute (bug 565172) by Zac Medico
1 If sync-hooks-only-on-change is set to true, do not trigger postsync
2 hooks unless hooks would have executed for a master repository or the
3 repository has changed since the previous sync operation.
4
5 If the user has not explicitly enabled sync-hooks-only-on-change in
6 repos.conf, then execute all hooks regardless of whether or not
7 anything has changed (for backward compatibility).
8
9 X-Gentoo-Bug: 565172
10 X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=565172
11 ---
12 [PATCH v2] renames sync-hooks-lazy to sync-hooks-only-on-change
13
14 man/portage.5 | 7 +++-
15 pym/portage/emaint/modules/sync/sync.py | 57 +++++++++++++++++++++++++++------
16 pym/portage/repository/config.py | 6 ++--
17 pym/portage/sync/controller.py | 18 +++++++----
18 4 files changed, 70 insertions(+), 18 deletions(-)
19
20 diff --git a/man/portage.5 b/man/portage.5
21 index 8e2be4f..c9e70a0 100644
22 --- a/man/portage.5
23 +++ b/man/portage.5
24 @@ -1,4 +1,4 @@
25 -.TH "PORTAGE" "5" "Feb 2015" "Portage VERSION" "Portage"
26 +.TH "PORTAGE" "5" "Nov 2015" "Portage VERSION" "Portage"
27 .SH NAME
28 portage \- the heart of Gentoo
29 .SH "DESCRIPTION"
30 @@ -968,6 +968,11 @@ Specifies CVS repository.
31 Specifies clone depth to use for DVCS repositories. Defaults to 1 (only
32 the newest commit). If set to 0, the depth is unlimited.
33 .TP
34 +.B sync\-hooks\-only\-on\-change
35 +If set to true, then sync of a given repository will not trigger postsync
36 +hooks unless hooks would have executed for a master repository or the
37 +repository has changed since the previous sync operation.
38 +.TP
39 .B sync\-type
40 Specifies type of synchronization performed by `emerge \-\-sync`.
41 .br
42 diff --git a/pym/portage/emaint/modules/sync/sync.py b/pym/portage/emaint/modules/sync/sync.py
43 index 57c779d..15d63e2 100644
44 --- a/pym/portage/emaint/modules/sync/sync.py
45 +++ b/pym/portage/emaint/modules/sync/sync.py
46 @@ -233,15 +233,17 @@ class SyncRepos(object):
47 retvals = sync_scheduler.retvals
48 msgs.extend(sync_scheduler.msgs)
49
50 - # run the post_sync_hook one last time for
51 - # run only at sync completion hooks
52 - rcode = sync_manager.perform_post_sync_hook('')
53 if retvals:
54 msgs.extend(self.rmessage(retvals, 'sync'))
55 else:
56 msgs.extend(self.rmessage([('None', os.EX_OK)], 'sync'))
57 - if rcode:
58 - msgs.extend(self.rmessage([('None', rcode)], 'post-sync'))
59 +
60 + # run the post_sync_hook one last time for
61 + # run only at sync completion hooks
62 + if sync_scheduler.global_hooks_enabled:
63 + rcode = sync_manager.perform_post_sync_hook('')
64 + if rcode:
65 + msgs.extend(self.rmessage([('None', rcode)], 'post-sync'))
66
67 # Reload the whole config.
68 portage._sync_mode = False
69 @@ -339,6 +341,8 @@ class SyncScheduler(AsyncScheduler):
70 if master.name in selected_repo_names:
71 self._repo_map[master.name] = master
72 self._sync_graph.add(master.name, repo.name)
73 + self._complete_graph = self._sync_graph.copy()
74 + self._hooks_repos = set()
75 self._update_leaf_nodes()
76
77 def _task_exit(self, task):
78 @@ -347,9 +351,13 @@ class SyncScheduler(AsyncScheduler):
79 more leaf nodes.
80 '''
81 self._running_tasks.discard(task)
82 + # Set hooks_enabled = True by default, in order to ensure
83 + # that hooks will be called in a backward-compatible manner
84 + # even if all sync tasks have failed.
85 + hooks_enabled = True
86 returncode = task.returncode
87 if task.returncode == os.EX_OK:
88 - returncode, message, updatecache_flg = task.result
89 + returncode, message, updatecache_flg, hooks_enabled = task.result
90 if message:
91 self.msgs.append(message)
92 repo = task.kwargs['repo'].name
93 @@ -357,8 +365,38 @@ class SyncScheduler(AsyncScheduler):
94 self.retvals.append((repo, returncode))
95 self._sync_graph.remove(repo)
96 self._update_leaf_nodes()
97 + if hooks_enabled:
98 + self._hooks_repos.add(repo)
99 super(SyncScheduler, self)._task_exit(self)
100
101 + def _master_hooks(self, repo_name):
102 + """
103 + @param repo_name: a repo name
104 + @type repo_name: str
105 + @return: True if hooks would have been executed for any master
106 + repositories of the given repo, False otherwise
107 + @rtype: bool
108 + """
109 + traversed_nodes = set()
110 + node_stack = [repo_name]
111 + while node_stack:
112 + node = node_stack.pop()
113 + if node in self._hooks_repos:
114 + return True
115 + if node not in traversed_nodes:
116 + traversed_nodes.add(node)
117 + node_stack.extend(self._complete_graph.child_nodes(node))
118 + return False
119 +
120 + @property
121 + def global_hooks_enabled(self):
122 + """
123 + @return: True if repo.postsync.d hooks would have been executed
124 + for any repositories.
125 + @rtype: bool
126 + """
127 + return bool(self._hooks_repos)
128 +
129 def _update_leaf_nodes(self):
130 '''
131 Populate self._leaf_nodes with current leaves from
132 @@ -389,9 +427,10 @@ class SyncScheduler(AsyncScheduler):
133 self._running_repos.add(node)
134 self._update_leaf_nodes()
135
136 - task = self._sync_manager.async(
137 - self._emerge_config, self._repo_map[node])
138 - return task
139 + return self._sync_manager.async(
140 + emerge_config=self._emerge_config,
141 + repo=self._repo_map[node],
142 + master_hooks=self._master_hooks(node))
143
144 def _can_add_job(self):
145 '''
146 diff --git a/pym/portage/repository/config.py b/pym/portage/repository/config.py
147 index 1060bc7..ffb4544 100644
148 --- a/pym/portage/repository/config.py
149 +++ b/pym/portage/repository/config.py
150 @@ -87,7 +87,7 @@ class RepoConfig(object):
151 'main_repo', 'manifest_hashes', 'masters', 'missing_repo_name',
152 'name', 'portage1_profiles', 'portage1_profiles_compat', 'priority',
153 'profile_formats', 'sign_commit', 'sign_manifest',
154 - 'sync_depth',
155 + 'sync_depth', 'sync_hooks_only_on_change',
156 'sync_type', 'sync_umask', 'sync_uri', 'sync_user', 'thin_manifest',
157 'update_changelog', 'user_location', '_eapis_banned',
158 '_eapis_deprecated', '_masters_orig', 'module_specific_options',
159 @@ -175,6 +175,8 @@ class RepoConfig(object):
160 self.auto_sync = auto_sync
161
162 self.sync_depth = repo_opts.get('sync-depth')
163 + self.sync_hooks_only_on_change = repo_opts.get(
164 + 'sync-hooks-only-on-change', 'false').lower() == 'true'
165
166 self.module_specific_options = {}
167
168 @@ -506,7 +508,7 @@ class RepoConfigLoader(object):
169 # repos.conf is allowed to override.
170 for k in ('aliases', 'auto_sync', 'eclass_overrides',
171 'force', 'masters', 'priority',
172 - 'sync_depth',
173 + 'sync_depth', 'sync_hooks_only_on_change',
174 'sync_type', 'sync_umask', 'sync_uri', 'sync_user',
175 'module_specific_options'):
176 v = getattr(repos_conf_opts, k, None)
177 diff --git a/pym/portage/sync/controller.py b/pym/portage/sync/controller.py
178 index e8132c2..4595293 100644
179 --- a/pym/portage/sync/controller.py
180 +++ b/pym/portage/sync/controller.py
181 @@ -114,16 +114,17 @@ class SyncManager(object):
182 return desc
183 return []
184
185 - def async(self, emerge_config=None, repo=None):
186 + def async(self, emerge_config=None, repo=None, master_hooks=True):
187 self.emerge_config = emerge_config
188 self.settings, self.trees, self.mtimedb = emerge_config
189 self.xterm_titles = "notitles" not in self.settings.features
190 self.portdb = self.trees[self.settings['EROOT']]['porttree'].dbapi
191 return SyncRepo(sync_task=AsyncFunction(target=self.sync,
192 - kwargs=dict(emerge_config=emerge_config, repo=repo)),
193 + kwargs=dict(emerge_config=emerge_config, repo=repo,
194 + master_hooks=master_hooks)),
195 sync_callback=self._sync_callback)
196
197 - def sync(self, emerge_config=None, repo=None):
198 + def sync(self, emerge_config=None, repo=None, master_hooks=True):
199 self.callback = None
200 self.repo = repo
201 self.exitcode = 1
202 @@ -156,9 +157,14 @@ class SyncManager(object):
203 taskmaster = TaskHandler(callback=self.do_callback)
204 taskmaster.run_tasks(tasks, func, status, options=task_opts)
205
206 - self.perform_post_sync_hook(repo.name, repo.sync_uri, repo.location)
207 + hooks_enabled = False
208 + if (master_hooks or self.updatecache_flg or
209 + not repo.sync_hooks_only_on_change):
210 + hooks_enabled = True
211 + self.perform_post_sync_hook(
212 + repo.name, repo.sync_uri, repo.location)
213
214 - return self.exitcode, None, self.updatecache_flg
215 + return self.exitcode, None, self.updatecache_flg, hooks_enabled
216
217
218 def do_callback(self, result):
219 @@ -328,7 +334,7 @@ class SyncManager(object):
220 exitcode = proc.returncode
221 updatecache_flg = False
222 if proc.returncode == os.EX_OK:
223 - exitcode, message, updatecache_flg = proc.result
224 + exitcode, message, updatecache_flg, hooks_enabled = proc.result
225
226 if updatecache_flg and "metadata-transfer" not in self.settings.features:
227 updatecache_flg = False
228 --
229 2.4.9