Ejemplo n.º 1
0
def updateAll(cfg, **kwargs):
    showItems = kwargs.pop('showItems', False)
    restartInfo = kwargs.get('restartInfo', None)
    migrate = kwargs.pop('migrate', False)
    modelArg = kwargs.pop('model', False)
    modelFile = kwargs.get('systemModelFile', None)
    model = kwargs.get('systemModel', None)
    infoArg = kwargs.get('info', False)

    if model and modelFile and modelFile.exists() and restartInfo is None:
        model.refreshVersionSnapshots()
        if modelArg:
            model.write(sys.stdout)
            sys.stdout.flush()
            return None

    kwargs['installMissing'] = kwargs['removeNotByDefault'] = migrate
    if 'callback' not in kwargs or not kwargs.get('callback'):
        kwargs['callback'] = UpdateCallback(cfg)
    # load trove cache only if --info provided
    kwargs['loadTroveCache'] = infoArg

    client = conaryclient.ConaryClient(cfg)
    # We want to be careful not to break the old style display, for whoever
    # might have a parser for that output.
    withLongDisplay = (cfg.fullFlavors or cfg.fullVersions or cfg.showLabels)
    formatter = UpdateAllFormatter()
    if restartInfo or (model and modelFile and modelFile.exists()):
        updateItems = []
        applyList = None
    else:
        if showItems and withLongDisplay:
            updateItems = client.getUpdateItemList()
            dcfg = display.DisplayConfig()
            dcfg.setTroveDisplay(fullFlavors = cfg.fullFlavors,
                                 fullVersions = cfg.fullVersions,
                                 showLabels = cfg.showLabels)
            formatter = display.TroveTupFormatter(dcfg)
        else:
            updateItems = client.fullUpdateItemList()
            applyList = [ (x[0], (None, None), x[1:], True) for x in updateItems ]

    if showItems:
        for (name, version, flavor) in sorted(updateItems, key=lambda x:x[0]):
            print formatter.formatNVF(name, version, flavor)
        return

    _updateTroves(cfg, applyList, **kwargs)
    # Clean up after ourselves
    if restartInfo:
        util.rmtree(restartInfo, ignore_errors=True)
Ejemplo n.º 2
0
    def testFlavorDisplayed(self):
        repos = self.openRepository()
        db = self.openDatabase()

        foobar = Flavor('~foo,~bar')
        nofoobar = Flavor('~!foo,~!bar')
        v1 = VFS('/localhost@rpl:devel/1.0-1-1')

        dcfg = display.DisplayConfig(repos, db)
        dcfg.setTroveDisplay(baseFlavors=[Flavor('~foo')])
        formatter = display.TroveTupFormatter(dcfg)
        formatter.prepareTuples([('foo', v1, foobar), ('foo', v1, nofoobar)])

        vStr, flv = formatter.getTupleStrings('foo', v1, foobar)
        assert (str(flv) == '~bar,~foo')

        vStr, flv = formatter.getTupleStrings('foo', v1, nofoobar)
        assert (str(flv) == '~!bar,~!foo')
Ejemplo n.º 3
0
def _updateTroves(cfg, applyList, **kwargs):
    # Take out the apply-related keyword arguments
    applyDefaults = dict(
                        replaceFiles = False,
                        replaceManagedFiles = False,
                        replaceUnmanagedFiles = False,
                        replaceModifiedFiles = False,
                        replaceModifiedConfigFiles = False,
                        tagScript = None,
                        justDatabase = False,
                        skipCapsuleOps = False,
                        info = False,
                        keepJournal = False,
                        noRestart = False,
                        noScripts = False,
    )
    applyKwargs = {}
    for k in applyDefaults:
        if k in kwargs:
            applyKwargs[k] = kwargs.pop(k)

    callback = kwargs.pop('callback')
    loadTroveCache = kwargs.pop('loadTroveCache', False)
    applyKwargs['test'] = kwargs.get('test', False)
    applyKwargs['localRollbacks'] = cfg.localRollbacks
    applyKwargs['autoPinList'] = cfg.pinTroves

    model = kwargs.pop('systemModel', None)
    modelFile = kwargs.pop('systemModelFile', None)
    modelGraph = kwargs.pop('modelGraph', None)
    modelTrace = kwargs.pop('modelTrace', None)

    noRestart = applyKwargs.get('noRestart', False)

    client = conaryclient.ConaryClient(cfg, modelFile=modelFile)
    client.setUpdateCallback(callback)
    if kwargs.pop('disconnected', False):
        client.disconnectRepos()
    migrate = kwargs.get('migrate', False)
    # even though we no longer differentiate forceMigrate, we still
    # remove it from kwargs to avoid confusing prepareUpdateJob
    kwargs.pop('forceMigrate', False)
    restartInfo = kwargs.get('restartInfo', None)

    # Initialize the critical update set
    applyCriticalOnly = kwargs.get('applyCriticalOnly', False)
    if kwargs.get('criticalUpdateInfo') is not None:
        kwargs['criticalUpdateInfo'].criticalOnly = applyCriticalOnly
    else:
        kwargs['criticalUpdateInfo'] = CriticalUpdateInfo(applyCriticalOnly)

    info = applyKwargs.pop('info', False)

    # Rename depCheck to resolveDeps
    depCheck = kwargs.pop('depCheck', True)
    kwargs['resolveDeps'] = depCheck

    if not info:
        client.checkWriteableRoot()

    # Unfortunately there's no easy way to make 'test' or 'info' mode work
    # with capsule sync, doubly so because it influences the decisions made
    # later on about what troves to update. So this will always really
    # apply, but the good news is that it never modifies the system outside
    # of the Conary DB.
    client.syncCapsuleDatabase(callback, makePins=True)

    updJob = client.newUpdateJob()

    try:
        if model:
            changeSetList = kwargs.get('fromChangesets', [])
            criticalUpdates = kwargs.get('criticalUpdateInfo', None)

            tc = modelupdate.CMLTroveCache(client.getDatabase(),
                                                   client.getRepos(),
                                                   callback = callback,
                                                   changeSetList =
                                                        changeSetList)
            tcPath = cfg.root + cfg.dbPath + '/modelcache'
            if loadTroveCache:
                if os.path.exists(tcPath):
                    log.info("loading %s", tcPath)
                    callback.loadingModelCache()
                    tc.load(tcPath)
            ts = client.cmlGraph(model, changeSetList = changeSetList)
            if modelGraph is not None:
                ts.g.generateDotFile(modelGraph)
            suggMap = client._updateFromTroveSetGraph(updJob, ts, tc,
                                        fromChangesets = changeSetList,
                                        criticalUpdateInfo = criticalUpdates,
                                        callback = callback)
            if modelTrace is not None:
                ts.g.trace([ parseTroveSpec(x) for x in modelTrace ] )

            finalModel = copy.deepcopy(model)
            if model.suggestSimplifications(tc, ts.g):
                log.info("possible system model simplifications found")
                ts2 = client.cmlGraph(model, changeSetList = changeSetList)
                updJob2 = client.newUpdateJob()
                try:
                    suggMap2 = client._updateFromTroveSetGraph(updJob2, ts2,
                                        tc,
                                        fromChangesets = changeSetList,
                                        criticalUpdateInfo = criticalUpdates)
                except errors.TroveNotFound:
                    log.info("bad model generated; bailing")
                else:
                    if (suggMap == suggMap2 and
                        updJob.getJobs() == updJob2.getJobs()):
                        log.info("simplified model verfied; using it instead")
                        ts = ts2
                        finalModel = model
                        updJob = updJob2
                        suggMap = suggMap2
                    else:
                        log.info("simplified model changed result; ignoring")

            model = finalModel
            modelFile.model = finalModel

            if tc.cacheModified():
                log.info("saving %s", tcPath)
                callback.savingModelCache()
                tc.save(tcPath)
                callback.done()
        else:
            suggMap = client.prepareUpdateJob(updJob, applyList, **kwargs)
    except:
        callback.done()
        client.close()
        raise

    if info:
        callback.done()
        displayUpdateInfo(updJob, cfg, noRestart=noRestart)
        if restartInfo and not model:
            callback.done()
            newJobs = set(itertools.chain(*updJob.getJobs()))
            oldJobs = set(updJob.getItemList())
            addedJobs = newJobs - oldJobs
            removedJobs = oldJobs - newJobs
            if addedJobs or removedJobs:
                print
                print 'NOTE: after critical updates were applied, the contents of the update were recalculated:'
                print
                displayChangedJobs(addedJobs, removedJobs, cfg)
        updJob.close()
        client.close()
        return

    if model:
        missingLocalTroves = model.getMissingLocalTroves(tc, ts)
        if missingLocalTroves:
            print 'Update would leave references to missing local troves:'
            for troveTup in missingLocalTroves:
                if not isinstance(troveTup, trovetup.TroveTuple):
                    troveTup = trovetup.TroveTuple(troveTup)
                print "\t" + str(troveTup)
            client.close()
            return

    if suggMap:
        callback.done()
        dcfg = display.DisplayConfig()
        dcfg.setTroveDisplay(fullFlavors = cfg.fullFlavors,
                             fullVersions = cfg.fullVersions,
                             showLabels = cfg.showLabels)
        formatter = display.TroveTupFormatter(dcfg)

        print "Including extra troves to resolve dependencies:"
        print "   ",

        items = sorted(set(formatter.formatNVF(*x)
                       for x in itertools.chain(*suggMap.itervalues())))
        print " ".join(items)

    askInteractive = cfg.interactive
    if restartInfo:
        callback.done()
        newJobs = set(itertools.chain(*updJob.getJobs()))
        oldJobs = set(updJob.getItemList())
        addedJobs = newJobs - oldJobs
        removedJobs = oldJobs - newJobs

        if not model and addedJobs or removedJobs:
            print 'NOTE: after critical updates were applied, the contents of the update were recalculated:'
            displayChangedJobs(addedJobs, removedJobs, cfg)
        else:
            askInteractive = False

    if not updJob.jobs:
        # Nothing to do
        print 'Update would not modify system'
        if model and not kwargs.get('test'):
            # Make sure 'conary sync' clears model.next even if nothing needs
            # to be done.
            modelFile.closeSnapshot()
        updJob.close()
        client.close()
        return

    elif askInteractive:
        print 'The following updates will be performed:'
        displayUpdateInfo(updJob, cfg, noRestart=noRestart)

    if migrate and cfg.interactive:
        print ('Migrate erases all troves not referenced in the groups'
               ' specified.')

    if askInteractive:
        if migrate:
            style = 'migrate'
        else:
            style = 'update'
        okay = cmdline.askYn('continue with %s? [Y/n]' % style, default=True)
        if not okay:
            updJob.close()
            client.close()
            return

    if not noRestart and updJob.getCriticalJobs():
        print "Performing critical system updates, will then restart update."
    try:
        restartDir = client.applyUpdateJob(updJob, **applyKwargs)
    finally:
        updJob.close()
        client.close()

    if restartDir:
        params = sys.argv

        # Write command line to disk
        import xmlrpclib
        cmdlinefile = open(os.path.join(restartDir, 'cmdline'), "w")
        cmdlinefile.write(xmlrpclib.dumps((params, ), methodresponse = True))
        cmdlinefile.close()

        # CNY-980: we should have the whole script of changes to perform in
        # the restart directory (in the job list); if in migrate mode, re-exec
        # as regular update
        if migrate and 'migrate' in params:
            params[params.index('migrate')] = 'update'

        params.extend(['--restart-info=%s' % restartDir])
        client.close()
        raise errors.ReexecRequired(
                'Critical update completed, rerunning command...', params,
                restartDir)
    else:
        if (not kwargs.get('test', False)) and model:
            modelFile.closeSnapshot()