]>
Commit | Line | Data |
---|---|---|
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 |
22 | import os |
23 | import shutil | |
ca38a577 | 24 | import tempfile |
a2d1644c | 25 | |
8b6bc023 MT |
26 | import logging |
27 | log = logging.getLogger("pakfire") | |
28 | ||
964aa579 MT |
29 | from . import base |
30 | from . import metadata | |
a2d1644c | 31 | |
c605d735 | 32 | import pakfire.compress as compress |
ca38a577 | 33 | import pakfire.downloader as downloader |
c605d735 MT |
34 | import pakfire.packages as packages |
35 | import pakfire.util as util | |
a2d1644c MT |
36 | |
37 | from pakfire.constants import * | |
97d7d682 | 38 | from pakfire.i18n import _ |
a2d1644c | 39 | |
c605d735 | 40 | class 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 |
272 | class 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 |