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

Replies