Exemple #1
0
class Installer:
    "Installer class, provides install routines for pisi packages"

    def __init__(self, package_fname):
        "initialize from a file name"
        self.package = Package(package_fname)
        self.package.read()
        self.metadata = self.package.metadata
        self.files = self.package.files
        self.pkginfo = self.metadata.package

    def install(self, ask_reinstall = True):
        "entry point"
        ctx.ui.info('Installing %s, version %s, release %s, build %s' %
                (self.pkginfo.name, self.pkginfo.version,
                 self.pkginfo.release, self.pkginfo.build))
        self.ask_reinstall = ask_reinstall
        self.check_requirements()
        self.check_relations()
        self.reinstall()
        self.extract_install()
        self.store_pisi_files()
        if ctx.comard:
            self.register_comar_scripts()
        self.update_databases()

    def check_requirements(self):
        """check system requirements"""
        #TODO: IS THERE ENOUGH SPACE?
        # what to do if / is split into /usr, /var, etc.
        pass

    def check_relations(self):
        # check if package is in database
        # If it is not, put it into 3rd party packagedb
        if not packagedb.has_package(self.pkginfo.name):
            db = packagedb.thirdparty_packagedb
            db.add_package(self.pkginfo)

        # check conflicts
        for pkg in self.metadata.package.conflicts:
            if ctx.installdb.is_installed(self.pkginfo):
                raise InstallError("Package conflicts " + pkg)

        # check dependencies
        if not ctx.config.get_option('ignore_dependency'):
            if not dependency.installable(self.pkginfo.name):
                ctx.ui.error('Dependencies for ' + self.pkginfo.name +
                             ' not satisfied')
                raise InstallError("Package not installable")

    def reinstall(self):
        "check reinstall, confirm action, and remove package if reinstall"

        pkg = self.pkginfo

        if ctx.installdb.is_installed(pkg.name): # is this a reinstallation?
            (iversion, irelease, ibuild) = ctx.installdb.get_version(pkg.name)

            # determine if same version
            same_ver = False
            ignore_build = ctx.config.options and ctx.config.options.ignore_build_no
            if (not ibuild) or (not pkg.build) or ignore_build:
                # we don't look at builds to compare two package versions
                if pkg.version == iversion and pkg.release == irelease:
                    same_ver = True
            else:
                if pkg.build == ibuild:
                    same_ver = True

            if same_ver:
                if self.ask_reinstall:
                    if not ctx.ui.confirm('Re-install same version package?'):
                        raise InstallError('Package re-install declined')
            else:
                upgrade = False
                # is this an upgrade?
                # determine and report the kind of upgrade: version, release, build
                if pkg.version > iversion:
                    ctx.ui.info('Upgrading to new upstream version')
                    upgrade = True
                elif pkg.release > irelease:
                    ctx.ui.info('Upgrading to new distribution release')
                    upgrade = True
                elif ((not ignore_build) and ibuild and pkg.build
                       and pkg.build > ibuild):
                    ctx.ui.info('Upgrading to new distribution build')
                    upgrade = True

                # is this a downgrade? confirm this action.
                if self.ask_reinstall and (not upgrade):
                    if pkg.version < iversion:
                        x = 'Downgrade to old upstream version?'
                    elif pkg.release < irelease:
                        x = 'Downgrade to old distribution release?'
                    else:
                        x = 'Downgrade to old distribution build?'
                    if not ctx.ui.confirm(x):
                        raise InstallError('Package downgrade declined')

            # remove old package then
            operations.remove_single(pkg.name)

    def extract_install(self):
        "unzip package in place"

        ctx.ui.info('Extracting files,')
        self.package.extract_dir_flat('install', ctx.config.destdir)
 
    def store_pisi_files(self):
        """put files.xml, metadata.xml, actions.py and COMAR scripts
        somewhere in the file system. We'll need these in future..."""

        ctx.ui.info('Storing %s, ' % ctx.const.files_xml)
        self.package.extract_file(ctx.const.files_xml, self.package.pkg_dir())

        ctx.ui.info('%s.' % ctx.const.metadata_xml)
        self.package.extract_file(ctx.const.metadata_xml, self.package.pkg_dir())

        for pcomar in self.metadata.package.providesComar:
            fpath = os.path.join(ctx.const.comar_dir, pcomar.script)
            # comar prefix is added to the pkg_dir while extracting comar
            # script file. so we'll use pkg_dir as destination.
            ctx.ui.info('Storing %s' % fpath)
            self.package.extract_file(fpath, self.package.pkg_dir())

    def register_comar_scripts(self):
        "register COMAR scripts"

        com = ctx.comard

        for pcomar in self.metadata.package.providesComar:
            scriptPath = os.path.join(self.package.comar_dir(),pcomar.script)
            ctx.ui.info("Registering COMAR script %s" % pcomar.script)

            com.register(pcomar.om,
                         self.metadata.package.name,
                         scriptPath)
            while 1:
                reply = com.read_cmd()
                if reply[0] == com.RESULT:
                    break
                elif reply[1] == com.ERROR:
                    raise InstallError, "COMAR.register failed!"


    def update_databases(self):
        "update databases"

        # installdb
        ctx.installdb.install(self.metadata.package.name,
                          self.metadata.package.version,
                          self.metadata.package.release,
                          self.metadata.package.build,
                          self.metadata.package.distribution)

        # installed packages
        packagedb.inst_packagedb.add_package(self.pkginfo)
class Install(AtomicOperation):
    "Install class, provides install routines for pisi packages"

    def __init__(self, package_fname, ignore_dep = None):
        "initialize from a file name"
        super(Install, self).__init__(ignore_dep)
        self.package = Package(package_fname)
        self.package.read()
        self.metadata = self.package.metadata
        self.files = self.package.files
        self.pkginfo = self.metadata.package

    def install(self, ask_reinstall = True):
        "entry point"
        ctx.ui.status(_('Installing %s, version %s, release %s, build %s') %
                (self.pkginfo.name, self.pkginfo.version,
                 self.pkginfo.release, self.pkginfo.build))
        ctx.ui.notify(pisi.ui.installing, package = self.pkginfo, files = self.files)
        self.ask_reinstall = ask_reinstall
        self.check_requirements()
        self.check_relations()
        self.check_reinstall()
        self.extract_install()
        self.store_pisi_files()
        if ctx.comar:
            import pisi.comariface as comariface
            self.register_comar_scripts()
            comariface.run_postinstall(self.pkginfo.name)
        self.update_databases()
        self.update_environment()
        ctx.ui.status()
        if self.upgrade:
            event = pisi.ui.upgraded
        else:
            event = pisi.ui.installed
        ctx.ui.notify(event, package = self.pkginfo, files = self.files)

    def check_requirements(self):
        """check system requirements"""
        #TODO: IS THERE ENOUGH SPACE?
        # what to do if / is split into /usr, /var, etc.
        pass

    def check_relations(self):
        # check conflicts
        for pkg in self.metadata.package.conflicts:
            if ctx.installdb.is_installed(self.pkginfo):
                raise Error(_("Package conflicts %s") % pkg)

        # check dependencies
        if not ctx.config.get_option('ignore_dependency'):
            if not self.pkginfo.installable():
                ctx.ui.error(_('Dependencies for %s not satisfied') %
                             self.pkginfo.name)
                raise Error(_("Package not installable"))

        # check if package is in database
        # If it is not, put it into 3rd party packagedb
        if not packagedb.has_package(self.pkginfo.name):
            db = packagedb.thirdparty_packagedb
            db.add_package(self.pkginfo)

    def check_reinstall(self):
        "check reinstall, confirm action, and schedule reinstall"

        pkg = self.pkginfo

        self.reinstall = False
        self.upgrade = False
        if ctx.installdb.is_installed(pkg.name): # is this a reinstallation?
            (iversion, irelease, ibuild) = ctx.installdb.get_version(pkg.name)

            # determine if same version
            same_ver = False
            ignore_build = ctx.config.options and ctx.config.options.ignore_build_no
            if (not ibuild) or (not pkg.build) or ignore_build:
                # we don't look at builds to compare two package versions
                if pkg.version == iversion and pkg.release == irelease:
                    same_ver = True
            else:
                if pkg.build == ibuild:
                    same_ver = True

            if same_ver:
                if self.ask_reinstall:
                    if not ctx.ui.confirm(_('Re-install same version package?')):
                        raise Error(_('Package re-install declined'))
            else:
                upgrade = False
                # is this an upgrade?
                # determine and report the kind of upgrade: version, release, build
                if pkg.version > iversion:
                    ctx.ui.info(_('Upgrading to new upstream version'))
                    upgrade = True
                elif pkg.release > irelease:
                    ctx.ui.info(_('Upgrading to new distribution release'))
                    upgrade = True
                elif ((not ignore_build) and ibuild and pkg.build
                       and pkg.build > ibuild):
                    ctx.ui.info(_('Upgrading to new distribution build'))
                    upgrade = True
                self.upgrade = upgrade

                # is this a downgrade? confirm this action.
                if self.ask_reinstall and (not upgrade):
                    if pkg.version < iversion:
                        x = _('Downgrade to old upstream version?')
                    elif pkg.release < irelease:
                        x = _('Downgrade to old distribution release?')
                    else:
                        x = _('Downgrade to old distribution build?')
                    if not ctx.ui.confirm(x):
                        raise Error(_('Package downgrade declined'))


            # schedule for reinstall
            self.old_files = ctx.installdb.files(pkg.name)
            self.old_path = ctx.installdb.pkg_dir(pkg.name, iversion, irelease)
            self.reinstall = True
            Remove(pkg.name).run_preremove()

    def extract_install(self):
        "unzip package in place"

        ctx.ui.info(_('Extracting files'))
        self.package.extract_dir_flat('install', ctx.config.dest_dir())

        if self.reinstall:
            # remove left over files
            new = set(map(lambda x: str(x.path), self.files.list))
            old = set(map(lambda x: str(x.path), self.old_files.list))
            leftover = old - new
            old_fileinfo = {}
            for fileinfo in self.old_files.list:
                old_fileinfo[str(fileinfo.path)] = fileinfo
            for path in leftover:
                Remove.remove_file( old_fileinfo[path] )

    def store_pisi_files(self):
        """put files.xml, metadata.xml, actions.py and COMAR scripts
        somewhere in the file system. We'll need these in future..."""

        ctx.ui.info(_('Storing %s, ') % ctx.const.files_xml)
        self.package.extract_file(ctx.const.files_xml, self.package.pkg_dir())

        ctx.ui.info(_('Storing %s.') % ctx.const.metadata_xml)
        self.package.extract_file(ctx.const.metadata_xml, self.package.pkg_dir())

        for pcomar in self.metadata.package.providesComar:
            fpath = os.path.join(ctx.const.comar_dir, pcomar.script)
            # comar prefix is added to the pkg_dir while extracting comar
            # script file. so we'll use pkg_dir as destination.
            ctx.ui.info(_('Storing %s') % fpath)
            self.package.extract_file(fpath, self.package.pkg_dir())

    def register_comar_scripts(self):
        "register COMAR scripts"

        for pcomar in self.metadata.package.providesComar:
            scriptPath = os.path.join(self.package.comar_dir(),pcomar.script)
            import pisi.comariface
            pisi.comariface.register(pcomar, self.metadata.package.name,
                                     scriptPath)

    def update_databases(self):
        "update databases"

        if self.reinstall:
            Remove(self.metadata.package.name).remove_db()
            Remove.remove_pisi_files(self.old_path)

        # installdb
        ctx.installdb.install(self.metadata.package.name,
                          self.metadata.package.version,
                          self.metadata.package.release,
                          self.metadata.package.build,
                          self.metadata.package.distribution)

        # filesdb
        ctx.filesdb.add_files(self.metadata.package.name, self.files)

        # installed packages
        packagedb.inst_packagedb.add_package(self.pkginfo)

    def update_environment(self):
        # check if we have any shared objects or anything under
        # /etc/env.d
        shared = False
        for x in self.files.list:
            if x.path.endswith('.so') or x.path.startswith('/etc/env.d'):
                shared = True
                break
        if not ctx.get_option('bypass_ldconfig'):
            if shared:
                ctx.ui.info(_("Regenerating /etc/ld.so.cache..."))
                util.env_update()
        else:
            ctx.ui.warning(_("Bypassing ldconfig"))