]> git.ipfire.org Git - people/ms/pakfire.git/blame - src/pakfire/repository/local.py
Migrate to Python 3
[people/ms/pakfire.git] / src / pakfire / repository / local.py
CommitLineData
a2d1644c 1#!/usr/bin/python
b792d887
MT
2###############################################################################
3# #
4# Pakfire - The IPFire package management system #
5# Copyright (C) 2011 Pakfire development team #
6# #
7# This program is free software: you can redistribute it and/or modify #
8# it under the terms of the GNU General Public License as published by #
9# the Free Software Foundation, either version 3 of the License, or #
10# (at your option) any later version. #
11# #
12# This program is distributed in the hope that it will be useful, #
13# but WITHOUT ANY WARRANTY; without even the implied warranty of #
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
15# GNU General Public License for more details. #
16# #
17# You should have received a copy of the GNU General Public License #
18# along with this program. If not, see <http://www.gnu.org/licenses/>. #
19# #
20###############################################################################
a2d1644c 21
a2d1644c
MT
22import os
23import shutil
ca38a577 24import tempfile
a2d1644c 25
8b6bc023
MT
26import logging
27log = logging.getLogger("pakfire")
28
964aa579
MT
29from . import base
30from . import metadata
a2d1644c 31
c605d735 32import pakfire.compress as compress
ca38a577 33import pakfire.downloader as downloader
c605d735
MT
34import pakfire.packages as packages
35import pakfire.util as util
a2d1644c
MT
36
37from pakfire.constants import *
97d7d682 38from pakfire.i18n import _
a2d1644c 39
c605d735 40class RepositoryDir(base.RepositoryFactory):
27296963 41 def __init__(self, pakfire, name, description, path, key_id=None):
c605d735 42 base.RepositoryFactory.__init__(self, pakfire, name, description)
a2d1644c 43
c605d735 44 # Path to files.
a2d1644c 45 self.path = path
a2d1644c 46
0f8d6745
MT
47 # The key that is used to sign all added packages.
48 self.key_id = key_id
a2d1644c 49
8276111d
MT
50 def remove(self):
51 self.index.clear()
52 util.rm(self.path)
53
a2d1644c
MT
54 @property
55 def priority(self):
56 """
57 The local repository has always a high priority.
58 """
59 return 10
60
022c792a
MT
61 @property
62 def local(self):
63 # Yes, this is local.
64 return True
65
0f8d6745 66 def search_files(self, *paths):
c605d735 67 """
0f8d6745 68 Search for possible package files in the paths.
c605d735 69 """
0f8d6745 70 files = []
a2d1644c 71
0f8d6745
MT
72 for path in paths:
73 if not os.path.exists(path):
74 continue
c605d735 75
0f8d6745
MT
76 if os.path.isdir(path):
77 for dir, subdirs, _files in os.walk(path):
78 for file in sorted(_files):
79 # Skip files that do not have the right extension
80 if not file.endswith(".%s" % PACKAGE_EXTENSION):
81 continue
68c0e769 82
0f8d6745
MT
83 file = os.path.join(dir, file)
84 files.append(file)
68c0e769 85
0f8d6745
MT
86 elif os.path.isfile(path) and path.endswith(".%s" % PACKAGE_EXTENSION):
87 files.append(path)
68c0e769 88
0f8d6745 89 return files
68c0e769 90
ca38a577 91 def download_package(self, url):
66a0a465 92 grabber = downloader.PackageDownloader(self.pakfire)
ca38a577
MT
93
94 tmpfile = None
95 try:
96 tmpfile = tempfile.NamedTemporaryFile(mode="wb", delete=False)
ca38a577 97 tmpfile.close()
66a0a465
MT
98
99 basename = os.path.basename(url)
100 grabber.urlgrab(url, filename=tmpfile.name, text=basename)
ca38a577
MT
101
102 # Add the package to the repository.
103 self.add_package(tmpfile.name)
ca38a577
MT
104 finally:
105 # Delete the temporary file afterwards.
106 # Ignore any errors.
107 if tmpfile:
108 try:
109 os.unlink(tmpfile.name)
110 except:
111 pass
112
27296963 113 def add_packages(self, files):
0f8d6745 114 # Search for possible package files in the paths.
ca38a577 115 files = self.search_files(*files)
0f8d6745
MT
116
117 # Give up if there are no files to process.
118 if not files:
119 return
120
121 # Create progress bar.
122 pb = util.make_progress(_("%s: Adding packages...") % self.name, len(files))
68c0e769
MT
123 i = 0
124
0f8d6745 125 for file in files:
68c0e769
MT
126 if pb:
127 i += 1
128 pb.update(i)
129
ca38a577 130 # Add the package to the repository.
27296963 131 self.add_package(file, optimize_index=False)
0f8d6745 132
ca38a577
MT
133 # Optimize the index.
134 self.optimize_index()
68c0e769
MT
135
136 if pb:
137 pb.finish()
138
0f8d6745
MT
139 # Optimize the index.
140 self.index.optimize()
c605d735 141
27296963
MT
142 def add_package(self, filename, optimize_index=True, check_uuids=False):
143 repo_filename = os.path.join(self.path, os.path.basename(filename))
ca38a577 144
27296963
MT
145 # Check if the package needs to be copied.
146 needs_copy = True
ca38a577 147
27296963
MT
148 if os.path.exists(repo_filename):
149 pkg2 = packages.open(self.pakfire, self, repo_filename)
ca38a577 150
27296963
MT
151 if check_uuids:
152 pkg1 = packages.open(self.pakfire, None, filename)
ca38a577 153
27296963
MT
154 # Package file does already exist, but the UUID don't match.
155 # Copy the package file and then re-open it.
156 if pkg1.uuid == pkg2.uuid:
157 needs_copy = False
158 else:
159 needs_copy = False
ca38a577 160
27296963
MT
161 # Copy the package file
162 if needs_copy:
163 if not os.path.exists(self.path):
164 os.makedirs(self.path)
ca38a577 165
27296963
MT
166 # Copy the file.
167 try:
168 os.link(filename, repo_filename)
169 except OSError:
170 shutil.copy2(filename, repo_filename)
ca38a577 171
27296963
MT
172 # Re-open the package.
173 pkg2 = packages.open(self.pakfire, self, repo_filename)
174
175 # The package needs to be signed.
176 if self.key_id:
177 pkg2.sign(self.key_id)
ca38a577
MT
178
179 # Add package to the index.
27296963 180 self.index.add_package(pkg2)
ca38a577
MT
181
182 if optimize_index:
183 self.optimize_index()
184
ca38a577
MT
185 def optimize_index(self):
186 """
187 Optimize the index.
188 """
189 self.index.optimize()
190
c605d735
MT
191 def save(self, path=None, algo="xz"):
192 """
193 This function saves the database and metadata to path so it can
194 be exported to a remote repository.
195 """
196 if not path:
197 path = self.path
c1962d40 198
c605d735
MT
199 # Create filenames
200 metapath = os.path.join(path, METADATA_DOWNLOAD_PATH)
201 db_path = os.path.join(metapath, METADATA_DATABASE_FILE)
202 md_path = os.path.join(metapath, METADATA_DOWNLOAD_FILE)
a2d1644c 203
9f0bcfa3
MT
204 # Remove all pre-existing metadata.
205 if os.path.exists(metapath):
9f0bcfa3 206 util.rm(metapath)
a2d1644c 207
9f0bcfa3
MT
208 # Create directory for metdadata.
209 os.makedirs(metapath)
a2d1644c 210
c605d735
MT
211 # Save the database to path and get the filename.
212 self.index.write(db_path)
a2d1644c 213
c605d735
MT
214 # Make a reference to the database file that it will get a unique name
215 # so we won't get into any trouble with caching proxies.
216 db_hash = util.calc_hash1(db_path)
d507be4d 217
c605d735
MT
218 db_path2 = os.path.join(os.path.dirname(db_path),
219 "%s-%s" % (db_hash, os.path.basename(db_path)))
d507be4d 220
c605d735
MT
221 # Compress the database.
222 if algo:
97d7d682
MT
223 # Open input file and get filesize of input file.
224 f = open(db_path)
225 filesize = os.path.getsize(db_path)
226
227 # Make a nice progress bar.
228 p = util.make_progress(_("Compressing database..."), filesize)
229
230 # Create compressing file handler.
231 c = compress.compressobj(db_path2)
232
233 try:
234 size = 0
235 while True:
236 buf = f.read(BUFFER_SIZE)
237 if not buf:
238 break
239
240 if p:
241 size += len(buf)
242 p.update(size)
243
244 c.write(buf)
245 except:
246 # XXX catch compression errors
247 raise
248
249 finally:
250 f.close()
251 c.close()
252 p.finish()
253
254 # Remove old database.
255 os.unlink(db_path)
a2d1644c 256
c605d735 257 else:
97d7d682 258 shutil.move(db_path, db_path2)
a2d1644c 259
c605d735 260 # Create a new metadata object and add out information to it.
2c99efa7 261 md = metadata.Metadata(self.pakfire)
a2d1644c 262
c605d735
MT
263 # Save name of the hashed database to the metadata.
264 md.database = os.path.basename(db_path2)
265 md.database_hash1 = db_hash
266 md.database_compression = algo
a2d1644c 267
c605d735
MT
268 # Save metdata to repository.
269 md.save(md_path)
a2d1644c
MT
270
271
c605d735
MT
272class RepositoryBuild(RepositoryDir):
273 def __init__(self, pakfire):
a6bd96bc 274 # XXX it is also hardcoded
0f8d6745
MT
275 path = pakfire.config.get(None, "local_build_repo_path", "/var/lib/pakfire/local")
276 #path = os.path.join(path, pakfire.distro.sname)
a6bd96bc 277 assert path
677ff42a 278
c605d735 279 RepositoryDir.__init__(self, pakfire, "build", "Locally built packages", path)
677ff42a 280
36b328f2
MT
281 def open(self):
282 # Find all files in the repository dir.
283 files = self.search_files(self.path)
811d22ad 284
36b328f2
MT
285 # Create progress bar.
286 pb = util.make_progress(_("%s: Reading packages...") % self.name, len(files))
287 i = 0
677ff42a 288
36b328f2
MT
289 # Add all files to the index.
290 for file in files:
291 if pb:
292 i += 1
293 pb.update(i)
677ff42a 294
36b328f2
MT
295 pkg = packages.open(self.pakfire, self, file)
296 self.index.add_package(pkg)
297
298 if pb:
299 pb.finish()
0f8d6745 300
36b328f2
MT
301 # Mark repo as open.
302 self.opened = True
a2d1644c 303
36b328f2
MT
304 def close(self):
305 # Wipe the index.
306 self.index.clear()
a2d1644c 307
36b328f2
MT
308 # Mark repository as not being open.
309 self.opened = False
a2d1644c
MT
310
311 @property
0f8d6745 312 def local(self):
c605d735 313 """
0f8d6745 314 Yes, this is local.
c605d735 315 """
0f8d6745 316 return True
862bea4d
MT
317
318 @property
0f8d6745
MT
319 def priority(self):
320 return 20000