aboutsummaryrefslogtreecommitdiff
blob: a4bce9073b6f74c6074fb526e7748e151980e1e0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# Copyright 2020 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2

from collections import OrderedDict
from collections.abc import Mapping
from hashlib import md5

from portage.localization import _
from portage.util import _recursive_file_list, writemsg
from portage.util.configparser import (SafeConfigParser, ConfigParserError,
	read_configs)


class BinRepoConfig:
	__slots__ = (
		'name',
		'name_fallback',
		'priority',
		'sync_uri',
	)
	def __init__(self, opts):
		"""
		Create a BinRepoConfig with options in opts.
		"""
		for k in self.__slots__:
			setattr(self, k, opts.get(k.replace('_', '-')))

	def info_string(self):
		"""
		Returns a formatted string containing informations about the repository.
		Used by emerge --info.
		"""
		indent = " " * 4
		repo_msg = []
		repo_msg.append(self.name or self.name_fallback)
		if self.priority is not None:
			repo_msg.append(indent + "priority: " + str(self.priority))
		repo_msg.append(indent + "sync-uri: " + self.sync_uri)
		repo_msg.append("")
		return "\n".join(repo_msg)


class BinRepoConfigLoader(Mapping):
	def __init__(self, paths, settings):
		"""Load config from files in paths"""

		# Defaults for value interpolation.
		parser_defaults = {
			"EPREFIX" : settings["EPREFIX"],
			"EROOT" : settings["EROOT"],
			"PORTAGE_CONFIGROOT" : settings["PORTAGE_CONFIGROOT"],
			"ROOT" : settings["ROOT"],
		}

		try:
			parser = self._parse(paths, parser_defaults)
		except ConfigParserError as e:
			writemsg(
				_("!!! Error while reading binrepo config file: %s\n") % e,
				noiselevel=-1)
			parser = SafeConfigParser(defaults=parser_defaults)

		repos = []
		sync_uris = []
		for section_name in parser.sections():
			repo_data = dict(parser[section_name].items())
			repo_data['name'] = section_name
			repo = BinRepoConfig(repo_data)
			if repo.sync_uri is None:
				writemsg(_("!!! Missing sync-uri setting for binrepo %s\n") % (repo.name,), noiselevel=-1)
				continue

			sync_uri = self._normalize_uri(repo.sync_uri)
			sync_uris.append(sync_uri)
			repo.sync_uri = sync_uri
			if repo.priority is not None:
				try:
					repo.priority = int(repo.priority)
				except ValueError:
					repo.priority = None
			repos.append(repo)

		sync_uris = set(sync_uris)
		current_priority = 0
		for sync_uri in reversed(settings.get("PORTAGE_BINHOST", "").split()):
			sync_uri = self._normalize_uri(sync_uri)
			if sync_uri not in sync_uris:
				current_priority += 1
				sync_uris.add(sync_uri)
				repos.append(BinRepoConfig({
					'name-fallback': self._digest_uri(sync_uri),
					'name': None,
					'priority': current_priority,
					'sync-uri': sync_uri,
				}))

		self._data = OrderedDict((repo.name or repo.name_fallback, repo) for repo in
			sorted(repos, key=lambda repo: (repo.priority or 0, repo.name or repo.name_fallback)))

	@staticmethod
	def _digest_uri(uri):
		return md5(uri.encode('utf_8')).hexdigest()

	@staticmethod
	def _normalize_uri(uri):
		return uri.rstrip('/')

	@staticmethod
	def _parse(paths, defaults):
		parser = SafeConfigParser(defaults=defaults)
		recursive_paths = []
		for p in paths:
			if isinstance(p, str):
				recursive_paths.extend(_recursive_file_list(p))
			else:
				recursive_paths.append(p)

		read_configs(parser, recursive_paths)
		return parser

	def __iter__(self):
		return iter(self._data)

	def __contains__(self, key):
		return key in self._data

	def __getitem__(self, key):
		return self._data[key]

	def __len__(self):
		return len(self._data)