]> git.ipfire.org Git - pakfire.git/commitdiff
Add transaction test for duplicate files.
authorMichael Tremer <michael.tremer@ipfire.org>
Fri, 30 Sep 2011 09:58:02 +0000 (11:58 +0200)
committerMichael Tremer <michael.tremer@ipfire.org>
Fri, 30 Sep 2011 12:24:25 +0000 (14:24 +0200)
12 files changed:
po/pakfire.pot
python/pakfire/actions.py
python/pakfire/base.py
python/pakfire/errors.py
python/pakfire/filelist.py [new file with mode: 0644]
python/pakfire/i18n.py
python/pakfire/packages/file.py
python/pakfire/packages/installed.py
python/pakfire/repository/database.py
python/pakfire/repository/index.py
python/pakfire/repository/local.py
python/pakfire/transaction.py

index 38cfa04697c6dea140a34371da688fdb6b1f9f25..e3ea95e1d27abb973fe2a6d73ea7622b8afd04cd 100644 (file)
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-09-27 16:07+0200\n"
+"POT-Creation-Date: 2011-09-28 12:35+0200\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -17,46 +17,53 @@ msgstr ""
 "Content-Type: text/plain; charset=CHARSET\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-#: ../python/pakfire/actions.py:108
+#: ../python/pakfire/actions.py:112
 #, python-format
 msgid "Cannot run scriptlet because no interpreter is available: %s"
 msgstr ""
 
-#: ../python/pakfire/actions.py:112
+#: ../python/pakfire/actions.py:116
 #, python-format
 msgid "Cannot run scriptlet because the interpreter is not executable: %s"
 msgstr ""
 
-#: ../python/pakfire/actions.py:161
+#: ../python/pakfire/actions.py:165
 #, python-format
 msgid ""
 "The scriptlet returned an error:\n"
 "%s"
 msgstr ""
 
-#: ../python/pakfire/actions.py:164
+#: ../python/pakfire/actions.py:168
 #, python-format
 msgid "The scriptlet ran more than %s seconds and was killed."
 msgstr ""
 
-#: ../python/pakfire/actions.py:222 ../python/pakfire/actions.py:279
+#: ../python/pakfire/actions.py:223 ../python/pakfire/actions.py:239
+#: ../python/pakfire/actions.py:262 ../python/pakfire/actions.py:285
+#: ../python/pakfire/actions.py:302 ../python/pakfire/actions.py:321
+#, python-format
+msgid "Running transaction test for %s"
+msgstr ""
+
+#: ../python/pakfire/actions.py:232 ../python/pakfire/actions.py:314
 msgid "Installing"
 msgstr ""
 
-#: ../python/pakfire/actions.py:232
+#: ../python/pakfire/actions.py:248
 msgid "Updating"
 msgstr ""
 
-#: ../python/pakfire/actions.py:246
+#: ../python/pakfire/actions.py:268
 msgid "Removing"
 msgstr ""
 
 #. Cleaning up leftover files and stuff.
-#: ../python/pakfire/actions.py:264
+#: ../python/pakfire/actions.py:292
 msgid "Cleanup"
 msgstr ""
 
-#: ../python/pakfire/actions.py:289
+#: ../python/pakfire/actions.py:330
 msgid "Downgrading"
 msgstr ""
 
@@ -70,270 +77,274 @@ msgstr ""
 msgid "There are no packages to install."
 msgstr ""
 
-#: ../python/pakfire/base.py:451
+#: ../python/pakfire/base.py:454
 msgid "Build command has failed."
 msgstr ""
 
-#: ../python/pakfire/base.py:535
+#: ../python/pakfire/base.py:538
 msgid "Everything is fine."
 msgstr ""
 
-#: ../python/pakfire/builder.py:123
+#: ../python/pakfire/builder.py:122
 msgid "Package information:"
 msgstr ""
 
 #. Copy the makefile and load source tarballs.
-#: ../python/pakfire/builder.py:261
+#: ../python/pakfire/builder.py:284
 msgid "Extracting"
 msgstr ""
 
-#: ../python/pakfire/builder.py:551
+#: ../python/pakfire/builder.py:540
 msgid "The build command failed. See logfile for details."
 msgstr ""
 
 #. Package the result.
 #. Make all these little package from the build environment.
-#: ../python/pakfire/builder.py:700
+#: ../python/pakfire/builder.py:684
 msgid "Creating packages:"
 msgstr ""
 
 #. Execute the buildscript of this stage.
-#: ../python/pakfire/builder.py:720
+#: ../python/pakfire/builder.py:704
 #, python-format
 msgid "Running stage %s:"
 msgstr ""
 
-#: ../python/pakfire/cli.py:42
+#: ../python/pakfire/cli.py:43
 msgid "Pakfire command line interface."
 msgstr ""
 
-#: ../python/pakfire/cli.py:49
+#: ../python/pakfire/cli.py:50
 msgid "The path where pakfire should operate in."
 msgstr ""
 
-#: ../python/pakfire/cli.py:112
+#: ../python/pakfire/cli.py:113
 msgid "Enable verbose output."
 msgstr ""
 
-#: ../python/pakfire/cli.py:115
+#: ../python/pakfire/cli.py:116
 msgid "Path to a configuration file to load."
 msgstr ""
 
-#: ../python/pakfire/cli.py:118
+#: ../python/pakfire/cli.py:119
 msgid "Disable a repository temporarily."
 msgstr ""
 
-#: ../python/pakfire/cli.py:121
+#: ../python/pakfire/cli.py:122
 msgid "Enable a repository temporarily."
 msgstr ""
 
-#: ../python/pakfire/cli.py:124
+#: ../python/pakfire/cli.py:125
 msgid "Run pakfire in offline mode."
 msgstr ""
 
-#: ../python/pakfire/cli.py:129
+#: ../python/pakfire/cli.py:130
 msgid "Install one or more packages to the system."
 msgstr ""
 
-#: ../python/pakfire/cli.py:131
+#: ../python/pakfire/cli.py:132
 msgid "Give name of at least one package to install."
 msgstr ""
 
-#: ../python/pakfire/cli.py:137
+#: ../python/pakfire/cli.py:138
 msgid "Install one or more packages from the filesystem."
 msgstr ""
 
-#: ../python/pakfire/cli.py:139
+#: ../python/pakfire/cli.py:140
 msgid "Give filename of at least one package."
 msgstr ""
 
-#: ../python/pakfire/cli.py:145
+#: ../python/pakfire/cli.py:146
 msgid "Remove one or more packages from the system."
 msgstr ""
 
-#: ../python/pakfire/cli.py:147
+#: ../python/pakfire/cli.py:148
 msgid "Give name of at least one package to remove."
 msgstr ""
 
-#: ../python/pakfire/cli.py:153
+#: ../python/pakfire/cli.py:154
 msgid "Update the whole system or one specific package."
 msgstr ""
 
-#: ../python/pakfire/cli.py:155 ../python/pakfire/cli.py:163
+#: ../python/pakfire/cli.py:156 ../python/pakfire/cli.py:164
 msgid "Give a name of a package to update or leave emtpy for all."
 msgstr ""
 
-#: ../python/pakfire/cli.py:161
+#: ../python/pakfire/cli.py:162
 msgid "Check, if there are any updates available."
 msgstr ""
 
-#: ../python/pakfire/cli.py:169
+#: ../python/pakfire/cli.py:170
 msgid "Print some information about the given package(s)."
 msgstr ""
 
-#: ../python/pakfire/cli.py:171
+#: ../python/pakfire/cli.py:172
 msgid "Give at least the name of one package."
 msgstr ""
 
-#: ../python/pakfire/cli.py:177
+#: ../python/pakfire/cli.py:178
 msgid "Search for a given pattern."
 msgstr ""
 
-#: ../python/pakfire/cli.py:179
+#: ../python/pakfire/cli.py:180
 msgid "A pattern to search for."
 msgstr ""
 
-#: ../python/pakfire/cli.py:185
+#: ../python/pakfire/cli.py:186
 msgid "Get a list of packages that provide a given file or feature."
 msgstr ""
 
-#: ../python/pakfire/cli.py:187
+#: ../python/pakfire/cli.py:188
 msgid "File or feature to search for."
 msgstr ""
 
-#: ../python/pakfire/cli.py:193
+#: ../python/pakfire/cli.py:194
 msgid "Get list of packages that belong to the given group."
 msgstr ""
 
-#: ../python/pakfire/cli.py:195
+#: ../python/pakfire/cli.py:196
 msgid "Group name to search for."
 msgstr ""
 
-#: ../python/pakfire/cli.py:201
+#: ../python/pakfire/cli.py:202
 msgid "Install all packages that belong to the given group."
 msgstr ""
 
-#: ../python/pakfire/cli.py:203
+#: ../python/pakfire/cli.py:204
 msgid "Group name."
 msgstr ""
 
-#: ../python/pakfire/cli.py:209
+#: ../python/pakfire/cli.py:210
 msgid "List all currently enabled repositories."
 msgstr ""
 
-#: ../python/pakfire/cli.py:213
+#: ../python/pakfire/cli.py:214
 msgid "Cleanup commands."
 msgstr ""
 
-#: ../python/pakfire/cli.py:221
+#: ../python/pakfire/cli.py:222
 msgid "Cleanup all temporary files."
 msgstr ""
 
-#: ../python/pakfire/cli.py:227
+#: ../python/pakfire/cli.py:228
 msgid "Check the system for any errors."
 msgstr ""
 
-#: ../python/pakfire/cli.py:233
+#: ../python/pakfire/cli.py:234
 msgid "Check the dependencies for a particular package."
 msgstr ""
 
-#: ../python/pakfire/cli.py:235
+#: ../python/pakfire/cli.py:236
 msgid "Give name of at least one package to check."
 msgstr ""
 
-#: ../python/pakfire/cli.py:298 ../python/pakfire/transaction.py:194
+#: ../python/pakfire/cli.py:299 ../python/pakfire/transaction.py:246
 msgid "Repository"
 msgstr ""
 
-#: ../python/pakfire/cli.py:298
+#: ../python/pakfire/cli.py:299
 msgid "Enabled"
 msgstr ""
 
-#: ../python/pakfire/cli.py:298
+#: ../python/pakfire/cli.py:299
 msgid "Priority"
 msgstr ""
 
-#: ../python/pakfire/cli.py:298
+#: ../python/pakfire/cli.py:299
 msgid "Packages"
 msgstr ""
 
-#: ../python/pakfire/cli.py:310
+#: ../python/pakfire/cli.py:311
 msgid "Cleaning up everything..."
 msgstr ""
 
-#: ../python/pakfire/cli.py:324 ../python/pakfire/cli.py:579
+#: ../python/pakfire/cli.py:327
+msgid "You cannot run pakfire-builder in a pakfire chroot."
+msgstr ""
+
+#: ../python/pakfire/cli.py:330 ../python/pakfire/cli.py:585
 msgid "Pakfire builder command line interface."
 msgstr ""
 
-#: ../python/pakfire/cli.py:379
+#: ../python/pakfire/cli.py:385
 msgid "Update the package indexes."
 msgstr ""
 
-#: ../python/pakfire/cli.py:385 ../python/pakfire/cli.py:599
+#: ../python/pakfire/cli.py:391 ../python/pakfire/cli.py:605
 msgid "Build one or more packages."
 msgstr ""
 
-#: ../python/pakfire/cli.py:387 ../python/pakfire/cli.py:601
+#: ../python/pakfire/cli.py:393 ../python/pakfire/cli.py:607
 msgid "Give name of at least one package to build."
 msgstr ""
 
-#: ../python/pakfire/cli.py:391 ../python/pakfire/cli.py:605
+#: ../python/pakfire/cli.py:397 ../python/pakfire/cli.py:611
 msgid "Build the package for the given architecture."
 msgstr ""
 
-#: ../python/pakfire/cli.py:393 ../python/pakfire/cli.py:419
-#: ../python/pakfire/cli.py:607
+#: ../python/pakfire/cli.py:399 ../python/pakfire/cli.py:425
+#: ../python/pakfire/cli.py:613
 msgid "Path were the output files should be copied to."
 msgstr ""
 
-#: ../python/pakfire/cli.py:395 ../python/pakfire/cli.py:408
-#: ../python/pakfire/cli.py:609
+#: ../python/pakfire/cli.py:401 ../python/pakfire/cli.py:414
+#: ../python/pakfire/cli.py:615
 msgid "Mode to run in. Is either 'release' or 'development' (default)."
 msgstr ""
 
-#: ../python/pakfire/cli.py:400
+#: ../python/pakfire/cli.py:406
 msgid "Go into a shell."
 msgstr ""
 
-#: ../python/pakfire/cli.py:402
+#: ../python/pakfire/cli.py:408
 msgid "Give name of a package."
 msgstr ""
 
-#: ../python/pakfire/cli.py:406
+#: ../python/pakfire/cli.py:412
 msgid "Emulated architecture in the shell."
 msgstr ""
 
-#: ../python/pakfire/cli.py:413
+#: ../python/pakfire/cli.py:419
 msgid "Generate a source package."
 msgstr ""
 
-#: ../python/pakfire/cli.py:415
+#: ../python/pakfire/cli.py:421
 msgid "Give name(s) of a package(s)."
 msgstr ""
 
-#: ../python/pakfire/cli.py:492
+#: ../python/pakfire/cli.py:498
 msgid "Pakfire server command line interface."
 msgstr ""
 
-#: ../python/pakfire/cli.py:529
+#: ../python/pakfire/cli.py:535
 msgid "Request a build job from the server."
 msgstr ""
 
-#: ../python/pakfire/cli.py:535
+#: ../python/pakfire/cli.py:541
 msgid "Send a keepalive to the server."
 msgstr ""
 
-#: ../python/pakfire/cli.py:542
+#: ../python/pakfire/cli.py:548
 msgid "Update all repositories."
 msgstr ""
 
-#: ../python/pakfire/cli.py:548
+#: ../python/pakfire/cli.py:554
 msgid "Repository management commands."
 msgstr ""
 
-#: ../python/pakfire/cli.py:556
+#: ../python/pakfire/cli.py:562
 msgid "Create a new repository index."
 msgstr ""
 
-#: ../python/pakfire/cli.py:557
+#: ../python/pakfire/cli.py:563
 msgid "Path to the packages."
 msgstr ""
 
-#: ../python/pakfire/cli.py:558
+#: ../python/pakfire/cli.py:564
 msgid "Path to input packages."
 msgstr ""
 
-#: ../python/pakfire/cli.py:611
+#: ../python/pakfire/cli.py:617
 msgid "Do not verify build dependencies."
 msgstr ""
 
@@ -358,15 +369,23 @@ msgid ""
 "line and try again."
 msgstr ""
 
+#: ../python/pakfire/errors.py:78
+msgid "Running pakfire-build in a pakfire container?"
+msgstr ""
+
+#: ../python/pakfire/errors.py:82 ../python/pakfire/transaction.py:308
+msgid "Transaction test was not successful"
+msgstr ""
+
 #: ../python/pakfire/packages/base.py:89
 msgid "Name"
 msgstr ""
 
-#: ../python/pakfire/packages/base.py:90 ../python/pakfire/transaction.py:193
+#: ../python/pakfire/packages/base.py:90 ../python/pakfire/transaction.py:245
 msgid "Arch"
 msgstr ""
 
-#: ../python/pakfire/packages/base.py:91 ../python/pakfire/transaction.py:193
+#: ../python/pakfire/packages/base.py:91 ../python/pakfire/transaction.py:245
 msgid "Version"
 msgstr ""
 
@@ -374,7 +393,7 @@ msgstr ""
 msgid "Release"
 msgstr ""
 
-#: ../python/pakfire/packages/base.py:96 ../python/pakfire/transaction.py:194
+#: ../python/pakfire/packages/base.py:96 ../python/pakfire/transaction.py:246
 msgid "Size"
 msgstr ""
 
@@ -460,11 +479,11 @@ msgstr ""
 msgid "Filename: %s"
 msgstr ""
 
-#: ../python/pakfire/packages/make.py:101
+#: ../python/pakfire/packages/make.py:100
 msgid "Package name is undefined."
 msgstr ""
 
-#: ../python/pakfire/packages/make.py:104
+#: ../python/pakfire/packages/make.py:103
 msgid "Package version is undefined."
 msgstr ""
 
@@ -536,62 +555,70 @@ msgstr ""
 msgid "    Solutions:"
 msgstr ""
 
-#: ../python/pakfire/transaction.py:128
+#: ../python/pakfire/transaction.py:180
 msgid "Downloading packages:"
 msgstr ""
 
-#: ../python/pakfire/transaction.py:193
+#: ../python/pakfire/transaction.py:245
 msgid "Package"
 msgstr ""
 
-#: ../python/pakfire/transaction.py:198
+#: ../python/pakfire/transaction.py:250
 msgid "Installing:"
 msgstr ""
 
-#: ../python/pakfire/transaction.py:199
+#: ../python/pakfire/transaction.py:251
 msgid "Reinstalling:"
 msgstr ""
 
-#: ../python/pakfire/transaction.py:200
+#: ../python/pakfire/transaction.py:252
 msgid "Updating:"
 msgstr ""
 
-#: ../python/pakfire/transaction.py:201
+#: ../python/pakfire/transaction.py:253
 msgid "Downgrading:"
 msgstr ""
 
-#: ../python/pakfire/transaction.py:202
+#: ../python/pakfire/transaction.py:254
 msgid "Removing:"
 msgstr ""
 
-#: ../python/pakfire/transaction.py:208
+#: ../python/pakfire/transaction.py:260
 msgid "Transaction Summary"
 msgstr ""
 
-#: ../python/pakfire/transaction.py:215
+#: ../python/pakfire/transaction.py:267
 msgid "package"
 msgstr ""
 
-#: ../python/pakfire/transaction.py:221
+#: ../python/pakfire/transaction.py:273
 #, python-format
 msgid "Total download size: %s"
 msgstr ""
 
-#: ../python/pakfire/transaction.py:225
+#: ../python/pakfire/transaction.py:277
 #, python-format
 msgid "Installed size: %s"
 msgstr ""
 
-#: ../python/pakfire/transaction.py:227
+#: ../python/pakfire/transaction.py:279
 #, python-format
 msgid "Freed size: %s"
 msgstr ""
 
-#: ../python/pakfire/transaction.py:236
+#: ../python/pakfire/transaction.py:288
 msgid "Is this okay?"
 msgstr ""
 
-#: ../python/pakfire/transaction.py:242
+#: ../python/pakfire/transaction.py:291
+msgid "Running Transaction Test"
+msgstr ""
+
+#: ../python/pakfire/transaction.py:303
+msgid "Transaction Test Succeeded"
+msgstr ""
+
+#: ../python/pakfire/transaction.py:317
 msgid "Running transaction"
 msgstr ""
 
index 2efa609543ef8990171d168039646c7678c18ed8..ee1b5275b54e0c15320576e7f167b541043d9376 100644 (file)
@@ -52,6 +52,10 @@ class Action(object):
                # A function to run additional initialization.
                pass
 
+       def check(self, filelist):
+               # This is just a dummy test that does nothing at all.
+               return filelist
+
        @property
        def needs_download(self):
                return self.type in ("install", "reinstall", "upgrade", "downgrade",) \
@@ -215,6 +219,12 @@ class ActionScriptPostTransUp(ActionScriptPostTrans):
 class ActionInstall(Action):
        type = "install"
 
+       def check(self, check):
+               logging.debug(_("Running transaction test for %s") % self.pkg.friendly_name)
+
+               # Check if this package can be installed.
+               check.install(self.pkg)
+
        def run(self):
                # Add package to the database.
                self.local.add_package(self.pkg)
@@ -225,6 +235,12 @@ class ActionInstall(Action):
 class ActionUpdate(Action):
        type = "upgrade"
 
+       def check(self, check):
+               logging.debug(_("Running transaction test for %s") % self.pkg.friendly_name)
+
+               # Check if this package can be updated.
+               check.update(self.pkg)
+
        def run(self):
                # Add new package to the database.
                self.local.add_package(self.pkg)
@@ -242,6 +258,12 @@ class ActionRemove(Action):
                self.pkg = self.local.index.db.get_package_from_solv(self.pkg_solv)
                assert self.pkg
 
+       def check(self, check):
+               logging.debug(_("Running transaction test for %s") % self.pkg.friendly_name)
+
+               # Check if this package can be removed.
+               check.remove(self.pkg)
+
        def run(self):
                self.pkg.cleanup(_("Removing"), prefix=self.pakfire.path)
 
@@ -259,6 +281,12 @@ class ActionCleanup(Action):
                self.pkg = self.local.index.db.get_package_from_solv(self.pkg_solv)
                assert self.pkg
 
+       def check(self, check):
+               logging.debug(_("Running transaction test for %s") % self.pkg.friendly_name)
+
+               # Check if this package can be removed.
+               check.cleanup(self.pkg)
+
        def run(self):
                # Cleaning up leftover files and stuff.
                self.pkg.cleanup(_("Cleanup"), prefix=self.pakfire.path)
@@ -270,6 +298,13 @@ class ActionCleanup(Action):
 class ActionReinstall(Action):
        type = "reinstall"
 
+       def check(self, check):
+               logging.debug(_("Running transaction test for %s") % self.pkg.friendly_name)
+
+               # Check if this package can be reinstalled.
+               check.remove(self.pkg)
+               check.install(self.pkg)
+
        def run(self):
                # Remove package from the database and add it afterwards.
                # Sounds weird, but fixes broken entries in the database.
@@ -282,6 +317,12 @@ class ActionReinstall(Action):
 class ActionDowngrade(Action):
        type = "downgrade"
 
+       def check(self, check):
+               logging.debug(_("Running transaction test for %s") % self.pkg.friendly_name)
+
+               # Check if this package can be downgraded.
+               check.install(self.pkg)
+
        def run(self):
                # Add new package to database.
                self.local.add_package(self.pkg)
index b2c2fed3960e69dcb422cc76fb9efa6fc409956a..2b2fd54f28a147a68208376a6bdd270c9df21ab5 100644 (file)
@@ -27,6 +27,7 @@ import string
 import builder
 import config
 import distro
+import filelist
 import logger
 import repository
 import packages
@@ -106,7 +107,10 @@ class Pakfire(object):
        def create_relation(self, s):
                assert s
 
-               if s.startswith("/"):
+               if isinstance(s, filelist._File):
+                       return satsolver.Relation(self.pool, s.name)
+
+               elif s.startswith("/"):
                        return satsolver.Relation(self.pool, s)
 
                for pattern, type in self.RELATIONS:
index 87cb84014c21803129c4224b80d0060bff43d13d..9e8f0cc0e373a4ffb04c5fdd00bfe89de09d16e5 100644 (file)
@@ -76,3 +76,7 @@ class PakfireError(Error):
 
 class PakfireContainerError(Error):
        message = _("Running pakfire-build in a pakfire container?")
+
+
+class TransactionCheckError(Error):
+       message = _("Transaction test was not successful")
diff --git a/python/pakfire/filelist.py b/python/pakfire/filelist.py
new file mode 100644 (file)
index 0000000..4f280f5
--- /dev/null
@@ -0,0 +1,92 @@
+#!/usr/bin/python
+###############################################################################
+#                                                                             #
+# Pakfire - The IPFire package management system                              #
+# Copyright (C) 2011 Pakfire development team                                 #
+#                                                                             #
+# 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 3 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, see <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+###############################################################################
+
+class _File(object):
+       def __init__(self, pakfire):
+               self.pakfire = pakfire
+
+
+class File(_File):
+       def __init__(self, pakfire):
+               _File.__init__(self, pakfire)
+
+               self.name = ""
+               self.pkg  = None
+               self.size = -1
+               self.hash1 = ""
+
+       def __cmp__(self, other):
+               return cmp(self.pkg, other.pkg) or cmp(self.name, other.name)
+
+       def is_dir(self):
+               # XXX TODO
+               # VERY POOR CHECK
+               return self.name.endswith("/")
+
+       def is_config(self):
+               # XXX TODO
+               return False
+
+
+class FileDatabase(_File):
+       def __init__(self, pakfire, db, row_id):
+               _File.__init__(self, pakfire)
+
+               self.db = db
+               self.row_id = row_id
+
+               self.__row = None
+
+       @property
+       def row(self):
+               """
+                       Lazy fetching of the database row.
+               """
+               if self.__row is None:
+                       c = self.db.cursor()
+                       c.execute("SELECT * FROM files WHERE id = ? LIMIT 1", (self.row_id,))
+
+                       # Check if we got the same row.
+                       #assert c.lastrowid == self.row_id
+
+                       for row in c:
+                               self.__row = row
+                               break
+
+                       c.close()
+
+               return self.__row
+
+       @property
+       def pkg(self):
+               return self.db.get_package_by_id(self.row["pkg"])
+
+       @property
+       def name(self):
+               return self.row["name"]
+
+       @property
+       def size(self):
+               return self.row["size"]
+
+       @property
+       def hash1(self):
+               return self.row["hash1"]
index 2980dce5e96a6f16b450c9ac81be8f8a6b68b92c..cae14ebe0724442306dde7d099afd9662213638e 100644 (file)
@@ -41,3 +41,17 @@ def _(singular, plural=None, n=None):
                return gettext.dngettext("pakfire", singular, plural, n)
 
        return gettext.dgettext("pakfire", singular)
+
+def list(self, parts):
+       """
+               Returns a comma-separated list for the given list of parts.
+
+               The format is, e.g., "A, B and C", "A and B" or just "A" for lists
+               of size 1.
+       """
+       if len(parts) == 0: return ""
+       if len(parts) == 1: return parts[0]
+       return _("%(commas)s and %(last)s") % {
+               "commas": u", ".join(parts[:-1]),
+               "last": parts[len(parts) - 1],
+       }
index f6e370902d2c3127104fa2e2b3ed1e89cf9f9d08..ed37fee5250eb1ea213388d01ba691c362e4beb3 100644 (file)
@@ -26,6 +26,7 @@ import tarfile
 import tempfile
 import xattr
 
+import pakfire.filelist
 import pakfire.util as util
 import pakfire.compress as compress
 from pakfire.constants import *
@@ -133,6 +134,9 @@ class FilePackage(Package):
                # Place to cache the metadata
                self._metadata = {}
 
+               # Place to cache the filelist
+               self._filelist = None
+
                # Store the format of this package file.
                self.format = self.get_format()
 
@@ -332,33 +336,51 @@ class FilePackage(Package):
 
                return inst_size
 
-       @property
-       def filelist(self):
+       def get_filelist(self):
                """
                        Return a list of the files that are contained in the package
                        payload.
                """
+               ret = []
+
                a = self.open_archive()
                f = a.extractfile("filelist")
 
-               ret = []
                for line in f.readlines():
                        line = line.strip()
 
+                       file = pakfire.filelist.File(self.pakfire)
+
                        if self.format >= 1:
                                line = line.split()
-                               line = line[0]
+                               name = line[0]
 
-                       if not line.startswith("/"):
-                               line = "/%s" % line
+                               # XXX need to parse the rest of the information from the
+                               # file
 
-                       ret.append(line)
+                       else:
+                               name = line
+
+                       if not name.startswith("/"):
+                               name = "/%s" % name
+
+                       file.name = name
+                       file.pkg  = self
+
+                       ret.append(file)
 
                f.close()
                a.close()
 
                return ret
 
+       @property
+       def filelist(self):
+               if self._filelist is None:
+                       self._filelist = self.get_filelist()
+
+               return self._filelist
+
        @property
        def configfiles(self):
                a = self.open_archive()
index 4f01fec37cdf4e9b086fa9eec6d2a3a13845ab8a..f0d8364d56bd4392950cfb527d1e1376f86224bf 100644 (file)
@@ -22,6 +22,7 @@
 import os
 
 import pakfire.downloader
+import pakfire.filelist
 
 from base import Package
 from file import BinaryPackage
@@ -168,13 +169,16 @@ class DatabasePackage(Package):
 
        @property
        def filelist(self):
+               filelist = []
+
                c = self.db.cursor()
-               try:
-                       c.execute("SELECT name FROM files WHERE pkg = ?", (self.id,))
+               c.execute("SELECT id FROM files WHERE pkg = ?", (self.id,))
+
+               for id in c:
+                       file = pakfire.filelist.FileDatabase(self.pakfire, self.db, id[0])
+                       filelist.append(file)
 
-                       return [f["name"] for f in c]
-               finally:
-                       c.close()
+               return filelist
 
        @property
        def configfiles(self):
index f8dc8ca8d0eda0e85b918162cbdb69921baead86..1b3872f02d8f324b788a501e61b58bf57ae68a4a 100644 (file)
@@ -117,6 +117,7 @@ class DatabaseLocal(Database):
                        INSERT INTO settings(key, val) VALUES('version', '0');
 
                        CREATE TABLE files(
+                               id                      INTEGER PRIMARY KEY,
                                name            TEXT,
                                pkg                     INTEGER,
                                size            INTEGER,
@@ -233,8 +234,8 @@ class DatabaseLocal(Database):
 
                        pkg_id = c.lastrowid
 
-                       c.executemany("INSERT INTO files(name, pkg) VALUES(?, ?)",
-                               ((file, pkg_id) for file in pkg.filelist))
+                       c.executemany("INSERT INTO files(name, pkg, size, hash1) VALUES(?, ?, ?, ?)",
+                               ((f.name, pkg_id, f.size, f.hash1) for f in pkg.filelist))
 
                except:
                        raise
@@ -266,6 +267,17 @@ class DatabaseLocal(Database):
                c.close()
                self.commit()
 
+       def get_package_by_id(self, id):
+               c = self.cursor()
+               c.execute("SELECT * FROM packages WHERE id = ?", (id,))
+
+               try:
+                       for row in c:
+                               return packages.DatabasePackage(self.pakfire, self.repo, self, row)
+
+               finally:
+                       c.close()
+
        @property
        def packages(self):
                c = self.cursor()
index 9a398d240cbe77883631458141e00a5effb8013a..9b4b309fa71c327af98d342de2091230f1928da8 100644 (file)
@@ -433,3 +433,9 @@ class IndexLocal(Index):
 
                        if pb:
                                pb.finish()
+
+       @property
+       def filelist(self):
+               for pkg in self.db.packages:
+                       for file in pkg.filelist:
+                               yield file
index 5ca12fc3212b89e39502e27e01f82bbb64aafba9..8e41f5e07e8b0d9d2fa2bde720e7ad7a4259959d 100644 (file)
@@ -205,3 +205,7 @@ class RepositoryLocal(base.RepositoryFactory):
        def rem_package(self, pkg):
                # Remove package from the database.
                self.index.rem_package(pkg)
+
+       @property
+       def filelist(self):
+               return self.index.filelist
index 5dd9d5f0e4c73906a733981b5c47bbbdfbae9e4c..e7734a850b7d340e91bbe2ef8b661b8441dd350c 100644 (file)
@@ -25,6 +25,7 @@ import progressbar
 import sys
 import time
 
+import i18n
 import packages
 import satsolver
 import util
@@ -37,6 +38,86 @@ PKG_DUMP_FORMAT = " %-21s %-8s %-21s %-18s %6s "
 # Import all actions directly.
 from actions import *
 
+class TransactionCheck(object):
+       def __init__(self, pakfire, transaction):
+               self.pakfire = pakfire
+               self.transaction = transaction
+
+               # A place to store errors.
+               self.errors = []
+
+               # Get a list of all installed files from the database.
+               self.filelist = self.load_filelist()
+
+       @property
+       def error_files(self):
+               ret = {}
+
+               for name, files in self.filelist.items():
+                       if len(files) <= 1:
+                               continue
+
+                       ret[name] = files
+
+               return ret
+
+       @property
+       def successful(self):
+               return not self.error_files
+
+       def print_errors(self):
+               for name, files in sorted(self.error_files.items()):
+                       assert len(files) >= 2
+
+                       pkgs = [f.pkg.friendly_name for f in files]
+
+                       if len(files) == 2:
+                               logging.critical(
+                                       _("file %s from %s conflicts with file from package %s") % \
+                                               (name, pkgs[0], pkgs[1])
+                               )
+
+                       elif len(files) >= 3:
+                               logging.critical(
+                                       _("file %s from %s conflicts with files from %s") % \
+                                               (name, pkgs[0], i18n.list(pkgs[1:]))
+                               )
+
+       def load_filelist(self):
+               filelist = {}
+
+               for file in self.pakfire.repos.local.filelist:
+                       filelist[file.name] = [file,]
+
+               return filelist
+
+       def install(self, pkg):
+               for file in pkg.filelist:
+                       if file.is_dir():
+                               continue
+
+                       if self.filelist.has_key(file.name):
+                               self.filelist[file.name].append(file)
+
+                       else:
+                               self.filelist[file.name] = [file,]
+
+                               #self.errors.append((self.ERROR_TYPE_CONFLICT, file))
+
+       def remove(self, pkg):
+               for file in pkg.filelist:
+                       try:
+                               self.filelist[file.name].remove(file)
+                       except KeyError:
+                               pass
+
+       def update(self, pkg):
+               self.install(pkg)
+
+       def cleanup(self, pkg):
+               self.remove(pkg)
+
+
 class Transaction(object):
        action_classes = {
                ActionInstall.type   : [ActionScriptPreIn, ActionInstall, ActionScriptPostIn, ActionScriptPostTransIn],
@@ -235,10 +316,32 @@ class Transaction(object):
 
                return util.ask_user(_("Is this okay?"))
 
+       def check(self):
+               logging.info(_("Running Transaction Test"))
+
+               # Initialize the check object.
+               check = TransactionCheck(self.pakfire, self)
+
+               for action in self.actions:
+                       try:
+                               action.check(check)
+                       except ActionError, e:
+                               raise
+
+               if check.successful:
+                       logging.info(_("Transaction Test Succeeded"))
+                       return
+
+               check.print_errors()
+               raise TransactionCheckError, _("Transaction test was not successful")
+
        def run(self):
                # Download all packages.
                self.download()
 
+               # Run the transaction test
+               self.check()
+
                logging.info(_("Running transaction"))
                # Run all actions in order and catch all kinds of ActionError.
                for action in self.actions: