File: Pool.py

package info (click to toggle)
debpartial-mirror 0.3.1%2Bnmu1
  • links: PTS, VCS
  • area: main
  • in suites: buster, stretch
  • size: 476 kB
  • sloc: python: 3,117; makefile: 16
file content (187 lines) | stat: -rw-r--r-- 5,882 bytes parent folder | download | duplicates (3)
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
# debpartial_mirror - partial debian mirror package tool
# (c) 2004 Otavio Salvador <otavio@debian.org>, Marco Presi <zufus@debian.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA	02111-1307	USA

import os
import sys

import apt_pkg

from cdd import FileSystem

from debpartial_mirror import Download


class Pool:
	"""
	This class provides methods to manage pool dirs into the
	partial-mirror.
	"""
	def __init__(self, backend):
		self._backend = backend
		self._got_files = []
		self._containsForeignPackages = False
		self._filesystem = FileSystem.FileSystem(
			backend["mirror_dir"],
			backend["name"]
		)

	def _process_package(self, pkg):
		"""
		This method is called for each package and should be override
		in each child class.
		"""
		raise NotImplemented

	def _calc_need_files(self):
		"""
		This method is called to build the list of need files to
		permit to us to clean up the mirror. If you need to handle in
		a special way to calc it, you're free to override this method.
		"""
		if not len(self._got_files):
			self._backend.process()
			need_files = []
			for architecture in self._backend["architectures"]:
				need_files.extend([pkg['Filename'] for pkg in self._backend.get_binary_list(architecture).values()])
		else:
			need_files = self._got_files

		return need_files

	def _link_internal(self, pkg, mirror):
		filename = pkg['Filename']
		self._filesystem.mkdir(os.path.dirname(filename))
		src = self._backend["mirror_dir"] + "/" + mirror["name"] + "/" + filename
		dst = os.path.join(self._filesystem.base(), filename)
		if not os.path.exists(dst):
			try:
				print "Linking [%s] %s" % (mirror["name"],  filename)
				os.link (src, dst)
			except OSError, msg:
				print "Error while linking a file:"
				print " [%s] %s" % (mirror["name"], filename)
				print " System message: %s" % msg
				sys.exit(1) #TODO: fixme
		self._got_files.append(filename)

	def upgrade(self):
		"""
		Manage the pool upgrade process
		TODO: Handle source packages.
		"""
		def processPackage(pkg, architecture):
			foundList =  self._backend.get_binary_list(architecture).whereis(pkg["Package"])
			if foundList in  (self._backend.get_binary_list(architecture), self._backend.get_full_binary_list(architecture)):
				self._process_package(pkg)
			else: # required dependency from another mirror
				for backend in self._backend.backends:
					if backend.get_full_binary_list(architecture) == foundList:
						break
				else:
					raise RuntimeError("No backend found for %s", pkg["Package"])

				self._link_internal(pkg, backend)
				self._containsForeignPackages = True

		for architecture in self._backend["architectures"]:
			for pkg in self._backend.get_binary_list(architecture).values():
				filename = pkg['Filename']
				if not self._filesystem.exists(filename):
					processPackage(pkg, architecture)
				elif self._filesystem.md5sum(filename) == pkg['MD5sum']:
					self._got_files.append(filename)
				else:
					print 'Removing corrupted package', pkg['Package']
					self._filesystem.remove(filename)
					processPackage(pkg, architecture)


	def clean (self):
		"""
		Clean old files
		"""
		need_files = self._calc_need_files()

		# Walk in all debian related files of mirror
		for current in self._filesystem.match("^.+\.(dsc|(diff|tar)\.gz|deb|udeb)$"):
			if current not in need_files:
				print "Removing unneeded file: %s" % current
				self._filesystem.remove(current)
				try:
					self._filesystem.rmdir(os.path.dirname(current), True)
				except OSError:
					pass

	def containsForeignPackages(self):
		return self._containsForeignPackages


class RemotePool (Pool):
	"""
	This class provides methods to fill pool dir downloading remote files
	"""
	def __init__ (self, backend):
		Pool.__init__(self, backend) # Call parent constructor

		self.download = Download.Download(name = "Pool_" + backend["name"]) # Our Download manager

	def _process_package (self, pkg):
		self._filesystem.mkdir(os.path.dirname(pkg['Filename']))

		self.download.get(
			os.path.join(self._backend["server"], pkg['Filename']),
			os.path.join(self._filesystem.base(), pkg['Filename'])
		)
		self._got_files.append(pkg['Filename'])

	def upgrade (self):
		Pool.upgrade(self) # Call parent method
		self.download.wait_mine() # Wait until our downloads finish


class LocalPool (Pool):
	"""
	This class provides methods to fill pool dir linking from local files
	"""
	def _process_package (self):
		self._filesystem.mkdir(os.path.dirname(pkg['Filename']))
		os.link(
			self._backend["server"].split('file://')[1] + pkg,
			self._local + pkg
		)
		self._got_files.append(pkg['Filename'])


class MergePool (Pool):
	"""
	This class provides methods to fill pool dir mergin other pools
	"""

	def _calc_need_files(self):
		need_files = []
		for architecture in self._backend["architectures"]:
			for mirror in self._backend.get_mirrors():
				for pkg in self._backend.get_packages_for_mirror(mirror, architecture).values():
					need_files.append(pkg['Filename'])
		return need_files

	def merge (self):
		for architecture in self._backend["architectures"]:
			for mirror in self._backend.get_mirrors():
				for pkg in self._backend.get_packages_for_mirror(mirror, architecture).values():
					self._link_internal(pkg, mirror)