def ConaryStateFromFile(self, path, repos=None, parseSource=True): if self.stateFileVersion() == 0: return state.ConaryStateFromFile(path) else: # support added in 1.0.31 and 1.1.4 return state.ConaryStateFromFile(path, repos=repos, parseSource=parseSource)
def testUpdateRecipes(self): self.logFilter.add() log.setVerbosity(log.INFO) simpleRecipe = recipes.simpleRecipe os.chdir(self.workDir) self.newpkg('simple') os.chdir('simple') self.writeFile('simple.recipe', simpleRecipe) self.addfile('simple.recipe') self.writeFile('foo', 'bar\n') self.buildCfg.configLine('[foo]') self.buildCfg.configLine('[bar]') conaryStateFile = state.ConaryStateFromFile(os.getcwd() + '/CONARY') conaryStateFile.setContext('foo') conaryStateFile.write(os.getcwd() + '/CONARY') # here we pretend we've done an rmake commit of the same job. repos = self.openRepository() trv = self.addComponent('simple:source', '1.0', [('simple.recipe', simpleRecipe)]) commit.updateRecipes(repos, self.buildCfg, [os.getcwd() + '/simple.recipe'], [trv.getNameVersionFlavor()]) assert (os.path.exists('foo')) conaryStateFile = state.ConaryStateFromFile(os.getcwd() + '/CONARY') stateFile = conaryStateFile.getSourceState() assert (stateFile.getVersion() == trv.getVersion()) assert (conaryStateFile.getContext() == 'foo') conaryStateFile.setContext('bar') conaryStateFile.write(os.getcwd() + '/CONARY') assert (checkin.diff(repos) == 0) trv = self.addComponent( 'simple:source', '2.0', [('simple.recipe', simpleRecipe + '\n\t#change\n')]) assert (checkin.diff(repos) == 0) commit.updateRecipes(repos, self.buildCfg, [os.getcwd() + '/simple.recipe'], [trv.getNameVersionFlavor()]) assert (checkin.diff(repos) == 0) assert (os.path.exists('foo')) conaryStateFile = state.ConaryStateFromFile(os.getcwd() + '/CONARY') stateFile = conaryStateFile.getSourceState() assert (stateFile.getVersion() == trv.getVersion()) assert (conaryStateFile.getContext() == 'bar') self.logFilter.compare([ '+ Replacing CONARY file %s/simple after initial commit' % self.workDir, '+ Updating %s/simple after commit' % self.workDir, '+ patching %s/simple/simple.recipe' % self.workDir, '+ patch: applying hunk 1 of 1' ])
def setContext(cfg, context=None, environ=None, searchCurrentDir=False): if environ is None: environ = os.environ if context is not None: where = 'given manually' else: context = cfg.context where = 'specified as the default context in the conary configuration' if searchCurrentDir: try: conaryState = state.ConaryStateFromFile('CONARY', parseSource=False) if conaryState.hasContext(): context = conaryState.getContext() where = 'specified in the CONARY state file' except state.CONARYFileMissing: pass if 'CONARY_CONTEXT' in environ: context = environ['CONARY_CONTEXT'] where = 'specified in the CONARY_CONTEXT environment variable' if context: if not cfg.getContext(context): raise cfgtypes.CfgError('context "%s" (%s) does not exist' % (context, where)) cfg.setContext(context) return cfg
def _getLocalCook(conaryclient, cfg, recipePath, message): if not hasattr(cook, 'getRecipeInfoFromPath'): raise errors.RmakeError('Local cooks require at least conary 1.0.19') recipeDir = os.path.dirname(recipePath) # We do not want to sign commits to the local repository, doing so # would require that we manage keys in this repository as well. oldKey = cfg.signatureKey oldMap = cfg.signatureKeyMap oldInteractive = cfg.interactive oldWorkDir = os.getcwd() try: cfg.signatureKey = None cfg.signatureKeyMap = {} cfg.interactive = False if os.access(recipeDir + '/CONARY', os.R_OK): os.chdir(recipeDir) stateFile = state.ConaryStateFromFile(recipeDir + '/CONARY') if stateFile.hasSourceState(): stateFile = stateFile.getSourceState() if stateFile.getVersion() != versions.NewVersion(): return _shadowAndCommit(conaryclient, cfg, recipeDir, stateFile, message) else: return _commitRecipe(conaryclient, cfg, recipePath, message, branch=stateFile.getBranch()) return _commitRecipe(conaryclient, cfg, recipePath, message) finally: cfg.signatureKey = oldKey cfg.signatureKeyMap = oldMap cfg.interactive = oldInteractive os.chdir(oldWorkDir)
def testCrossMerge(self): self.addComponent('test:source', '/localhost@rpl:r1//a/1.0-1', fileContents=[('test.recipe', simpleRecipe)]) self.addComponent('test:source', '/localhost@rpl:r2//a/2.0-1', fileContents=[('test.recipe', simpleRecipe2)]) self.addComponent('test:source', '/localhost@rpl:r1//a//b/1.0-1', fileContents=[('test.recipe', simpleRecipe)]) os.chdir(self.workDir) self.checkout('test=localhost@rpl:b') os.chdir('test') self.logCheck2([ '+ Merging from /localhost@rpl:r1//a onto new shadow ' '/localhost@rpl:r2//a', '+ patching %s/test/test.recipe' % self.workDir, '+ patch: applying hunk 1 of 1' ], self.merge, verbosity=log.INFO) self.verifyFile('test.recipe', simpleRecipe2) self.commit() trvState = state.ConaryStateFromFile('CONARY') assert (str(trvState.getSourceState().getVersion()) == '/localhost@rpl:r2//a//b/2.0-1.0.1') self.addComponent('test:source', '/localhost@rpl:r1//a/3.0-1', fileContents=[('test.recipe', simpleRecipe3)]) self.logCheck2([ '+ Merging from /localhost@rpl:r2//a onto /localhost@rpl:r1//a', '+ patching %s/test/test.recipe' % self.workDir, '+ patch: applying hunk 1 of 1' ], self.merge, verbosity=log.INFO) self.verifyFile('test.recipe', simpleRecipe3) self.commit() trvState = state.ConaryStateFromFile('CONARY') assert (str(trvState.getSourceState().getVersion()) == '/localhost@rpl:r1//a//b/3.0-1.0.1')
def _getRepositoryStateFromDirectory(self, targetDir): ''' Create repository and state objects for working with a checkout @param targetDir: directory containing Conary checkout ''' repos = self._getRepositoryClient() conaryState = state.ConaryStateFromFile(targetDir + '/CONARY', repos) sourceState = conaryState.getSourceState() return repos, sourceState
def updateRecipes(repos, cfg, recipeList, committedSources): committedSourcesByNB = {} for name, version, flavor in committedSources: committedSourcesByNB[name, version.branch()] = version for recipe in recipeList: recipeDir = os.path.dirname(recipe) stateFilePath = recipeDir + '/CONARY' if not os.path.exists(stateFilePath): continue conaryStateFile = state.ConaryStateFromFile(stateFilePath) if not conaryStateFile.hasSourceState(): continue context = conaryStateFile.getContext() stateFile = conaryStateFile.getSourceState() troveName = stateFile.getName() branch = stateFile.getBranch() if (troveName, branch) not in committedSourcesByNB: continue stateVersion = stateFile.getVersion() newVersion = committedSourcesByNB[troveName, branch] if stateVersion != versions.NewVersion(): log.info('Updating %s after commit' % recipeDir) if compat.ConaryVersion().updateSrcTakesMultipleVersions(): try: # Added in CNY-3035 checkin.nologUpdateSrc(repos, [recipeDir]) except checkin.builderrors.UpToDate: pass # Don't mention if the source is already up to date except checkin.builderrors.CheckinError, e: e.logError() except AttributeError: checkin.updateSrc(repos, [recipeDir]) else: curDir = os.getcwd() try: os.chdir(recipeDir) checkin.updateSrc(repos) finally: os.chdir(curDir)
def _removeNonRecipeFilesFromCheckout(self, recipePath): recipeDir = os.path.dirname(recipePath) recipeName = os.path.basename(recipePath) repos = self._getRepositoryClient() statePath = os.path.join(recipeDir, 'CONARY') conaryState = state.ConaryStateFromFile(statePath, repos) sourceState = conaryState.getSourceState() for (pathId, path, _, _) in list(sourceState.iterFileList()): if path == recipeName: continue path = os.path.join(recipeDir, path) sourceState.removeFile(pathId) if util.exists(path): statInfo = os.lstat(path) try: if statInfo.st_mode & stat.S_IFDIR: os.rmdir(path) else: os.unlink(path) except OSError, e: self._handle.ui.warning("cannot remove %s: %s", path, e.strerror)
def testUpdateRecipesAddFile(self): simpleRecipe = recipes.simpleRecipe repos = self.openRepository() trv = self.addComponent('simple:source', '1.0', [('simple.recipe', simpleRecipe), ('bam', 'bam\n')]) os.chdir(self.workDir) self.checkout('simple') os.chdir('simple') self.writeFile('foo', 'bar\n') self.addfile('foo', text=True) self.writeFile('bar', 'bar\n') self.addfile('bar', binary=True) self.remove('bam') trv = self.addComponent('simple:source', '2.0', [('simple.recipe', simpleRecipe), ('foo', 'bar\n'), ('bar', 'bar\n')]) commit.updateRecipes(repos, self.buildCfg, [os.getcwd() + '/simple.recipe'], [trv.getNameVersionFlavor()]) conaryStateFile = state.ConaryStateFromFile(os.getcwd() + '/CONARY') stateFile = conaryStateFile.getSourceState() assert (stateFile.getVersion() == trv.getVersion())
checkin.nologUpdateSrc(repos, [recipeDir]) except checkin.builderrors.UpToDate: pass # Don't mention if the source is already up to date except checkin.builderrors.CheckinError, e: e.logError() except AttributeError: checkin.updateSrc(repos, [recipeDir]) else: curDir = os.getcwd() try: os.chdir(recipeDir) checkin.updateSrc(repos) finally: os.chdir(curDir) else: log.info('Replacing CONARY file %s after initial commit' % recipeDir) d = tempfile.mkdtemp(dir='/var/tmp', prefix='rmake-update-%s' % troveName) # check out the newly committed version of this recipe # (too much work, since we only want the CONARY file not # the file contents. Oh well.) and update the CONARY state # file to it. This will not lose any local changes made after # the build started but _will_ cause any added/removed files # to need to be readded/removed via cvc add/remove checkin.checkout(repos, cfg, d, ['%s=%s' % (troveName, newVersion)]) newConaryStateFile = state.ConaryStateFromFile(d + '/CONARY') newConaryStateFile.setContext(context) newConaryStateFile.write(stateFilePath)
def runCommand(self, cfg, argSet, args, profile=False, callback=None, repos=None): args = args[1:] level = log.getVerbosity() macros = {} prep = 0 downloadOnly = False resume = None if argSet.has_key('flavor'): buildFlavor = deps.deps.parseFlavor(argSet['flavor'], raiseError=True) cfg.buildFlavor = deps.deps.overrideFlavor(cfg.buildFlavor, buildFlavor) del argSet['flavor'] if argSet.has_key('macros'): f = open(argSet['macros']) for row in f: row = row.strip() if not row or row[0] == '#': continue cfg.configLine('macros ' + row.strip()) f.close() del f del argSet['macros'] if argSet.has_key('macro'): for macro in argSet['macro']: cfg.configLine('macros ' + macro) del argSet['macro'] if argSet.has_key('prep'): del argSet['prep'] prep = 1 if argSet.has_key('ignore-buildreqs'): del argSet['ignore-buildreqs'] ignoreDeps = True elif argSet.has_key('no-deps'): del argSet['no-deps'] ignoreDeps = True else: ignoreDeps = False if argSet.has_key('download'): if argSet.has_key('prep') or prep == True: log.warn( 'download and prep should not be used together... prefering download only' ) del argSet['download'] ignoreDeps = True downloadOnly = True showBuildReqs = argSet.pop('show-buildreqs', False) if argSet.has_key('quiet'): cfg.quiet = True del argSet['quiet'] if 'no-clean' in argSet: cfg.cleanAfterCook = False del argSet['no-clean'] allowFlavorChange = argSet.pop('allow-flavor-change', False) if argSet.has_key('resume'): resume = argSet['resume'] del argSet['resume'] if argSet.has_key('unknown-flags'): unknownFlags = argSet['unknown-flags'] del argSet['unknown-flags'] else: unknownFlags = False if argSet.has_key('debug-exceptions'): del argSet['debug-exceptions'] cfg.debugRecipeExceptions = True crossCompile = argSet.pop('cross', None) if crossCompile: parts = crossCompile.split('--') isCrossTool = False if len(parts) == 1: crossTarget = crossCompile crossHost = None else: crossHost, crossTarget = parts if crossHost == 'local': crossHost = None isCrossTool = True crossCompile = (crossHost, crossTarget, isCrossTool) targetFile = argSet.pop("to-file", None) if argSet: return self.usage() groupOptions = cook.GroupCookOptions( alwaysBumpCount=True, errorOnFlavorChange=not allowFlavorChange, shortenFlavors=cfg.shortenGroupFlavors) # the remainder of the argument list are the things to build. # e.g., foo /path/to/bar.recipe, etc. items = args[1:] if not items: # if nothing was specified, try to build the package in the current # directory if os.path.isfile('CONARY'): conaryState = state.ConaryStateFromFile('CONARY', repos) items = [conaryState] if not items: # if we still don't have anything to build, throw a usage # message return self.usage() try: cook.cookCommand( cfg, items, prep, macros, resume=resume, allowUnknownFlags=unknownFlags, ignoreDeps=ignoreDeps, showBuildReqs=showBuildReqs, profile=profile, crossCompile=crossCompile, downloadOnly=downloadOnly, groupOptions=groupOptions, changeSetFile=targetFile, ) except builderrors.GroupFlavorChangedError, err: err.args = ( err.args[0] + '\n(Add the --allow-flavor-change flag to override this error)\n', ) raise
def derive(repos, cfg, targetLabel, troveSpec, checkoutDir=None, extract=False, info=False, callback=None): """ Performs all the commands necessary to create a derived recipe. First it shadows the package, then it creates a checkout of the shadow and converts the checkout to a derived recipe package. Finally if extract = True, it installs an version of the binary package into a root. @param repos: trovesource to search for and derive packages from @param cfg: configuration to use when deriving the package @type cfg: ConaryConfiguration object @param targetLabel: label to derive from @type targetLabel: versions.Label @param checkoutDir: directory to create the checkout in. If None, defaults to currentDir + packageName. @param extract: If True, creates a subdirectory of the checkout named _ROOT_ with the contents of the binary of the derived package. @param info: If true, only display the information about the shadow that would be performed if the derive command were completed. @param callback: """ origDir = os.getcwd() try: if callback is None: callback = DeriveCallback() if isinstance(troveSpec, tuple): troveName, versionSpec, flavor = troveSpec versionSpec = str(versionSpec) troveSpec = cmdline.toTroveSpec(troveName, versionSpec, flavor) else: troveName, versionSpec, flavor = cmdline.parseTroveSpec(troveSpec) if isinstance(targetLabel, str): targetLabel = Label(targetLabel) troveName, versionSpec, flavor = cmdline.parseTroveSpec(troveSpec) result = repos.findTrove(cfg.buildLabel, (troveName, versionSpec, flavor), cfg.flavor) # findTrove shouldn't return multiple items for one package anymore # when a flavor is specified. troveToDerive, = result # displaying output along the screen allows there to be a record # of what operations were performed. Since this command is # an aggregate of several commands I think that is appropriate, # rather than simply using a progress callback. log.info('Shadowing %s=%s[%s] onto %s' % (troveToDerive[0], troveToDerive[1], troveToDerive[2], targetLabel)) if info: cfg.interactive = False error = branch.branch(repos, cfg, str(targetLabel), ['%s=%s[%s]' % troveToDerive], makeShadow=True, sourceOnly=True, binaryOnly=False, allowEmptyShadow=True, info=info) if info or error: return shadowedVersion = troveToDerive[1].createShadow(targetLabel) shadowedVersion = shadowedVersion.getSourceVersion(False) troveName = troveName.split(':')[0] checkoutDir = checkoutDir or troveName checkin.checkout(repos, cfg, checkoutDir, ["%s=%s" % (troveName, shadowedVersion)], callback=callback) os.chdir(checkoutDir) nvfs = repos.getTrovesBySource(troveToDerive[0] + ':source', troveToDerive[1].getSourceVersion()) trvs = repos.getTroves(nvfs) hasCapsule = [x for x in trvs if x.troveInfo.capsule.type()] if hasCapsule: derivedRecipeType = 'DerivedCapsuleRecipe' removeText = '' else: derivedRecipeType = 'DerivedPackageRecipe' removeText = \ """ # This appliance uses PHP as a command interpreter but does # not include a web server, so remove the file that creates # a dependency on the web server r.Remove('/etc/httpd/conf.d/php.conf') """ log.info('Rewriting recipe file') recipeName = troveName + '.recipe' className = util.convertPackageNameToClassName(troveName) derivedRecipe = """ class %(className)sRecipe(%(recipeBaseClass)s): name = '%(name)s' version = '%(version)s' def setup(r): ''' In this recipe, you can make modifications to the package. Examples: # This appliance has high-memory-use PHP scripts r.Replace('memory_limit = 8M', 'memory_limit = 32M', '/etc/php.ini') %(removeText)s # This appliance requires that a few binaries be replaced # with binaries built from a custom archive that includes # a Makefile that honors the DESTDIR variable for its # install target. r.addArchive('foo.tar.gz') r.Make() r.MakeInstall() # This appliance requires an extra configuration file r.Create('/etc/myconfigfile', contents='some data') ''' """ % dict(className=className, name=troveName, version=shadowedVersion.trailingRevision().getVersion(), recipeBaseClass=derivedRecipeType, removeText=removeText) open(recipeName, 'w').write(derivedRecipe) log.info('Removing extra files from checkout') conaryState = state.ConaryStateFromFile('CONARY', repos) sourceState = conaryState.getSourceState() # clear the factory since we don't care about how the parent trove was # created sourceState.setFactory('') addRecipe = True for (pathId, path, fileId, version) in list(sourceState.iterFileList()): if path == recipeName: addRecipe = False continue sourceState.removeFile(pathId) if util.exists(path): statInfo = os.lstat(path) try: if statInfo.st_mode & stat.S_IFDIR: os.rmdir(path) else: os.unlink(path) except OSError, e: log.warning("cannot remove %s: %s" % (path, e.strerror)) conaryState.write('CONARY') if addRecipe: checkin.addFiles([recipeName]) if extract: log.info('extracting files from %s=%s[%s]' % (troveToDerive)) # extract to _ROOT_ extractDir = os.path.join(os.getcwd(), '_ROOT_') ts = [(troveToDerive[0], (None, None), (troveToDerive[1], troveToDerive[2]), True)] cs = repos.createChangeSet(ts, recurse=True) ChangesetExploder(cs, extractDir) # extract to _OLD_ROOT_ secondDir = os.path.join(os.getcwd(), '_OLD_ROOT_') cs = repos.createChangeSet(ts, recurse=True) ChangesetExploder(cs, secondDir)
def getNameForCheckout(checkoutDir): conaryState = state.ConaryStateFromFile(checkoutDir + '/CONARY') return conaryState.getSourceState().getName().split(':', 1)[0]
def _commitRecipe(conaryclient, cfg, recipePath, message, branch=None): repos = conaryclient.getRepos() conaryCompat = compat.ConaryVersion() recipeClass, pathList = _getPathList(repos, cfg, recipePath) sourceName = recipeClass.name + ':source' log.info("Creating a copy of %s in the rMake internal repository..." % recipeClass.name) cwd = os.getcwd() recipeDir = tempfile.mkdtemp() log.resetErrorOccurred() try: fileNames = [] # Create a source trove that matches the recipe we're trying to cook if not branch: branch = versions.Branch([cfg.buildLabel]) targetLabel = cfg.getTargetLabel(branch) if compat.ConaryVersion().supportsNewPkgBranch(): buildBranch = branch.createShadow(targetLabel) kw = dict(buildBranch=buildBranch) else: buildBranch = versions.Branch([targetLabel]) kw={} cfg.buildLabel = targetLabel if not repos.getTroveLeavesByBranch( { sourceName : { buildBranch : None } }).get(sourceName, None): # we pass it None for repos to avoid the label-based check for # existing packages. checkin.newTrove(None, cfg, recipeClass.name, dir=recipeDir, **kw) else: # see if this package exists on our build branch checkin.checkout(repos, cfg, recipeDir, ['%s=%s' % (sourceName, buildBranch)]) os.chdir(recipeDir) sourceState = state.ConaryStateFromFile(recipeDir + '/CONARY').getSourceState() fileNames = dict((os.path.basename(x), x) for x in pathList) for (pathId, baseName, fileId, version) in list(sourceState.iterFileList()): # update or remove any currently existing files if baseName not in fileNames: sourceState.removeFilePath(baseName) else: shutil.copyfile(fileNames[baseName], os.path.join(recipeDir, baseName)) del fileNames[baseName] for baseName, path in fileNames.iteritems(): shutil.copyfile(path, os.path.join(recipeDir, baseName)) if conaryCompat.stateFileVersion() > 0: # mark all the files as binary - this this version can # never be checked in, it doesn't really matter, but # conary likes us to give a value. for fileName in fileNames: isConfig = _getConfigInfo(fileName) checkin.addFiles([fileName], binary=not isConfig, text=isConfig) else: checkin.addFiles(fileNames) _doCommit(recipePath, repos, cfg, 'Temporary recipe build for rmake') newState = conaryCompat.ConaryStateFromFile(recipeDir + '/CONARY', repos=repos) return newState.getSourceState().getNameVersionFlavor() finally: os.chdir(cwd) shutil.rmtree(recipeDir)
def _shadowAndCommit(conaryclient, cfg, recipeDir, stateFile, message): repos = conaryclient.getRepos() conaryCompat = compat.ConaryVersion() oldSourceVersion = stateFile.getVersion() targetLabel = cfg.getTargetLabel(oldSourceVersion) if not targetLabel: raise errors.RmakeError( 'Cannot cook local recipes unless a target label is set') skipped, cs = conaryclient.createShadowChangeSet(str(targetLabel), [stateFile.getNameVersionFlavor()]) recipePath = recipeDir + '/' + stateFile.getName().split(':')[0] + '.recipe' recipeClass, pathList = _getPathList(repos, cfg, recipePath, relative=True) troveName = stateFile.getName() troveVersion = stateFile.getVersion() if not skipped: signAbsoluteChangeset(cs, None) repos.commitChangeSet(cs) log.info("Shadowing %s to internal repository..." % troveName) shadowBranch = troveVersion.createShadow(targetLabel).branch() shadowVersion = repos.findTrove(None, (troveName, str(shadowBranch), None), None)[0][1] cwd = os.getcwd() prefix = 'rmake-shadow-%s-' % troveName.split(':')[0] shadowSourceDir = tempfile.mkdtemp(prefix=prefix) try: log.info("Committing local changes to %s to the" " internal repository..." % troveName) log.resetErrorOccurred() checkin.checkout(repos, cfg, shadowSourceDir, ['%s=%s' % (troveName, shadowVersion)]) if compat.ConaryVersion().stateFileVersion() > 0: kw = dict(repos=repos) else: kw = {} # grab new and old state and make any modifications due to adding # or deleting of files (we assume files that don't exist are # autosource and can be ignored) oldState = conaryCompat.ConaryStateFromFile(recipeDir + '/CONARY', repos=repos).getSourceState() newConaryState = conaryCompat.ConaryStateFromFile( shadowSourceDir + '/CONARY', repos=repos) newState = newConaryState.getSourceState() neededFiles = set(x[1] for x in oldState.iterFileList() if os.path.exists(os.path.join(recipeDir, x[1]))) neededFiles.update(pathList) autoSourceFiles = set(x[1] for x in oldState.iterFileList() if oldState.fileIsAutoSource(x[0])) existingFiles = set(x[1] for x in newState.iterFileList() if os.path.exists(os.path.join(shadowSourceDir, x[1]))) toCopy = neededFiles & existingFiles toDel = existingFiles - neededFiles toAdd = neededFiles - existingFiles for sourceFile in (toCopy | toAdd): newPath = os.path.join(shadowSourceDir, sourceFile) if os.path.dirname(sourceFile): util.mkdirChain(os.path.dirname(newPath)) if os.path.isdir(sourceFile): util.mkdirChain(newPath) else: shutil.copyfile(os.path.join(recipeDir, sourceFile), newPath) os.chdir(shadowSourceDir) if hasattr(cfg.sourceSearchDir, '_getUnexpanded'): cfg.configKey('sourceSearchDir', cfg.sourceSearchDir._getUnexpanded()) for f in toDel: checkin.removeFile(f) if toDel: # toDel modifies the CONARY file on disk, so reload with the # changes made there. newState = conaryCompat.ConaryStateFromFile( shadowSourceDir + '/CONARY', repos=repos).getSourceState() if conaryCompat.stateFileVersion() == 0: checkin.addFiles(toAdd) else: oldPathIds = dict((x[1], x[0]) for x in oldState.iterFileList()) for path in toAdd: if path in oldPathIds: isConfig = oldState.fileIsConfig(oldPathIds[path]) else: isConfig = _getConfigInfo(path) checkin.addFiles([path], binary=not isConfig, text=isConfig) if toAdd: # get the new pathIDs for all the added troves, # since we can't set the refresh setting without the # needed pathIds newState = conaryCompat.ConaryStateFromFile( shadowSourceDir + '/CONARY', repos=repos).getSourceState() newPathIds = dict((x[1], x[0]) for x in newState.iterFileList()) for path in (toCopy | toAdd): if path in oldPathIds: isConfig = oldState.fileIsConfig(oldPathIds[path]) else: isConfig = _getConfigInfo(path) newState.fileIsConfig(newPathIds[path], isConfig) for path in autoSourceFiles: if path in newPathIds: needsRefresh = oldState.fileNeedsRefresh(oldPathIds[path]) newState.fileNeedsRefresh(newPathIds[path], needsRefresh) # if the factory changed, update it if newState.getFactory() != oldState.getFactory(): newState.setFactory(oldState.getFactory()) # we may have modified the state file. Write it back out to # disk so it will be picked up by the commit. newConaryState.setSourceState(newState) newConaryState.write(shadowSourceDir + '/CONARY') if message is None and compat.ConaryVersion().supportsCloneCallback(): message = 'Automated rMake commit' _doCommit('%s/%s' % (recipeDir, troveName), repos, cfg, message) newState = state.ConaryStateFromFile(shadowSourceDir + '/CONARY', **kw) return newState.getSourceState().getNameVersionFlavor() finally: os.chdir(cwd) if hasattr(cfg.sourceSearchDir, '_getUnexpanded'): cfg.configKey('sourceSearchDir', cfg.sourceSearchDir._getUnexpanded()) shutil.rmtree(shadowSourceDir)
def testCommitSource(self): repos = self.openRepository() # test signing the trove as well fingerprint = 'F7440D78FE813C882212C2BF8AC2828190B1E477' self._setupSignature(repos, fingerprint) self.openRmakeRepository() client = self.startRmakeServer() helper = self.getRmakeHelper(client.uri) trv = self.addComponent('simple:source', '1-1', '', [('simple.recipe', recipes.simpleRecipe)]) os.chdir(self.workDir) self.checkout('simple') self.writeFile('simple/simple.recipe', recipes.simpleRecipe + '\t#foo\n') jobId = self.discardOutput(helper.buildTroves, ['simple/simple.recipe']) # make a local change here while it's cooking os.chdir('simple') self.writeFile('simple.recipe', recipes.simpleRecipe + '\t#foo2\n') self.commit() helper.waitForJob(jobId) assert (client.getJob(jobId, withTroves=False).isBuilt()) troves = list(client.getJob(jobId).iterTroves()) assert (troves[0].getBinaryTroves()) self.logFilter.add() passed, txt = self.commitJob(helper, str(jobId)) assert (not passed) self.logFilter.compare([ 'error: The following source troves are out of date:\nsimple:source=/localhost@rpl:linux/1-1 (replaced by newer 1-2)\n\nUse --commit-outdated-sources to commit anyway' ]) self.logFilter.remove() passed, txt = self.commitJob(helper, str(jobId), commitOutdatedSources=True) assert (passed) assert (txt == """ Committed job 1: simple:source=/localhost@rpl:linux//rmakehost@local:linux/1-1.1[%s] -> simple=/localhost@rpl:linux/1-3-1[] simple:source=/localhost@rpl:linux/1-3[] """ % self.getArchFlavor()) results = repos.findTrove(self.cfg.installLabelPath, ('simple', None, None), self.cfg.flavor) assert (results) # check to make sure the trove and its source were both signed t = repos.getTrove(*results[0]) signature = t.getDigitalSignature(fingerprint) signature = signature.getSignatures().signatures.iter().next() assert (signature[0] == fingerprint) # check to make sure the clonedFrom setting is not set. #if compat.ConaryVersion().supportsCloneNoTracking(): # assert(not t.troveInfo.clonedFrom()) results = repos.findTrove(self.cfg.installLabelPath, ('simple:source', None, None), self.cfg.flavor) assert (results) t = repos.getTrove(*results[0]) signature = t.getDigitalSignature(fingerprint) signature = signature.getSignatures().signatures.iter().next() assert (signature[0] == fingerprint) assert (str( state.ConaryStateFromFile(self.workDir + '/simple/CONARY'). getSourceState().getVersion().trailingRevision()) == '1-3')