]> git.ipfire.org Git - pakfire.git/blob - python/pakfire/repository/local.py
Add transaction test for duplicate files.
[pakfire.git] / python / pakfire / repository / local.py
1 #!/usr/bin/python
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 ###############################################################################
21
22 import logging
23 import os
24 import shutil
25
26 import base
27 import index
28 import metadata
29
30 import pakfire.compress as compress
31 import pakfire.packages as packages
32 import pakfire.util as util
33
34 from pakfire.constants import *
35
36 class RepositoryDir(base.RepositoryFactory):
37 def __init__(self, pakfire, name, description, path, type="binary"):
38 base.RepositoryFactory.__init__(self, pakfire, name, description)
39
40 # Path to files.
41 self.path = path
42
43 # Save type.
44 assert type in ("binary", "source",)
45 self.type = type
46
47 # Create index
48 self.index = index.IndexDir(self.pakfire, self)
49
50 def remove(self):
51 self.index.clear()
52 util.rm(self.path)
53
54 @property
55 def priority(self):
56 """
57 The local repository has always a high priority.
58 """
59 return 10
60
61 @property
62 def local(self):
63 # Yes, this is local.
64 return True
65
66 def collect_packages(self, *args, **kwargs):
67 """
68 Proxy function to add packages to the index.
69 """
70
71 for pkg in self.index.collect_packages(*args, **kwargs):
72 # The path of the package in the repository
73 repo_filename = os.path.join(self.path, os.path.basename(pkg.filename))
74
75 # Do we need to copy the package files?
76 copy = True
77
78 # Check, if the package does already exists and check if the
79 # files are really equal.
80 if os.path.exists(repo_filename):
81 pkg_exists = packages.open(self.pakfire, self, repo_filename)
82 copy = False
83
84 # Check UUID at first (faster) and check the file hash to be
85 # absolutely sure.
86 # Otherwise, unlink the existing file and replace it with the
87 # new one.
88 if pkg.uuid != pkg_exists.uuid and pkg.hash1 != pkg_exists.hash1:
89 # Do not copy the file if it is already okay.
90 copy = True
91 os.unlink(repo_filename)
92
93 del pkg_exists
94
95 if copy:
96 logging.debug("Copying package '%s' to repository." % pkg)
97 repo_dirname = os.path.dirname(repo_filename)
98 if not os.path.exists(repo_dirname):
99 os.makedirs(repo_dirname)
100
101 # Try to use a hard link if possible, if we cannot do that we simply
102 # copy the file.
103 try:
104 os.link(pkg.filename, repo_filename)
105 except OSError:
106 shutil.copy2(pkg.filename, repo_filename)
107
108 def save(self, path=None, algo="xz"):
109 """
110 This function saves the database and metadata to path so it can
111 be exported to a remote repository.
112 """
113 if not path:
114 path = self.path
115
116 # Create filenames
117 metapath = os.path.join(path, METADATA_DOWNLOAD_PATH)
118 db_path = os.path.join(metapath, METADATA_DATABASE_FILE)
119 md_path = os.path.join(metapath, METADATA_DOWNLOAD_FILE)
120
121 # Remove all pre-existing metadata.
122 if os.path.exists(metapath):
123 print "Removing", metapath
124 util.rm(metapath)
125
126 # Create directory for metdadata.
127 os.makedirs(metapath)
128
129 # Save the database to path and get the filename.
130 self.index.write(db_path)
131
132 # Make a reference to the database file that it will get a unique name
133 # so we won't get into any trouble with caching proxies.
134 db_hash = util.calc_hash1(db_path)
135
136 db_path2 = os.path.join(os.path.dirname(db_path),
137 "%s-%s" % (db_hash, os.path.basename(db_path)))
138
139 # Compress the database.
140 if algo:
141 compress.compress(db_path, algo=algo, progress=True)
142
143 if not os.path.exists(db_path2):
144 shutil.move(db_path, db_path2)
145 else:
146 os.unlink(db_path)
147
148 # Create a new metadata object and add out information to it.
149 md = metadata.Metadata(self.pakfire, self)
150
151 # Save name of the hashed database to the metadata.
152 md.database = os.path.basename(db_path2)
153 md.database_hash1 = db_hash
154 md.database_compression = algo
155
156 # Save metdata to repository.
157 md.save(md_path)
158
159
160 class RepositoryBuild(RepositoryDir):
161 def __init__(self, pakfire):
162 # XXX need to add distro information to this path
163 path = pakfire.config.get("local_build_repo_path")
164
165 # Create path if it does not exist.
166 if not os.path.exists(path):
167 os.makedirs(path)
168
169 RepositoryDir.__init__(self, pakfire, "build", "Locally built packages", path)
170
171 @property
172 def local(self):
173 """
174 Yes, this is local.
175 """
176 return True
177
178 @property
179 def priority(self):
180 return 20000
181
182
183 class RepositoryLocal(base.RepositoryFactory):
184 def __init__(self, pakfire):
185 base.RepositoryFactory.__init__(self, pakfire, "@system", "Local repository")
186
187 self.index = index.IndexLocal(self.pakfire, self)
188
189 # Tell the solver, that these are the installed packages.
190 self.pool.set_installed(self.solver_repo)
191
192 @property
193 def priority(self):
194 """
195 The local repository has always a high priority.
196 """
197 return 10
198
199 def add_package(self, pkg):
200 # Add package to the database.
201 self.index.db.add_package(pkg)
202
203 self.index.add_package(pkg)
204
205 def rem_package(self, pkg):
206 # Remove package from the database.
207 self.index.rem_package(pkg)
208
209 @property
210 def filelist(self):
211 return self.index.filelist