예제 #1
0
 def listCached(self):
     items = []
     for name in os.listdir(self.cacheDir):
         if len(name) != (40 + len(self.suffix)) or not name.endswith(self.suffix):
             continue
         fingerprint = sha1FromString(name[:40])
         st = util.lstat(os.path.join(self.cacheDir, name, '.used'))
         if st:
             atime = st.st_mtime
         else:
             st = util.lstat(os.path.join(self.cacheDir, name))
             if st:
                 atime = st.st_atime
             else:
                 # Disappeared
                 continue
         size = 0
         items.append(CachedItem(fingerprint, atime, size))
     return items
예제 #2
0
 def listCached(self):
     items = []
     for name in os.listdir(self.cacheDir):
         if len(name) != (40 + len(self.suffix)) or not name.endswith(
                 self.suffix):
             continue
         fingerprint = sha1FromString(name[:40])
         st = util.lstat(os.path.join(self.cacheDir, name, '.used'))
         if st:
             atime = st.st_mtime
         else:
             st = util.lstat(os.path.join(self.cacheDir, name))
             if st:
                 atime = st.st_atime
             else:
                 # Disappeared
                 continue
         size = 0
         items.append(CachedItem(fingerprint, atime, size))
     return items
예제 #3
0
    def install(self, flags, troveCs):
        ACTION_RESTORE = 1
        ACTION_SKIP = 2
        ACTION_CONFLICT = 3

        rc = SingleCapsuleOperation.install(self, flags, troveCs)
        if rc is None:
            # parent class thinks we should just ignore this troveCs; I'm
            # not going to argue with it (it's probably because the capsule
            # hasn't changed
            return None

        (oldTrv, trv) = rc
        trvInfo = troveCs.getNewNameVersionFlavor()
        oldTrvInfo = troveCs.getOldNameVersionFlavor()
        hasCapsule = troveCs.hasCapsule()

        # Updates the fsJob metadata for installing the current trove.
        # It assumes files are replaced on install, and complains if something
        # is in the way unless the appropriate flags are set. This is a very
        # much simplified version of FilesystemJob._singleTrove() which maps
        # out a complete install strategy for native packages. Note that
        # we walk all of the files in this trove, not just the new files
        # or the changed files, because RPM installs all of the files.
        toRestore = []

        changedByPathId = dict((x[0], x) for x in troveCs.getChangedFileList())

        # things which aren't change, new, or removed are unchanged
        unchangedByPathId = (set(x[0] for x in trv.iterFileList()) -
                             set(changedByPathId.iterkeys()) -
                             set(x[0] for x in troveCs.getNewFileList()) -
                             set(troveCs.getOldFileList()))

        l = []
        for oldFileInfo in troveCs.getChangedFileList():
            oldFileId, oldVersion = oldTrv.getFile(oldFileInfo[0])[1:3]
            l.append((oldFileInfo[0], oldFileId, oldVersion))

        for unchangedPathId in unchangedByPathId:
            unchangedFileId, unchangedFileVersion = \
                                    trv.getFile(unchangedPathId)[1:3]
            l.append((unchangedPathId, unchangedFileId, unchangedFileVersion))

        fileObjs = self.db.getFileVersions(l)
        fileObjsByPathId = dict(
                [ (x[0], y) for x, y in
                    itertools.izip(l, fileObjs) ] )

        for fileInfo in trv.iterFileList():
            pathId, path, fileId, version = fileInfo

            if os.path.dirname(path) in self.netSharedPath:
                # we do nothing. really. nothing.
                #
                # we don't back it up. we don't mark it as removed in
                # our database. we don't look for conflicts. nothing.
                continue

            if pathId in changedByPathId:
                oldFileId = oldTrv.getFile(pathId)[1]
                fileChange = self.changeSet.getFileChange(oldFileId, fileId)
                if (oldFileId == fileId):
                    # only the version number changed; we don't need
                    # to merge anything here
                    fileObj = fileObjsByPathId[pathId]
                elif fileChange[0] == '\x01':
                    fileObj = fileObjsByPathId[pathId]
                    fileObj.twm(fileChange, fileObj)
                else:
                    fileObj = files.ThawFile(fileChange, pathId)
            elif pathId in unchangedByPathId:
                fileObj = fileObjsByPathId[pathId]
            else:
                # if it's not changed and it's not unchanged, it must be new
                fileStream = self.changeSet.getFileChange(None, fileId)
                fileObj = files.ThawFile(fileStream, pathId)

            absolutePath = util.joinPaths(self.root, path)

            if (fileObj.flags.isCapsuleAddition()):
                # this was added to the package outside of the RPM; we don't
                # have any responsibility for it
                continue
            elif (trove.conaryContents(hasCapsule, pathId, fileObj)
                  and fileObj.lsTag != 'd'):
                # this content isn't part of the capsule; remember to put
                # it back when RPM is done
                self.preservePath(path)
                continue

            s = util.lstat(absolutePath)
            if not s:
                # there is nothing in the way, so there is nothing which
                # concerns us here. Track the file for later.
                toRestore.append((fileInfo, fileObj))
                continue

            action = ACTION_CONFLICT

            existingOwners = list(
                self.db.iterFindPathReferences(path, justPresent = True,
                                               withStream = True))

            if existingOwners:
                # Don't complain about files owned by the previous version
                # of this trove.
                l = [ x for x in existingOwners if x[0:3] == oldTrvInfo ]
                if l:
                    existingOwners.remove(l[0])

                if not existingOwners:
                    action = ACTION_RESTORE
            elif stat.S_ISDIR(s.st_mode) and fileObj.lsTag == 'd':
                # Don't let existing directories stop us from taking over
                # ownership of the directory
                action = ACTION_RESTORE
            elif fileObj.flags.isInitialContents():
                # Initial contents files may be restored on top of things
                # already in the filesystem. They're ghosts or config files
                # and RPM will get the contents right either way, and we
                # should remove them either way.
                action = ACTION_RESTORE

            if action == ACTION_CONFLICT and existingOwners:
                if fileId in [ x[4] for x in existingOwners ]:
                    # The files share metadata same. Whatever it looks like on
                    # disk, RPM is going to blow it away with the new one.
                    for info in existingOwners:
                        self.fsJob.sharedFile(info[0], info[1], info[2],
                                              info[3])
                    action = ACTION_RESTORE
                elif path.startswith('/usr/share/doc/'):
                    # Mirror badness Red Hat patches into RPM for rhel4
                    # and rhel5
                    action = ACTION_RESTORE
                else:
                    existingFiles = [ files.ThawFile(x[5], pathId) for x
                                        in existingOwners ]

                    compatibility = [ 1 for x in existingFiles
                                        if fileObj.compatibleWith(x) ]


                    if 1 in compatibility:
                        # files can be shared even though the fileId's
                        # are different
                        for info in existingOwners:
                            self.fsJob.sharedFile(info[0], info[1], info[2],
                                                  info[3])
                        action = ACTION_RESTORE
                    elif 1 in [ files.rpmFileColorCmp(x, fileObj)
                              for x in existingFiles ]:
                        # rpm file colors and the default rpm setting for
                        # file color policy make elf64 files silently replace
                        # elf32 files. follow that behavior here.
                        #
                        # no, i'm not making this up
                        #
                        # yes, really
                        action = ACTION_SKIP
                    elif (self._checkReplaceManagedFiles(flags, path) or
                          1 in [ files.rpmFileColorCmp(fileObj, x)
                                 for x in existingFiles ]):
                        # The files are different. Bail unless we're supposed
                        # to replace managed files.
                        existingFile = files.FileFromFilesystem(absolutePath,
                                                                pathId)
                        for info in existingOwners:
                            self.fsJob.userRemoval(
                                fileObj = existingFile,
                                content =
                                    filecontents.FromFilesystem(absolutePath),
                                *info[0:4])
                        action = ACTION_RESTORE
                    else:
                        # it's not up to us to decide if this is a true
                        # conflict; the database layer will do that for
                        # us (see checkPathConflicts)
                        action = ACTION_RESTORE
            elif flags.replaceUnmanagedFiles:
                # we don't own it, but it's on disk. RPM will just write over
                # it and we have the flag saying we're good with that
                action = ACTION_RESTORE

            if action == ACTION_RESTORE:
                # We may proceed, and RPM will replace this file for us. We
                # need to track that it's being restored to avoid conflicts
                # with other restorations though.
                toRestore.append((fileInfo, fileObj))
            elif action == ACTION_CONFLICT:
                # The file exists already, we can't share it, and we're not
                # allowed to overwrite it.
                self._error(errors.FileInWayError(util.normpath(path),
                                                  troveCs.getName(),
                                                  troveCs.getNewVersion(),
                                                  troveCs.getNewFlavor()))
            else:
                assert(action == ACTION_SKIP)
                self.preservePath(path)
                self.fsJob.userRemoval(trv.getName(), trv.getVersion(),
                                       trv.getFlavor(), pathId)

        # toRestore is the list of what is going to be restored. We need to get
        # the fileObjects which will be created so we can track them in the
        # filesystem job. This lets the filesystem job look for resolveable
        # conflicts within this update. We handle newly created files first
        # and files which have changed (so we have to look up the diff)
        # a bit later.
        for fileInfo, fileObj in toRestore:
            fullPath = util.joinPaths(self.root, path)
            self.fsJob._restore(fileObj, fullPath, trvInfo,
                                "restoring %s from RPM",
                                restoreFile = False,
                                fileId = fileId)
예제 #4
0
    def install(self, flags, troveCs):
        ACTION_RESTORE = 1
        ACTION_SKIP = 2
        ACTION_CONFLICT = 3

        rc = SingleCapsuleOperation.install(self, flags, troveCs)
        if rc is None:
            # parent class thinks we should just ignore this troveCs; I'm
            # not going to argue with it (it's probably because the capsule
            # hasn't changed
            return None

        (oldTrv, trv) = rc
        trvInfo = troveCs.getNewNameVersionFlavor()
        oldTrvInfo = troveCs.getOldNameVersionFlavor()
        hasCapsule = troveCs.hasCapsule()

        # Updates the fsJob metadata for installing the current trove.
        # It assumes files are replaced on install, and complains if something
        # is in the way unless the appropriate flags are set. This is a very
        # much simplified version of FilesystemJob._singleTrove() which maps
        # out a complete install strategy for native packages. Note that
        # we walk all of the files in this trove, not just the new files
        # or the changed files, because RPM installs all of the files.
        toRestore = []

        changedByPathId = dict((x[0], x) for x in troveCs.getChangedFileList())

        # things which aren't change, new, or removed are unchanged
        unchangedByPathId = (set(x[0] for x in trv.iterFileList()) -
                             set(changedByPathId.iterkeys()) -
                             set(x[0] for x in troveCs.getNewFileList()) -
                             set(troveCs.getOldFileList()))

        l = []
        for oldFileInfo in troveCs.getChangedFileList():
            oldFileId, oldVersion = oldTrv.getFile(oldFileInfo[0])[1:3]
            l.append((oldFileInfo[0], oldFileId, oldVersion))

        for unchangedPathId in unchangedByPathId:
            unchangedFileId, unchangedFileVersion = \
                                    trv.getFile(unchangedPathId)[1:3]
            l.append((unchangedPathId, unchangedFileId, unchangedFileVersion))

        fileObjs = self.db.getFileVersions(l)
        fileObjsByPathId = dict([(x[0], y)
                                 for x, y in itertools.izip(l, fileObjs)])

        for fileInfo in trv.iterFileList():
            pathId, path, fileId, version = fileInfo

            if os.path.dirname(path) in self.netSharedPath:
                # we do nothing. really. nothing.
                #
                # we don't back it up. we don't mark it as removed in
                # our database. we don't look for conflicts. nothing.
                continue

            if pathId in changedByPathId:
                oldFileId = oldTrv.getFile(pathId)[1]
                fileChange = self.changeSet.getFileChange(oldFileId, fileId)
                if (oldFileId == fileId):
                    # only the version number changed; we don't need
                    # to merge anything here
                    fileObj = fileObjsByPathId[pathId]
                elif fileChange[0] == '\x01':
                    fileObj = fileObjsByPathId[pathId]
                    fileObj.twm(fileChange, fileObj)
                else:
                    fileObj = files.ThawFile(fileChange, pathId)
            elif pathId in unchangedByPathId:
                fileObj = fileObjsByPathId[pathId]
            else:
                # if it's not changed and it's not unchanged, it must be new
                fileStream = self.changeSet.getFileChange(None, fileId)
                fileObj = files.ThawFile(fileStream, pathId)

            absolutePath = util.joinPaths(self.root, path)

            if (fileObj.flags.isCapsuleAddition()):
                # this was added to the package outside of the RPM; we don't
                # have any responsibility for it
                continue
            elif (trove.conaryContents(hasCapsule, pathId, fileObj)
                  and fileObj.lsTag != 'd'):
                # this content isn't part of the capsule; remember to put
                # it back when RPM is done
                self.preservePath(path, unlink=True)
                continue

            s = util.lstat(absolutePath)
            if not s:
                # there is nothing in the way, so there is nothing which
                # concerns us here. Track the file for later.
                toRestore.append((fileInfo, fileObj))
                continue

            action = ACTION_CONFLICT

            existingOwners = list(
                self.db.iterFindPathReferences(path,
                                               justPresent=True,
                                               withStream=True))

            if existingOwners:
                # Don't complain about files owned by the previous version
                # of this trove.
                l = [x for x in existingOwners if x[0:3] == oldTrvInfo]
                if l:
                    existingOwners.remove(l[0])

                if not existingOwners:
                    action = ACTION_RESTORE
            elif stat.S_ISDIR(s.st_mode) and fileObj.lsTag == 'd':
                # Don't let existing directories stop us from taking over
                # ownership of the directory
                action = ACTION_RESTORE
            elif fileObj.flags.isInitialContents():
                # Initial contents files may be restored on top of things
                # already in the filesystem. They're ghosts or config files
                # and RPM will get the contents right either way, and we
                # should remove them either way.
                action = ACTION_RESTORE

            if action == ACTION_CONFLICT and not existingOwners:
                # Check for "conflicts" that might just be a view across a
                # symlink.
                if self.fsJob.findAliasedRemovals(absolutePath):
                    action = ACTION_RESTORE

            if action == ACTION_CONFLICT and existingOwners:
                if fileId in [x[4] for x in existingOwners]:
                    # The files share metadata same. Whatever it looks like on
                    # disk, RPM is going to blow it away with the new one.
                    for info in existingOwners:
                        self.fsJob.sharedFile(info[0], info[1], info[2],
                                              info[3])
                    action = ACTION_RESTORE
                elif path.startswith('/usr/share/doc/'):
                    # Mirror badness Red Hat patches into RPM for rhel4
                    # and rhel5
                    action = ACTION_RESTORE
                else:
                    existingFiles = [
                        files.ThawFile(x[5], pathId) for x in existingOwners
                    ]

                    compatibility = [
                        1 for x in existingFiles if fileObj.compatibleWith(x)
                    ]

                    if 1 in compatibility:
                        # files can be shared even though the fileId's
                        # are different
                        for info in existingOwners:
                            self.fsJob.sharedFile(info[0], info[1], info[2],
                                                  info[3])
                        action = ACTION_RESTORE
                    elif 1 in [
                            files.rpmFileColorCmp(x, fileObj)
                            for x in existingFiles
                    ]:
                        # rpm file colors and the default rpm setting for
                        # file color policy make elf64 files silently replace
                        # elf32 files. follow that behavior here.
                        #
                        # no, i'm not making this up
                        #
                        # yes, really
                        action = ACTION_SKIP
                    elif (self._checkReplaceManagedFiles(flags, path) or 1 in [
                            files.rpmFileColorCmp(fileObj, x)
                            for x in existingFiles
                    ]):
                        # The files are different. Bail unless we're supposed
                        # to replace managed files.
                        existingFile = files.FileFromFilesystem(
                            absolutePath, pathId)
                        for info in existingOwners:
                            self.fsJob.userRemoval(
                                fileObj=existingFile,
                                content=filecontents.FromFilesystem(
                                    absolutePath),
                                *info[0:4])
                        action = ACTION_RESTORE
                    else:
                        # it's not up to us to decide if this is a true
                        # conflict; the database layer will do that for
                        # us (see checkPathConflicts)
                        action = ACTION_RESTORE
            elif flags.replaceUnmanagedFiles:
                # we don't own it, but it's on disk. RPM will just write over
                # it and we have the flag saying we're good with that
                action = ACTION_RESTORE

            if action == ACTION_RESTORE:
                # We may proceed, and RPM will replace this file for us. We
                # need to track that it's being restored to avoid conflicts
                # with other restorations though.
                toRestore.append((fileInfo, fileObj))
            elif action == ACTION_CONFLICT:
                # The file exists already, we can't share it, and we're not
                # allowed to overwrite it.
                self._error(
                    errors.FileInWayError(util.normpath(path),
                                          troveCs.getName(),
                                          troveCs.getNewVersion(),
                                          troveCs.getNewFlavor()))
            else:
                assert (action == ACTION_SKIP)
                self.preservePath(path, unlink=False)
                self.fsJob.userRemoval(trv.getName(), trv.getVersion(),
                                       trv.getFlavor(), pathId)

        # toRestore is the list of what is going to be restored. We need to get
        # the fileObjects which will be created so we can track them in the
        # filesystem job. This lets the filesystem job look for resolveable
        # conflicts within this update. We handle newly created files first
        # and files which have changed (so we have to look up the diff)
        # a bit later.
        for fileInfo, fileObj in toRestore:
            fullPath = util.joinPaths(self.root, path)
            self.fsJob._restore(fileObj,
                                fullPath,
                                trvInfo,
                                "restoring %s from RPM",
                                restoreFile=False,
                                fileId=fileId)