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 |