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)
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')
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()