def runCommand(self, cfg, argSet, args, profile=False, callback=None, repos=None): args = args[1:] level = log.getVerbosity() message = argSet.pop("message", None) test = argSet.pop("test", False) logfile = argSet.pop("log-file", None) if argSet or len(args) != 1: return self.usage() if message and logfile: raise errors.ConaryError("options --message and --log-file are " "mutually exclusive") if logfile: # Read the checkin message from the file if logfile == '-': message = sys.stdin.read() else: try: message = open(logfile).read() except IOError, e: raise errors.ConaryError("While opening %s: %s" % (e.filename, e.strerror)) # Get rid of trailing white spaces, they're probably not # intended to be there anyway message = message.rstrip()
def loadEntitlementFromString(xmlContent, *args, **kw): # handle old callers source = kw.get('source', '<override>') serverName = kw.get('serverName', None) if len(args): if len(args) == 1: source = args[0] elif len(args) == 2: serverName = args[0] source = args[1] else: raise TypeError( 'loadEntitlementFromString() takes exactly 1 argument (%d given)' % len(args)) if serverName: import warnings warnings.warn( "The serverName argument to loadEntitlementFromString " "has been deprecated", DeprecationWarning) returnTimeout = kw.pop('returnTimeout', False) p = EntitlementParser() # wrap this in an <entitlement> top level tag (making it optional # [but recommended!] in the entitlement itself) # # XXX This synthetic wrapping should probably be made obsolete; everyone # should use emitEntitlement, which does the right thing. try: if '<entitlement>' not in xmlContent: p.parse("<entitlement>" + xmlContent + "</entitlement>") else: p.parse(xmlContent) try: entClass = p.get('class', None) entKey = p['key'] except KeyError: raise errors.ConaryError("Entitlement incomplete. Entitlements" " must include 'server', 'class', and" " 'key' values") except Exception, err: raise errors.ConaryError("Malformed entitlement at %s:" " %s" % (source, err))
def createSearchSourceStackFromStrings(searchSource, searchPath, flavor, db=None, fallBackToRepos=True): """ Create a search source stack from a list of search path elements. See L{createSearchPathFromStrings} for the elements allowed. """ try: strings = searchPath searchPath = createSearchPathFromStrings(searchPath) return createSearchSourceStack(searchSource, searchPath, flavor, db, fallBackToRepos=fallBackToRepos) except baseerrors.ConaryError, err: raise baseerrors.ConaryError('Could not create search path "%s": %s' % (' '.join(strings), err))
def doModelUpdate(cfg, sysmodel, modelFile, otherArgs, **kwargs): kwargs['systemModel'] = sysmodel kwargs['systemModelFile'] = modelFile kwargs['loadTroveCache'] = True kwargs.setdefault('updateByDefault', True) # erase is not default case kwargs.setdefault('model', False) kwargs.setdefault('keepExisting', True) # prefer "install" to "update" restartInfo = kwargs.get('restartInfo', None) patchArgs = kwargs.pop('patchSpec', None) fromChangesets = [] applyList = [] callback = kwargs.get('callback', None) if not callback: callback = callbacks.UpdateCallback(trustThreshold=cfg.trustThreshold) kwargs['callback'] = callback else: callback.setTrustThreshold(cfg.trustThreshold) if restartInfo is None: addArgs = [x[1:] for x in otherArgs if x.startswith('+')] rmArgs = [x[1:] for x in otherArgs if x.startswith('-')] defArgs = [x for x in otherArgs if not (x.startswith('+') or x.startswith('-'))] # find any default arguments that represent changesets to # install/update for defArg in list(defArgs): if kwargs['updateByDefault'] and os.path.isfile(defArg): try: cs = changeset.ChangeSetFromFile(defArg) fromChangesets.append((cs, defArg)) defArgs.remove(defArg) except filecontainer.BadContainer: # not a changeset, must be a trove name pass if kwargs['updateByDefault']: addArgs += defArgs else: rmArgs += defArgs if rmArgs: sysmodel.appendOpByName('erase', text=rmArgs) updateName = { False: 'update', True: 'install' }[kwargs['keepExisting']] branchArgs = {} for index, spec in enumerate(addArgs): try: troveSpec = trovetup.TroveSpec(spec) version = versions.Label(troveSpec.version) branchArgs[troveSpec] = index except: # Any exception is a parse failure in one of the # two steps, and so we do not convert that argument pass if branchArgs: client = conaryclient.ConaryClient(cfg) repos = client.getRepos() foundTroves = repos.findTroves(cfg.installLabelPath, branchArgs.keys(), defaultFlavor = cfg.flavor) for troveSpec in foundTroves: index = branchArgs[troveSpec] foundTrove = foundTroves[troveSpec][0] addArgs[index] = addArgs[index].replace( troveSpec.version, '%s/%s' %(foundTrove[1].trailingLabel(), foundTrove[1].trailingRevision())) disallowedChangesets = [] for cs, argName in fromChangesets: for troveTuple in cs.getPrimaryTroveList(): # group and redirect changesets will break the model the # next time it is run, so prevent them from getting in # the model in the first place if troveTuple[1].isOnLocalHost(): if troveTuple[0].startswith('group-'): disallowedChangesets.append((argName, 'group', trovetup.TroveTuple(*troveTuple).asString())) continue trvCs = cs.getNewTroveVersion(*troveTuple) if trvCs.getType() == trove.TROVE_TYPE_REDIRECT: disallowedChangesets.append((argName, 'redirect', trovetup.TroveTuple(*troveTuple).asString())) continue addArgs.append( trovetup.TroveTuple(*troveTuple).asString()) if disallowedChangesets: raise errors.ConaryError( 'group and redirect changesets on a local label' ' cannot be installed:\n ' + '\n '.join( '%s contains local %s: %s' % x for x in disallowedChangesets)) if addArgs: sysmodel.appendOpByName(updateName, text=addArgs) if patchArgs: sysmodel.appendOpByName('patch', text=patchArgs) kwargs['fromChangesets'] = [x[0] for x in fromChangesets] if kwargs.pop('model'): sysmodel.write(sys.stdout) sys.stdout.flush() return None keepExisting = kwargs.get('keepExisting') updateByDefault = kwargs.get('updateByDefault', True) applyList = cmdline.parseChangeList([], keepExisting, updateByDefault, allowChangeSets=True) else: # In the restart case, applyList == [] which says "sync to model" pass _updateTroves(cfg, applyList, **kwargs) # Clean up after ourselves if restartInfo: util.rmtree(restartInfo, ignore_errors=True)
def loadEntitlementFromProgram(fullPath, serverName): """ Executes the given file to generate an entitlement. The executable must print to stdout a full valid entitlement xml blob. """ readFd, writeFd = os.pipe() stdErrRead, stdErrWrite = os.pipe() childPid = os.fork() if not childPid: nullFd = os.open("/dev/null", os.O_RDONLY) try: try: os.close(readFd) # switch stdin to /dev/null os.dup2(nullFd, 0) os.close(nullFd) # both error and stderr are redirected - the entitlement # should be on stdout, and error info should be # on stderr. os.dup2(writeFd, 1) os.dup2(stdErrWrite, 2) os.close(writeFd) os.close(stdErrWrite) util.massCloseFileDescriptors(3, 252) os.execl(fullPath, fullPath, serverName) except Exception: traceback.print_exc(sys.stderr) finally: os._exit(1) os.close(writeFd) os.close(stdErrWrite) # read in from pipes. When they're closed, # the child process should have exited. output = [] errorOutput = [] buf = os.read(readFd, 1024) errBuf = os.read(stdErrRead, 1024) while buf or errBuf: if buf: output.append(buf) buf = os.read(readFd, 1024) if errBuf: errorOutput.append(errBuf) errBuf = os.read(stdErrRead, 1024) pid, status = os.waitpid(childPid, 0) os.close(readFd) os.close(stdErrRead) errMsg = '' if os.WIFEXITED(status) and os.WEXITSTATUS(status): errMsg = ('Entitlement generator at "%s"' ' died with exit status %d' % (fullPath, os.WEXITSTATUS(status))) elif os.WIFSIGNALED(status): errMsg = ('Entitlement generator at "%s"' ' died with signal %d' % (fullPath, os.WTERMSIG(status))) else: errMsg = '' if errMsg: if errorOutput: errMsg += ' - stderr output follows:\n%s' % ''.join(errorOutput) else: errMsg += ' - no output on stderr' raise errors.ConaryError(errMsg) # looks like we generated an entitlement - they're still the possibility # that the entitlement is broken. xmlContent = ''.join(output) return loadEntitlementFromString(xmlContent, fullPath)