Gentoo Archives: gentoo-commits

From: "Michał Górny" <mgorny@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/portage:master commit in: bin/, pym/repoman/, pym/portage/repository/, misc/, pym/portage/dbapi/, ...
Date: Sun, 13 Dec 2015 12:58:07
Message-Id: 1449992009.18692ada8579d367eb332fad7bfe273100f9638f.mgorny@gentoo
1 commit: 18692ada8579d367eb332fad7bfe273100f9638f
2 Author: Michał Górny <mgorny <AT> gentoo <DOT> org>
3 AuthorDate: Sat Dec 12 15:32:08 2015 +0000
4 Commit: Michał Górny <mgorny <AT> gentoo <DOT> org>
5 CommitDate: Sun Dec 13 07:33:29 2015 +0000
6 URL: https://gitweb.gentoo.org/proj/portage.git/commit/?id=18692ada
7
8 Revert "portage.repository.config: Clean reading of repository (...) "
9
10 This reverts commit 2cde1f65e9c585e78415857fdcac1fe5deaa60da. This was
11 unreviewed and is a breaking change made without any discussion or
12 announcement.
13
14 bin/emerge-webrsync | 4 +-
15 bin/portageq | 4 -
16 misc/emerge-delta-webrsync | 4 +-
17 pym/_emerge/actions.py | 33 ++++++
18 pym/portage/dbapi/porttree.py | 4 +-
19 pym/portage/repository/config.py | 229 ++++++++++++++++++++++-----------------
20 pym/repoman/repos.py | 6 +-
21 7 files changed, 171 insertions(+), 113 deletions(-)
22
23 diff --git a/bin/emerge-webrsync b/bin/emerge-webrsync
24 index fc5ab95..9961ad8 100755
25 --- a/bin/emerge-webrsync
26 +++ b/bin/emerge-webrsync
27 @@ -1,5 +1,5 @@
28 #!/bin/bash
29 -# Copyright 1999-2015 Gentoo Foundation
30 +# Copyright 1999-2014 Gentoo Foundation
31 # Distributed under the terms of the GNU General Public License v2
32 # Author: Karl Trygve Kalleberg <karltk@g.o>
33 # Rewritten from the old, Perl-based emerge-webrsync script
34 @@ -39,7 +39,7 @@ else
35 eecho "could not find 'portageq'; aborting"
36 exit 1
37 fi
38 -eval "$(PORTAGE_SYNC_MODE=1 "${portageq}" envvar -v DISTDIR EPREFIX FEATURES \
39 +eval "$("${portageq}" envvar -v DISTDIR EPREFIX FEATURES \
40 FETCHCOMMAND GENTOO_MIRRORS \
41 PORTAGE_BIN_PATH PORTAGE_CONFIGROOT PORTAGE_GPG_DIR \
42 PORTAGE_NICENESS PORTAGE_REPOSITORIES PORTAGE_RSYNC_EXTRA_OPTS \
43
44 diff --git a/bin/portageq b/bin/portageq
45 index 12886f0..925640b 100755
46 --- a/bin/portageq
47 +++ b/bin/portageq
48 @@ -66,10 +66,6 @@ def uses_eroot(function):
49 function.uses_eroot = True
50 return function
51
52 -# Workaround until emerge-webrsync and emerge-delta-webrsync are rewritten in Python.
53 -if os.environ.get("PORTAGE_SYNC_MODE") == "1":
54 - portage._sync_mode = True
55 -
56 # global to hold all function docstrings to be used for argparse help.
57 # Avoids python compilation level 2 optimization troubles.
58 docstrings = {}
59
60 diff --git a/misc/emerge-delta-webrsync b/misc/emerge-delta-webrsync
61 index 1cc04bd..f2dc822 100755
62 --- a/misc/emerge-delta-webrsync
63 +++ b/misc/emerge-delta-webrsync
64 @@ -1,5 +1,5 @@
65 #!/bin/bash
66 -# Copyright 1999-2015 Gentoo Foundation
67 +# Copyright 1999-2014 Gentoo Foundation
68 # Distributed under the terms of the GNU General Public License v2
69 # Author: Brian Harring <ferringb@g.o>, karltk@g.o originally.
70 # Rewritten from the old, Perl-based emerge-webrsync script
71 @@ -36,7 +36,7 @@ else
72 eecho "could not find 'portageq'; aborting"
73 exit 1
74 fi
75 -eval "$(PORTAGE_SYNC_MODE=1 "${portageq}" envvar -v DISTDIR EPREFIX FEATURES \
76 +eval "$("${portageq}" envvar -v DISTDIR EPREFIX FEATURES \
77 FETCHCOMMAND GENTOO_MIRRORS \
78 PORTAGE_BIN_PATH PORTAGE_CONFIGROOT PORTAGE_GPG_DIR \
79 PORTAGE_NICENESS PORTAGE_REPOSITORIES PORTAGE_RSYNC_EXTRA_OPTS \
80
81 diff --git a/pym/_emerge/actions.py b/pym/_emerge/actions.py
82 index a080ba4..c3b0b98 100644
83 --- a/pym/_emerge/actions.py
84 +++ b/pym/_emerge/actions.py
85 @@ -2693,6 +2693,38 @@ def expand_set_arguments(myfiles, myaction, root_config):
86 newargs.append(a)
87 return (newargs, retval)
88
89 +def repo_name_check(trees):
90 + missing_repo_names = set()
91 + for root_trees in trees.values():
92 + porttree = root_trees.get("porttree")
93 + if porttree:
94 + portdb = porttree.dbapi
95 + missing_repo_names.update(portdb.getMissingRepoNames())
96 +
97 + # Skip warnings about missing repo_name entries for
98 + # /usr/local/portage (see bug #248603).
99 + try:
100 + missing_repo_names.remove('/usr/local/portage')
101 + except KeyError:
102 + pass
103 +
104 + if missing_repo_names:
105 + msg = []
106 + msg.append("WARNING: One or more repositories " + \
107 + "have missing repo_name entries:")
108 + msg.append("")
109 + for p in missing_repo_names:
110 + msg.append("\t%s/profiles/repo_name" % (p,))
111 + msg.append("")
112 + msg.extend(textwrap.wrap("NOTE: Each repo_name entry " + \
113 + "should be a plain text file containing a unique " + \
114 + "name for the repository on the first line.", 70))
115 + msg.append("\n")
116 + writemsg_level("".join("%s\n" % l for l in msg),
117 + level=logging.WARNING, noiselevel=-1)
118 +
119 + return bool(missing_repo_names)
120 +
121 def repo_name_duplicate_check(trees):
122 ignored_repos = {}
123 for root, root_trees in trees.items():
124 @@ -2810,6 +2842,7 @@ def run_action(emerge_config):
125 if "--quiet" not in emerge_config.opts:
126 portage.deprecated_profile_check(
127 settings=emerge_config.target_config.settings)
128 + repo_name_check(emerge_config.trees)
129 repo_name_duplicate_check(emerge_config.trees)
130 config_protect_check(emerge_config.trees)
131 check_procfs()
132
133 diff --git a/pym/portage/dbapi/porttree.py b/pym/portage/dbapi/porttree.py
134 index 0b8034e..23f3169 100644
135 --- a/pym/portage/dbapi/porttree.py
136 +++ b/pym/portage/dbapi/porttree.py
137 @@ -354,9 +354,7 @@ class portdbapi(dbapi):
138 """
139 Returns a list of repository paths that lack profiles/repo_name.
140 """
141 - warnings.warn("portage.dbapi.porttree.portdbapi.getMissingRepoNames() is deprecated",
142 - DeprecationWarning, stacklevel=2)
143 - return frozenset()
144 + return self.settings.repositories.missing_repo_names
145
146 def getIgnoredRepos(self):
147 """
148
149 diff --git a/pym/portage/repository/config.py b/pym/portage/repository/config.py
150 index fff619f..97f45d4 100644
151 --- a/pym/portage/repository/config.py
152 +++ b/pym/portage/repository/config.py
153 @@ -21,7 +21,6 @@ import portage
154 from portage import eclass_cache, os
155 from portage.const import (MANIFEST2_HASH_FUNCTIONS, MANIFEST2_REQUIRED_HASH,
156 PORTAGE_BASE_PATH, REPO_NAME_LOC, USER_CONFIG_PATH)
157 -from portage.dep import _repo_name_re
158 from portage.eapi import eapi_allows_directories_on_profile_level_and_repository_level
159 from portage.env.loaders import KeyValuePairFileLoader
160 from portage.util import (normalize_path, read_corresponding_eapi_file, shlex_split,
161 @@ -53,36 +52,6 @@ _repo_name_sub_re = re.compile(r'[^\w-]')
162
163 _repo_attr_override_var_re = re.compile(r'^PORTAGE_REPOSITORY:([^:]+):([^:]+)$')
164
165 -def _read_repo_name(repo_location, quiet=False):
166 - layout_data = _read_layout_conf(repo_location)[0]
167 - repo_name = layout_data.get("repo-name")
168 - if repo_name is not None:
169 - if _repo_name_re.match(repo_name) is None:
170 - if not quiet:
171 - writemsg_level("!!! %s\n" % _("Repository name set in 'repo-name' attribute in %r is invalid: %r") %
172 - (os.path.join(repo_location, "metadata", "layout.conf"), repo_name), level=logging.ERROR, noiselevel=-1)
173 - return None
174 - return repo_name
175 -
176 - repo_name_file_location = os.path.join(repo_location, REPO_NAME_LOC)
177 - try:
178 - with io.open(_unicode_encode(repo_name_file_location, encoding=_encodings["fs"], errors="strict"),
179 - mode="r", encoding=_encodings["repo.content"], errors="replace") as f:
180 - repo_name = f.read()
181 - except EnvironmentError:
182 - repo_name = None
183 - if repo_name is not None:
184 - if repo_name.endswith("\n"):
185 - repo_name = repo_name[:-1]
186 - if _repo_name_re.match(repo_name) is None:
187 - if not quiet:
188 - writemsg_level("!!! %s\n" % _("Repository name set in %r is invalid: %r") %
189 - (repo_name_file_location, repo_name), level=logging.ERROR, noiselevel=-1)
190 - return None
191 - return repo_name
192 -
193 - return None
194 -
195 def _gen_valid_repo(name):
196 """
197 Substitute hyphen in place of characters that don't conform to PMS 3.1.5,
198 @@ -117,13 +86,13 @@ class RepoConfig(object):
199 'auto_sync', 'cache_formats', 'create_manifest', 'disable_manifest',
200 'eapi', 'eclass_db', 'eclass_locations', 'eclass_overrides',
201 'find_invalid_path_char', 'force', 'format', 'local_config', 'location',
202 - 'main_repo', 'manifest_hashes', 'masters', 'module_specific_options',
203 + 'main_repo', 'manifest_hashes', 'masters', 'missing_repo_name',
204 'name', 'portage1_profiles', 'portage1_profiles_compat', 'priority',
205 'profile_formats', 'sign_commit', 'sign_manifest',
206 'sync_depth', 'sync_hooks_only_on_change',
207 'sync_type', 'sync_umask', 'sync_uri', 'sync_user', 'thin_manifest',
208 'update_changelog', '_eapis_banned', '_eapis_deprecated',
209 - '_invalid_config', '_masters_orig'
210 + '_masters_orig', 'module_specific_options',
211 )
212
213 def __init__(self, name, repo_opts, local_config=True):
214 @@ -131,57 +100,6 @@ class RepoConfig(object):
215 Try to read repo_name in repository location, but if
216 it is not found use variable name as repository name"""
217
218 - self._invalid_config = False
219 -
220 - if name == "DEFAULT":
221 - self.location = None
222 - self.name = name
223 - else:
224 - location = repo_opts.get("location")
225 - if location is None:
226 - writemsg_level("!!! %s\n" % _("Section %r in repos.conf is missing 'location' attribute") %
227 - name, level=logging.ERROR, noiselevel=-1)
228 - self._invalid_config = True
229 - else:
230 - if not os.path.isabs(location):
231 - writemsg_level("!!! %s\n" % _("Section %r in repos.conf has 'location' attribute set to "
232 - "relative path: %r") % (name, location), level=logging.ERROR, noiselevel=-1)
233 - self._invalid_config = True
234 - location = None
235 - elif not os.path.lexists(location):
236 - if not portage._sync_mode:
237 - writemsg_level("!!! %s\n" % _("Section %r in repos.conf has 'location' attribute set to "
238 - "nonexistent directory: %r") % (name, location), level=logging.ERROR, noiselevel=-1)
239 - self._invalid_config = True
240 - location = None
241 - elif not os.path.isdir(location):
242 - writemsg_level("!!! %s\n" % _("Section %r in repos.conf has 'location' attribute set to "
243 - "non-directory: %r") % (name, location), level=logging.ERROR, noiselevel=-1)
244 - self._invalid_config = True
245 - location = None
246 - elif not os.access(location, os.R_OK):
247 - writemsg_level("!!! %s\n" % _("Section %r in repos.conf has 'location' attribute set to "
248 - "nonreadable directory: %r") % (name, location), level=logging.ERROR, noiselevel=-1)
249 - self._invalid_config = True
250 - location = None
251 - else:
252 - location = os.path.realpath(location)
253 - self.location = location
254 -
255 - if self.location is None or portage._sync_mode:
256 - self.name = name
257 - else:
258 - self.name = _read_repo_name(location)
259 - if self.name is None:
260 - writemsg_level("!!! %s\n" % _("Section %r in repos.conf refers to repository without repository name "
261 - "set in %r or in 'repo-name' attribute in %r") % (name, os.path.join(location, REPO_NAME_LOC),
262 - os.path.join(location, "metadata", "layout.conf")), level=logging.ERROR, noiselevel=-1)
263 - self._invalid_config = True
264 - elif name != self.name:
265 - writemsg_level("!!! %s\n" % _("Section %r in repos.conf has name different from repository name %r "
266 - "set inside repository") % (name, self.name), level=logging.ERROR, noiselevel=-1)
267 - self._invalid_config = True
268 -
269 force = repo_opts.get('force')
270 if force is not None:
271 force = tuple(force.split())
272 @@ -270,7 +188,32 @@ class RepoConfig(object):
273 format = format.strip()
274 self.format = format
275
276 + location = repo_opts.get('location')
277 + if location is not None and location.strip():
278 + if os.path.isdir(location) or portage._sync_mode:
279 + location = os.path.realpath(location)
280 + else:
281 + location = None
282 + self.location = location
283 +
284 + missing = True
285 + self.name = name
286 + if self.location is not None:
287 + self.name, missing = self._read_valid_repo_name(self.location)
288 + if missing:
289 + # The name from repos.conf has to be used here for
290 + # things like emerge-webrsync to work when the repo
291 + # is empty (bug #484950).
292 + if name is not None:
293 + self.name = name
294 + if portage._sync_mode:
295 + missing = False
296 +
297 + elif name == "DEFAULT":
298 + missing = False
299 +
300 self.eapi = None
301 + self.missing_repo_name = missing
302 # sign_commit is disabled by default, since it requires Git >=1.7.9,
303 # and key_id configured by `git config user.signingkey key_id`
304 self.sign_commit = False
305 @@ -306,6 +249,13 @@ class RepoConfig(object):
306 # them the ability to do incremental overrides
307 self.aliases = layout_data['aliases'] + tuple(aliases)
308
309 + if layout_data['repo-name']:
310 + # allow layout.conf to override repository name
311 + # useful when having two copies of the same repo enabled
312 + # to avoid modifying profiles/repo_name in one of them
313 + self.name = layout_data['repo-name']
314 + self.missing_repo_name = False
315 +
316 for value in ('allow-missing-manifest',
317 'allow-provide-virtual', 'cache-formats',
318 'create-manifest', 'disable-manifest', 'manifest-hashes',
319 @@ -393,11 +343,15 @@ class RepoConfig(object):
320 """Update repository with options in another RepoConfig"""
321
322 keys = set(self.__slots__)
323 + keys.discard("missing_repo_name")
324 for k in keys:
325 v = getattr(new_repo, k, None)
326 if v is not None:
327 setattr(self, k, v)
328
329 + if new_repo.name is not None:
330 + self.missing_repo_name = new_repo.missing_repo_name
331 +
332 @property
333 def writable(self):
334 """
335 @@ -409,6 +363,42 @@ class RepoConfig(object):
336 """
337 return os.access(first_existing(self.location), os.W_OK)
338
339 + @staticmethod
340 + def _read_valid_repo_name(repo_path):
341 + name, missing = RepoConfig._read_repo_name(repo_path)
342 + # We must ensure that the name conforms to PMS 3.1.5
343 + # in order to avoid InvalidAtom exceptions when we
344 + # use it to generate atoms.
345 + name = _gen_valid_repo(name)
346 + if not name:
347 + # name only contains invalid characters
348 + name = "x-" + os.path.basename(repo_path)
349 + name = _gen_valid_repo(name)
350 + # If basename only contains whitespace then the
351 + # end result is name = 'x-'.
352 + return name, missing
353 +
354 + @staticmethod
355 + def _read_repo_name(repo_path):
356 + """
357 + Read repo_name from repo_path.
358 + Returns repo_name, missing.
359 + """
360 + repo_name_path = os.path.join(repo_path, REPO_NAME_LOC)
361 + f = None
362 + try:
363 + f = io.open(
364 + _unicode_encode(repo_name_path,
365 + encoding=_encodings['fs'], errors='strict'),
366 + mode='r', encoding=_encodings['repo.content'],
367 + errors='replace')
368 + return f.readline().strip(), False
369 + except EnvironmentError:
370 + return "x-" + os.path.basename(repo_path), True
371 + finally:
372 + if f is not None:
373 + f.close()
374 +
375 def info_string(self):
376 """
377 Returns a formatted string containing informations about the repository.
378 @@ -616,11 +606,6 @@ class RepoConfigLoader(object):
379 parser.remove_section(deleted_repo)
380
381 for sname in parser.sections():
382 - if _repo_name_re.match(sname) is None:
383 - writemsg_level("!!! %s\n" % _("Section %r in repos.conf has invalid name") %
384 - sname, level=logging.ERROR, noiselevel=-1)
385 - continue
386 -
387 optdict = {}
388 for oname in parser.options(sname):
389 optdict[oname] = parser.get(sname, oname)
390 @@ -639,8 +624,10 @@ class RepoConfigLoader(object):
391 # Perform repos.conf sync variable validation
392 portage.sync.validate_config(repo, logging)
393
394 - if not repo._invalid_config:
395 - prepos[sname] = repo
396 + # For backward compatibility with locations set via PORTDIR and
397 + # PORTDIR_OVERLAY, delay validation of the location and repo.name
398 + # until after PORTDIR and PORTDIR_OVERLAY have been processed.
399 + prepos[sname] = repo
400
401 def __init__(self, paths, settings):
402 """Load config from files in paths"""
403 @@ -705,10 +692,50 @@ class RepoConfigLoader(object):
404 ignored_repos = tuple((repo_name, tuple(paths)) \
405 for repo_name, paths in ignored_map.items())
406
407 + self.missing_repo_names = frozenset(repo.location
408 + for repo in prepos.values()
409 + if repo.location is not None and repo.missing_repo_name)
410 +
411 # Do this before expanding aliases, so that location_map and
412 # treemap consistently map unaliased names whenever available.
413 for repo_name, repo in list(prepos.items()):
414 - if repo_name != "DEFAULT":
415 + if repo.location is None:
416 + if repo_name != 'DEFAULT':
417 + # Skip this warning for repoman (bug #474578).
418 + if settings.local_config and paths:
419 + writemsg_level("!!! %s\n" % _("Section '%s' in repos.conf is missing location attribute") %
420 + repo.name, level=logging.ERROR, noiselevel=-1)
421 + del prepos[repo_name]
422 + continue
423 + else:
424 + if not portage._sync_mode:
425 + if not isdir_raise_eaccess(repo.location):
426 + writemsg_level("!!! %s\n" % _("Section '%s' in repos.conf has location attribute set "
427 + "to nonexistent directory: '%s'") %
428 + (repo_name, repo.location), level=logging.ERROR, noiselevel=-1)
429 +
430 + # Ignore missing directory for 'gentoo' so that
431 + # first sync with emerge-webrsync is possible.
432 + if repo.name != 'gentoo':
433 + del prepos[repo_name]
434 + continue
435 +
436 + # After removing support for PORTDIR_OVERLAY, the following check can be:
437 + # if repo.missing_repo_name:
438 + if repo.missing_repo_name and repo.name != repo_name:
439 + writemsg_level("!!! %s\n" % _("Section '%s' in repos.conf refers to repository "
440 + "without repository name set in '%s'") %
441 + (repo_name, os.path.join(repo.location, REPO_NAME_LOC)), level=logging.ERROR, noiselevel=-1)
442 + del prepos[repo_name]
443 + continue
444 +
445 + if repo.name != repo_name:
446 + writemsg_level("!!! %s\n" % _("Section '%s' in repos.conf has name different "
447 + "from repository name '%s' set inside repository") %
448 + (repo_name, repo.name), level=logging.ERROR, noiselevel=-1)
449 + del prepos[repo_name]
450 + continue
451 +
452 location_map[repo.location] = repo_name
453 treemap[repo_name] = repo.location
454
455 @@ -997,20 +1024,18 @@ def load_repository_config(settings, extra_files=None):
456 def _get_repo_name(repo_location, cached=None):
457 if cached is not None:
458 return cached
459 - return _read_repo_name(repo_location, quiet=True)
460 + name, missing = RepoConfig._read_repo_name(repo_location)
461 + if missing:
462 + return None
463 + return name
464 +
465 +def parse_layout_conf(repo_location, repo_name=None):
466 + eapi = read_corresponding_eapi_file(os.path.join(repo_location, REPO_NAME_LOC))
467
468 -def _read_layout_conf(repo_location):
469 layout_filename = os.path.join(repo_location, "metadata", "layout.conf")
470 layout_file = KeyValuePairFileLoader(layout_filename, None, None)
471 layout_data, layout_errors = layout_file.load()
472
473 - return layout_data, layout_errors
474 -
475 -def parse_layout_conf(repo_location, repo_name=None):
476 - layout_data, layout_errors = _read_layout_conf(repo_location)
477 -
478 - eapi = read_corresponding_eapi_file(os.path.join(repo_location, REPO_NAME_LOC))
479 -
480 data = {}
481
482 # None indicates abscence of a masters setting, which later code uses
483 @@ -1039,6 +1064,8 @@ def parse_layout_conf(repo_location, repo_name=None):
484 data['thin-manifest'] = layout_data.get('thin-manifests', 'false').lower() \
485 == 'true'
486
487 + data['repo-name'] = _gen_valid_repo(layout_data.get('repo-name', ''))
488 +
489 manifest_policy = layout_data.get('use-manifests', 'strict').lower()
490 data['allow-missing-manifest'] = manifest_policy != 'strict'
491 data['create-manifest'] = manifest_policy != 'false'
492
493 diff --git a/pym/repoman/repos.py b/pym/repoman/repos.py
494 index e7b8463..9a62e05 100644
495 --- a/pym/repoman/repos.py
496 +++ b/pym/repoman/repos.py
497 @@ -130,7 +130,11 @@ class RepoSettings(object):
498
499 def _add_repo(self, config_root, portdir_overlay):
500 self.repo_conf = portage.repository.config
501 - self.repo_name = self.repo_conf._read_repo_name(portdir_overlay, quiet=True)
502 + self.repo_name = self.repo_conf.RepoConfig._read_valid_repo_name(
503 + portdir_overlay)[0]
504 + self.layout_conf_data = self.repo_conf.parse_layout_conf(portdir_overlay)[0]
505 + if self.layout_conf_data['repo-name']:
506 + self.repo_name = self.layout_conf_data['repo-name']
507 tmp_conf_file = io.StringIO(textwrap.dedent("""
508 [%s]
509 location = %s