aboutsummaryrefslogtreecommitdiff
blob: 8fc3269ca0a7ac3fc2820984e15836bd178d4157 (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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# Copyright 2005-2020 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2

from _emerge.Package import Package

import portage
from portage import os
from portage.exception import InvalidData
from portage.versions import _pkg_str

class MoveHandler:

	def __init__(self, tree, porttree):
		self._tree = tree
		self._portdb = porttree.dbapi
		self._update_keys = Package._dep_keys
		self._master_repo = self._portdb.repositories.mainRepo()
		if self._master_repo is not None:
			self._master_repo = self._master_repo.name

	def _grab_global_updates(self):
		from portage.update import grab_updates, parse_updates
		retupdates = {}
		errors = []

		for repo_name in self._portdb.getRepositories():
			repo = self._portdb.getRepositoryPath(repo_name)
			updpath = os.path.join(repo, "profiles", "updates")
			if not os.path.isdir(updpath):
				continue

			try:
				rawupdates = grab_updates(updpath)
			except portage.exception.DirectoryNotFound:
				rawupdates = []
			upd_commands = []
			for mykey, mystat, mycontent in rawupdates:
				commands, errors = parse_updates(mycontent)
				upd_commands.extend(commands)
				errors.extend(errors)
			retupdates[repo_name] = upd_commands

		if self._master_repo in retupdates:
			retupdates['DEFAULT'] = retupdates[self._master_repo]

		return retupdates, errors

	def check(self, **kwargs):
		onProgress = kwargs.get('onProgress', None)
		allupdates, errors = self._grab_global_updates()
		# Matching packages and moving them is relatively fast, so the
		# progress bar is updated in indeterminate mode.
		match = self._tree.dbapi.match
		aux_get = self._tree.dbapi.aux_get
		pkg_str = self._tree.dbapi._pkg_str
		settings = self._tree.dbapi.settings
		if onProgress:
			onProgress(0, 0)
		for repo, updates in allupdates.items():
			if repo == 'DEFAULT':
				continue
			if not updates:
				continue

			def repo_match(repository):
				return repository == repo or \
					(repo == self._master_repo and \
					repository not in allupdates)

			for i, update_cmd in enumerate(updates):
				if update_cmd[0] == "move":
					origcp, newcp = update_cmd[1:]
					for cpv in match(origcp):
						try:
							cpv = pkg_str(cpv, origcp.repo)
						except (KeyError, InvalidData):
							continue
						if repo_match(cpv.repo):
							errors.append("'%s' moved to '%s'" % (cpv, newcp))
				elif update_cmd[0] == "slotmove":
					pkg, origslot, newslot = update_cmd[1:]
					atom = pkg.with_slot(origslot)
					for cpv in match(atom):
						try:
							cpv = pkg_str(cpv, atom.repo)
						except (KeyError, InvalidData):
							continue
						if repo_match(cpv.repo):
							errors.append("'%s' slot moved from '%s' to '%s'" % \
								(cpv, origslot, newslot))
				if onProgress:
					onProgress(0, 0)

		# Searching for updates in all the metadata is relatively slow, so this
		# is where the progress bar comes out of indeterminate mode.
		cpv_all = self._tree.dbapi.cpv_all()
		cpv_all.sort()
		maxval = len(cpv_all)
		meta_keys = self._update_keys + self._portdb._pkg_str_aux_keys
		if onProgress:
			onProgress(maxval, 0)
		for i, cpv in enumerate(cpv_all):
			try:
				metadata = dict(zip(meta_keys, aux_get(cpv, meta_keys)))
			except KeyError:
				continue
			try:
				pkg = _pkg_str(cpv, metadata=metadata, settings=settings)
			except InvalidData:
				continue
			metadata = dict((k, metadata[k]) for k in self._update_keys)
			try:
				updates = allupdates[pkg.repo]
			except KeyError:
				try:
					updates = allupdates['DEFAULT']
				except KeyError:
					continue
			if not updates:
				continue
			metadata_updates = \
				portage.update_dbentries(updates, metadata, parent=pkg)
			if metadata_updates:
				errors.append("'%s' has outdated metadata" % cpv)
			if onProgress:
				onProgress(maxval, i+1)

		if errors:
			return (False, errors)
		return (True, None)

	def fix(self,  **kwargs):
		onProgress = kwargs.get('onProgress', None)
		allupdates, errors = self._grab_global_updates()
		# Matching packages and moving them is relatively fast, so the
		# progress bar is updated in indeterminate mode.
		move = self._tree.dbapi.move_ent
		slotmove = self._tree.dbapi.move_slot_ent
		if onProgress:
			onProgress(0, 0)
		for repo, updates in allupdates.items():
			if repo == 'DEFAULT':
				continue
			if not updates:
				continue

			def repo_match(repository):
				return repository == repo or \
					(repo == self._master_repo and \
					repository not in allupdates)

			for i, update_cmd in enumerate(updates):
				if update_cmd[0] == "move":
					move(update_cmd, repo_match=repo_match)
				elif update_cmd[0] == "slotmove":
					slotmove(update_cmd, repo_match=repo_match)
				if onProgress:
					onProgress(0, 0)

		# Searching for updates in all the metadata is relatively slow, so this
		# is where the progress bar comes out of indeterminate mode.
		self._tree.dbapi.update_ents(allupdates, onProgress=onProgress)
		if errors:
			return (False, errors)
		return (True, None)

class MoveInstalled(MoveHandler):

	short_desc = "Perform package move updates for installed packages"

	@staticmethod
	def name():
		return "moveinst"

	def __init__(self):
		eroot = portage.settings['EROOT']
		MoveHandler.__init__(self, portage.db[eroot]["vartree"], portage.db[eroot]["porttree"])

class MoveBinary(MoveHandler):

	short_desc = "Perform package move updates for binary packages"

	@staticmethod
	def name():
		return "movebin"

	def __init__(self):
		eroot = portage.settings['EROOT']
		MoveHandler.__init__(self, portage.db[eroot]["bintree"], portage.db[eroot]['porttree'])