1 |
--- |
2 |
man/portage.5 | 5 +++ |
3 |
pym/portage/package/ebuild/config.py | 2 + |
4 |
pym/portage/repository/config.py | 24 +++++++--- |
5 |
pym/portage/sync/modules/rsync/rsync.py | 6 ++- |
6 |
pym/portage/tests/sync/test_sync_local.py | 73 ++++++++++++++++++++++++++++--- |
7 |
5 files changed, 95 insertions(+), 15 deletions(-) |
8 |
|
9 |
diff --git a/man/portage.5 b/man/portage.5 |
10 |
index e77fc6e..e84142a 100644 |
11 |
--- a/man/portage.5 |
12 |
+++ b/man/portage.5 |
13 |
@@ -1021,6 +1021,11 @@ group id will be changed. |
14 |
.br |
15 |
This key takes precedence over FEATURES=userpriv. If user or group id |
16 |
is provided, Portage no longer uses owner of the directory. |
17 |
+.TP |
18 |
+.B sync-rsync-extra-opts |
19 |
+Extra options to give to rsync on repository synchronization. It takes |
20 |
+precedence over a declaration in [DEFAULT] section, that takes |
21 |
+precedence over PORTAGE_RSYNC_EXTRA_OPTS. |
22 |
.RE |
23 |
|
24 |
.I Example: |
25 |
diff --git a/pym/portage/package/ebuild/config.py b/pym/portage/package/ebuild/config.py |
26 |
index 3a4007b..08db363 100644 |
27 |
--- a/pym/portage/package/ebuild/config.py |
28 |
+++ b/pym/portage/package/ebuild/config.py |
29 |
@@ -515,6 +515,8 @@ class config(object): |
30 |
v = confs.get("SYNC") |
31 |
if v is not None: |
32 |
portdir_sync = v |
33 |
+ if 'PORTAGE_RSYNC_EXTRA_OPTS' in confs: |
34 |
+ self['PORTAGE_RSYNC_EXTRA_OPTS'] = confs['PORTAGE_RSYNC_EXTRA_OPTS'] |
35 |
|
36 |
self["PORTDIR"] = portdir |
37 |
self["PORTDIR_OVERLAY"] = portdir_overlay |
38 |
diff --git a/pym/portage/repository/config.py b/pym/portage/repository/config.py |
39 |
index b7c969d..196b87a 100644 |
40 |
--- a/pym/portage/repository/config.py |
41 |
+++ b/pym/portage/repository/config.py |
42 |
@@ -87,7 +87,7 @@ class RepoConfig(object): |
43 |
'main_repo', 'manifest_hashes', 'masters', 'missing_repo_name', |
44 |
'name', 'portage1_profiles', 'portage1_profiles_compat', 'priority', |
45 |
'profile_formats', 'sign_commit', 'sign_manifest', 'sync_cvs_repo', |
46 |
- 'sync_depth', |
47 |
+ 'sync_depth', 'sync_rsync_extra_opts', |
48 |
'sync_type', 'sync_umask', 'sync_uri', 'sync_user', 'thin_manifest', |
49 |
'update_changelog', 'user_location', '_eapis_banned', |
50 |
'_eapis_deprecated', '_masters_orig') |
51 |
@@ -180,6 +180,8 @@ class RepoConfig(object): |
52 |
|
53 |
self.sync_depth = repo_opts.get('sync-depth') |
54 |
|
55 |
+ self.sync_rsync_extra_opts = repo_opts.get('sync-rsync-extra-opts', None) |
56 |
+ |
57 |
# Not implemented. |
58 |
format = repo_opts.get('format') |
59 |
if format is not None: |
60 |
@@ -415,6 +417,8 @@ class RepoConfig(object): |
61 |
repo_msg.append(indent + "sync-umask: " + self.sync_umask) |
62 |
if self.sync_uri: |
63 |
repo_msg.append(indent + "sync-uri: " + self.sync_uri) |
64 |
+ if self.sync_rsync_extra_opts: |
65 |
+ repo_msg.append(indent + "sync-rsync-extra-opts: " + self.sync_rsync_extra_opts) |
66 |
if self.sync_user: |
67 |
repo_msg.append(indent + "sync-user: " + self.sync_user) |
68 |
if self.masters: |
69 |
@@ -477,6 +481,9 @@ class RepoConfigLoader(object): |
70 |
if prepos['DEFAULT'].masters is not None: |
71 |
default_repo_opts['masters'] = \ |
72 |
' '.join(prepos['DEFAULT'].masters) |
73 |
+ if prepos['DEFAULT'].sync_rsync_extra_opts is not None: |
74 |
+ default_repo_opts['sync-rsync-extra-opts'] = \ |
75 |
+ prepos['DEFAULT'].sync_rsync_extra_opts |
76 |
|
77 |
if overlays: |
78 |
# We need a copy of the original repos.conf data, since we're |
79 |
@@ -504,7 +511,7 @@ class RepoConfigLoader(object): |
80 |
# repos.conf is allowed to override. |
81 |
for k in ('aliases', 'auto_sync', 'eclass_overrides', |
82 |
'force', 'masters', 'priority', 'sync_cvs_repo', |
83 |
- 'sync_depth', |
84 |
+ 'sync_depth', 'sync_rsync_extra_opts', |
85 |
'sync_type', 'sync_umask', 'sync_uri', 'sync_user', |
86 |
): |
87 |
v = getattr(repos_conf_opts, k, None) |
88 |
@@ -543,9 +550,9 @@ class RepoConfigLoader(object): |
89 |
return portdir |
90 |
|
91 |
@staticmethod |
92 |
- def _parse(paths, prepos, ignored_map, ignored_location_map, local_config, portdir): |
93 |
+ def _parse(paths, prepos, ignored_map, ignored_location_map, local_config, portdir, default_opts): |
94 |
"""Parse files in paths to load config""" |
95 |
- parser = SafeConfigParser() |
96 |
+ parser = SafeConfigParser(defaults=default_opts) |
97 |
|
98 |
# use read_file/readfp in order to control decoding of unicode |
99 |
try: |
100 |
@@ -615,6 +622,7 @@ class RepoConfigLoader(object): |
101 |
treemap = {} |
102 |
ignored_map = {} |
103 |
ignored_location_map = {} |
104 |
+ default_opts = {} |
105 |
|
106 |
if "PORTAGE_REPOSITORIES" in settings: |
107 |
portdir = "" |
108 |
@@ -627,10 +635,13 @@ class RepoConfigLoader(object): |
109 |
# deprecated portdir_sync |
110 |
portdir_sync = settings.get("SYNC", "") |
111 |
|
112 |
+ default_opts['sync-rsync-extra-opts'] = \ |
113 |
+ settings.get("PORTAGE_RSYNC_EXTRA_OPTS", None) |
114 |
+ |
115 |
try: |
116 |
self._parse(paths, prepos, ignored_map, |
117 |
ignored_location_map, settings.local_config, |
118 |
- portdir) |
119 |
+ portdir, default_opts) |
120 |
except ConfigParserError as e: |
121 |
writemsg( |
122 |
_("!!! Error while reading repo config file: %s\n") % e, |
123 |
@@ -962,7 +973,8 @@ class RepoConfigLoader(object): |
124 |
def config_string(self): |
125 |
str_or_int_keys = ("auto_sync", "format", "location", |
126 |
"main_repo", "priority", "sync_cvs_repo", |
127 |
- "sync_type", "sync_umask", "sync_uri", 'sync_user') |
128 |
+ "sync_type", "sync_umask", "sync_uri", 'sync_user', |
129 |
+ 'sync_rsync_extra_opts') |
130 |
str_tuple_keys = ("aliases", "eclass_overrides", "force") |
131 |
repo_config_tuple_keys = ("masters",) |
132 |
keys = str_or_int_keys + str_tuple_keys + repo_config_tuple_keys |
133 |
diff --git a/pym/portage/sync/modules/rsync/rsync.py b/pym/portage/sync/modules/rsync/rsync.py |
134 |
index d84c36d..1f09f60 100644 |
135 |
--- a/pym/portage/sync/modules/rsync/rsync.py |
136 |
+++ b/pym/portage/sync/modules/rsync/rsync.py |
137 |
@@ -72,8 +72,10 @@ class RsyncSync(NewBase): |
138 |
rsync_opts = self._validate_rsync_opts(rsync_opts, syncuri) |
139 |
self.rsync_opts = self._rsync_opts_extend(opts, rsync_opts) |
140 |
|
141 |
- self.extra_rsync_opts = portage.util.shlex_split( |
142 |
- self.settings.get("PORTAGE_RSYNC_EXTRA_OPTS","")) |
143 |
+ self.extra_rsync_opts = list() |
144 |
+ if self.repo.sync_rsync_extra_opts is not None: |
145 |
+ self.extra_rsync_opts.extend(portage.util.shlex_split( |
146 |
+ self.repo.sync_rsync_extra_opts)) |
147 |
|
148 |
# Real local timestamp file. |
149 |
self.servertimestampfile = os.path.join( |
150 |
diff --git a/pym/portage/tests/sync/test_sync_local.py b/pym/portage/tests/sync/test_sync_local.py |
151 |
index 65c20f8..f50caba 100644 |
152 |
--- a/pym/portage/tests/sync/test_sync_local.py |
153 |
+++ b/pym/portage/tests/sync/test_sync_local.py |
154 |
@@ -7,7 +7,7 @@ import textwrap |
155 |
import time |
156 |
|
157 |
import portage |
158 |
-from portage import os, shutil |
159 |
+from portage import os, shutil, _shell_quote |
160 |
from portage import _unicode_decode |
161 |
from portage.const import PORTAGE_PYM_PATH, TIMESTAMP_FORMAT |
162 |
from portage.process import find_binary |
163 |
@@ -36,11 +36,14 @@ class SyncLocalTestCase(TestCase): |
164 |
return |
165 |
|
166 |
repos_conf = textwrap.dedent(""" |
167 |
+ [DEFAULT] |
168 |
+ %(default_keys)s |
169 |
[test_repo] |
170 |
location = %(EPREFIX)s/var/repositories/test_repo |
171 |
sync-type = %(sync-type)s |
172 |
sync-uri = file:/%(EPREFIX)s/var/repositories/test_repo_sync |
173 |
auto-sync = yes |
174 |
+ %(repo_extra_keys)s |
175 |
""") |
176 |
|
177 |
profile = { |
178 |
@@ -73,9 +76,17 @@ class SyncLocalTestCase(TestCase): |
179 |
committer_name = "Gentoo Dev" |
180 |
committer_email = "gentoo-dev@g.o" |
181 |
|
182 |
- def change_sync_type(sync_type): |
183 |
- env["PORTAGE_REPOSITORIES"] = repos_conf % \ |
184 |
- {"EPREFIX": eprefix, "sync-type": sync_type} |
185 |
+ def repos_set_conf(sync_type, dflt_keys=None, xtra_keys=None): |
186 |
+ env["PORTAGE_REPOSITORIES"] = repos_conf % {\ |
187 |
+ "EPREFIX": eprefix, "sync-type": sync_type, |
188 |
+ "default_keys": "" if dflt_keys is None else dflt_keys, |
189 |
+ "repo_extra_keys": "" if xtra_keys is None else xtra_keys} |
190 |
+ |
191 |
+ def alter_ebuild(): |
192 |
+ with open(os.path.join(repo.location + "_sync", |
193 |
+ "dev-libs", "A", "A-0.ebuild"), "a") as f: |
194 |
+ f.write("\n") |
195 |
+ os.unlink(os.path.join(metadata_dir, 'timestamp.chk')) |
196 |
|
197 |
sync_cmds = ( |
198 |
(homedir, cmds["emerge"] + ("--sync",)), |
199 |
@@ -90,6 +101,53 @@ class SyncLocalTestCase(TestCase): |
200 |
repo.location + "_sync")), |
201 |
) |
202 |
|
203 |
+ rsync_opts_repos = ( |
204 |
+ (homedir, alter_ebuild), |
205 |
+ (homedir, lambda: repos_set_conf("rsync", None, |
206 |
+ "sync-rsync-extra-opts = --backup --backup-dir=%s" % |
207 |
+ _shell_quote(repo.location + "_back"))), |
208 |
+ (homedir, cmds['emerge'] + ("--sync",)), |
209 |
+ (homedir, lambda: self.assertTrue(os.path.exists( |
210 |
+ repo.location + "_back"))), |
211 |
+ (homedir, lambda: shutil.rmtree(repo.location + "_back")), |
212 |
+ (homedir, lambda: repos_set_conf("rsync")), |
213 |
+ ) |
214 |
+ |
215 |
+ rsync_opts_repos_default = ( |
216 |
+ (homedir, alter_ebuild), |
217 |
+ (homedir, lambda: repos_set_conf("rsync", |
218 |
+ "sync-rsync-extra-opts = --backup --backup-dir=%s" % |
219 |
+ _shell_quote(repo.location+"_back"))), |
220 |
+ (homedir, cmds['emerge'] + ("--sync",)), |
221 |
+ (homedir, lambda: self.assertTrue(os.path.exists(repo.location + "_back"))), |
222 |
+ (homedir, lambda: shutil.rmtree(repo.location + "_back")), |
223 |
+ (homedir, lambda: repos_set_conf("rsync")), |
224 |
+ ) |
225 |
+ |
226 |
+ rsync_opts_repos_default_ovr = ( |
227 |
+ (homedir, alter_ebuild), |
228 |
+ (homedir, lambda: repos_set_conf("rsync", |
229 |
+ "sync-rsync-extra-opts = --backup --backup-dir=%s" % |
230 |
+ _shell_quote(repo.location + "_back_nowhere"), |
231 |
+ "sync-rsync-extra-opts = --backup --backup-dir=%s" % |
232 |
+ _shell_quote(repo.location + "_back"))), |
233 |
+ (homedir, cmds['emerge'] + ("--sync",)), |
234 |
+ (homedir, lambda: self.assertTrue(os.path.exists(repo.location + "_back"))), |
235 |
+ (homedir, lambda: shutil.rmtree(repo.location + "_back")), |
236 |
+ (homedir, lambda: repos_set_conf("rsync")), |
237 |
+ ) |
238 |
+ |
239 |
+ rsync_opts_repos_default_cancel = ( |
240 |
+ (homedir, alter_ebuild), |
241 |
+ (homedir, lambda: repos_set_conf("rsync", |
242 |
+ "sync-rsync-extra-opts = --backup --backup-dir=%s" % |
243 |
+ _shell_quote(repo.location + "_back_nowhere"), |
244 |
+ "sync-rsync-extra-opts = ")), |
245 |
+ (homedir, cmds['emerge'] + ("--sync",)), |
246 |
+ (homedir, lambda: self.assertFalse(os.path.exists(repo.location + "_back"))), |
247 |
+ (homedir, lambda: repos_set_conf("rsync")), |
248 |
+ ) |
249 |
+ |
250 |
delete_sync_repo = ( |
251 |
(homedir, lambda: shutil.rmtree( |
252 |
repo.location + "_sync")), |
253 |
@@ -107,7 +165,7 @@ class SyncLocalTestCase(TestCase): |
254 |
) |
255 |
|
256 |
sync_type_git = ( |
257 |
- (homedir, lambda: change_sync_type("git")), |
258 |
+ (homedir, lambda: repos_set_conf("git")), |
259 |
) |
260 |
|
261 |
pythonpath = os.environ.get("PYTHONPATH") |
262 |
@@ -132,10 +190,9 @@ class SyncLocalTestCase(TestCase): |
263 |
"PATH" : os.environ["PATH"], |
264 |
"PORTAGE_GRPNAME" : os.environ["PORTAGE_GRPNAME"], |
265 |
"PORTAGE_USERNAME" : os.environ["PORTAGE_USERNAME"], |
266 |
- "PORTAGE_REPOSITORIES" : repos_conf % |
267 |
- {"EPREFIX": eprefix, "sync-type": "rsync"}, |
268 |
"PYTHONPATH" : pythonpath, |
269 |
} |
270 |
+ repos_set_conf("rsync") |
271 |
|
272 |
if os.environ.get("SANDBOX_ON") == "1": |
273 |
# avoid problems from nested sandbox instances |
274 |
@@ -160,6 +217,8 @@ class SyncLocalTestCase(TestCase): |
275 |
stdout = subprocess.PIPE |
276 |
|
277 |
for cwd, cmd in rename_repo + sync_cmds + \ |
278 |
+ rsync_opts_repos + rsync_opts_repos_default + \ |
279 |
+ rsync_opts_repos_default_ovr + rsync_opts_repos_default_cancel + \ |
280 |
delete_sync_repo + git_repo_create + sync_type_git + \ |
281 |
rename_repo + sync_cmds: |