def _makeSourceTrove(package, helper): cs = ChangeSet() filesToAdd = {} ver = macro.expand(package.getBaseVersion(), package) version = _createVersion(package, helper, ver) latestSpec = (package.getName(), str(version.trailingLabel()), None) results = helper.getRepos().findTroves(None,[latestSpec],allowMissing=True, getLeaves=False,troveTypes=trovesource.TROVE_QUERY_ALL) if results: existingVersions = [x[1] for x in results.get(latestSpec, ())] while version in existingVersions: version.incrementSourceCount() new = Trove(package.name, version, deps.Flavor()) new.setFactory(package.targetConfig.factory) message = "Temporary Source for %s" % version message = message.rstrip() + "\n" new.changeChangeLog(ChangeLog(name=helper.cfg.name, contact=helper.cfg.contact, message=message)) for path, contents in package.recipeFiles.iteritems(): isText = path == package.getRecipeName() pathId = hashlib.md5(path).digest() fileHelper = filetypes.RegularFile(contents=contents, config=isText) fileStream = fileHelper.get(pathId) fileStream.flags.isSource(set=True) fileId = fileStream.fileId() fileVersion = new.getVersion() key = pathId + fileId filesToAdd[key] = (fileStream, fileHelper.contents, isText) new.addFile(pathId, path, fileVersion, fileId) new.invalidateDigests() new.computeDigests() for key, (fileObj, fileContents, cfgFile) in filesToAdd.items(): cs.addFileContents(fileObj.pathId(), fileObj.fileId(), ChangedFileTypes.file, fileContents, cfgFile) cs.addFile(None, fileObj.fileId(), fileObj.freeze()) cs.newTrove(new.diff(None, absolute=True)[0]) return new.getNameVersionFlavor(), cs
def _merge(self): changeSet = ChangeSet() deleteDirs = set() doCommit = False # If this is not None then all ephemeral sources will still be fetched # but will be placed in this directory instead. if self.helper.plan.ephemeralSourceDir: ephDir = self.helper.makeEphemeralDir() else: ephDir = None def _addFile(path, contents, isText): if path in oldFiles: # Always recycle pathId if available. pathId, _, oldFileId, oldFileVersion = oldFiles[path] else: pathId = hashlib.md5(path).digest() oldFileId = oldFileVersion = None fileHelper = filetypes.RegularFile(contents=contents, config=isText) fileStream = fileHelper.get(pathId) fileStream.flags.isSource(set=True) fileId = fileStream.fileId() # If the fileId matches, recycle the fileVersion too. if fileId == oldFileId: fileVersion = oldFileVersion else: fileVersion = newTrove.getVersion() filesToAdd[fileId] = (fileStream, fileHelper.contents, isText) newTrove.addFile(pathId, path, fileVersion, fileId) for package, (recipeText, recipeObj), oldTrove in zip( self.packages, self.recipes, self.oldTroves): filesToAdd = {} oldFiles = {} if oldTrove is not None: for pathId, path, fileId, fileVer in oldTrove.iterFileList(): oldFiles[path] = (pathId, path, fileId, fileVer) newTrove = Trove(package.name, package.nextVersion, deps.Flavor()) newTrove.setFactory(package.targetConfig.factory) # Add upstream files to new trove. Recycle pathids from the old # version. # LAZY: assume that everything other than the recipe is binary. # Conary has a magic module, but it only accepts filenames! for path, contents in package.recipeFiles.iteritems(): isText = path == package.getRecipeName() _addFile(path, contents, isText) # Collect requested auto sources from recipe. Unknown recipe types # will not be loaded so recipeObj will be the class, so assume # these have no sources. if not inspect.isclass(recipeObj): recipeFiles = dict((os.path.basename(x.getPath()), x) for x in recipeObj.getSourcePathList()) newFiles = set(x[1] for x in newTrove.iterFileList()) needFiles = set(recipeFiles) - newFiles for autoPath in needFiles: source = recipeFiles[autoPath] if getattr(source, 'contents', None ) and not source.sourcename: # Ignore trove scripts that have inline contents continue if not autoPath: log.error("bob does not support 'gussed' filenames; " "please use a full path for source '%s' in " "package %s", source.getPath(), package.name) raise RuntimeError("Unsupported source action") if (autoPath in oldFiles and not self.helper.plan.refreshSources and not source.ephemeral): # File exists in old version. pathId, path, fileId, fileVer = oldFiles[autoPath] newTrove.addFile(pathId, path, fileVer, fileId) continue if source.ephemeral and not ephDir: continue # File doesn't exist; need to create it. if source.ephemeral: laUrl = lookaside.laUrl(source.getPath()) tempDir = joinPaths(ephDir, os.path.dirname(laUrl.filePath())) mkdirChain(tempDir) else: tempDir = tempfile.mkdtemp() deleteDirs.add(tempDir) snapshot = _getSnapshot(self.helper, package, source, tempDir) if not source.ephemeral and snapshot: autoPathId = hashlib.md5(autoPath).digest() autoObj = FileFromFilesystem(snapshot, autoPathId) autoObj.flags.isAutoSource(set=True) autoObj.flags.isSource(set=True) autoFileId = autoObj.fileId() autoContents = filecontents.FromFilesystem(snapshot) filesToAdd[autoFileId] = (autoObj, autoContents, False) newTrove.addFile(autoPathId, autoPath, newTrove.getVersion(), autoFileId) # If the old and new troves are identical, just use the old one. if oldTrove and _sourcesIdentical( oldTrove, newTrove, [self.oldChangeSet, filesToAdd]): package.setDownstreamVersion(oldTrove.getVersion()) log.debug('Skipped %s=%s', oldTrove.getName(), oldTrove.getVersion()) continue # Add files and contents to changeset. for fileId, (fileObj, fileContents, cfgFile) in filesToAdd.items(): changeSet.addFileContents(fileObj.pathId(), fileObj.fileId(), ChangedFileTypes.file, fileContents, cfgFile) changeSet.addFile(None, fileObj.fileId(), fileObj.freeze()) # Create a changelog entry. changeLog = ChangeLog( name=self.helper.cfg.name, contact=self.helper.cfg.contact, message=self.helper.plan.commitMessage + '\n') newTrove.changeChangeLog(changeLog) # Calculate trove digests and add the trove to the changeset newTrove.invalidateDigests() newTrove.computeDigests() newTroveCs = newTrove.diff(None, absolute=True)[0] changeSet.newTrove(newTroveCs) doCommit = True package.setDownstreamVersion(newTrove.getVersion()) log.debug('Created %s=%s', newTrove.getName(), newTrove.getVersion()) if doCommit: cook.signAbsoluteChangesetByConfig(changeSet, self.helper.cfg) f = tempfile.NamedTemporaryFile(dir=os.getcwd(), suffix='.ccs', delete=False) f.close() changeSet.writeToFile(f.name) try: self.helper.getRepos().commitChangeSet(changeSet) except: log.error("Error committing changeset to repository, " "failed changeset is saved at %s", f.name) raise else: os.unlink(f.name) for path in deleteDirs: shutil.rmtree(path)
def _merge(self): changeSet = ChangeSet() deleteDirs = set() doCommit = False # If this is not None then all ephemeral sources will still be fetched # but will be placed in this directory instead. if self.helper.plan.ephemeralSourceDir: ephDir = self.helper.makeEphemeralDir() else: ephDir = None def _addFile(path, contents, isText): if path in oldFiles: # Always recycle pathId if available. pathId, _, oldFileId, oldFileVersion = oldFiles[path] else: pathId = hashlib.md5(path).digest() oldFileId = oldFileVersion = None fileHelper = filetypes.RegularFile(contents=contents, config=isText) fileStream = fileHelper.get(pathId) fileStream.flags.isSource(set=True) fileId = fileStream.fileId() # If the fileId matches, recycle the fileVersion too. if fileId == oldFileId: fileVersion = oldFileVersion else: fileVersion = newTrove.getVersion() filesToAdd[fileId] = (fileStream, fileHelper.contents, isText) newTrove.addFile(pathId, path, fileVersion, fileId) for package, (recipeText, recipeObj), oldTrove in zip( self.packages, self.recipes, self.oldTroves): filesToAdd = {} oldFiles = {} if oldTrove is not None: for pathId, path, fileId, fileVer in oldTrove.iterFileList(): oldFiles[path] = (pathId, path, fileId, fileVer) newTrove = Trove(package.name, package.nextVersion, deps.Flavor()) newTrove.setFactory(package.targetConfig.factory) # Add upstream files to new trove. Recycle pathids from the old # version. # LAZY: assume that everything other than the recipe is binary. # Conary has a magic module, but it only accepts filenames! for path, contents in package.recipeFiles.iteritems(): isText = path == package.getRecipeName() _addFile(path, contents, isText) # Collect requested auto sources from recipe. Unknown recipe types # will not be loaded so recipeObj will be the class, so assume # these have no sources. if not inspect.isclass(recipeObj): recipeFiles = dict((os.path.basename(x.getPath()), x) for x in recipeObj.getSourcePathList()) newFiles = set(x[1] for x in newTrove.iterFileList()) needFiles = set(recipeFiles) - newFiles for autoPath in needFiles: source = recipeFiles[autoPath] if (autoPath in oldFiles and not self.helper.plan.refreshSources and not source.ephemeral): # File exists in old version. pathId, path, fileId, fileVer = oldFiles[autoPath] newTrove.addFile(pathId, path, fileVer, fileId) continue if source.ephemeral and not ephDir: continue # File doesn't exist; need to create it. if source.ephemeral: laUrl = lookaside.laUrl(source.getPath()) tempDir = joinPaths(ephDir, os.path.dirname(laUrl.filePath())) mkdirChain(tempDir) else: tempDir = tempfile.mkdtemp() deleteDirs.add(tempDir) snapshot = _getSnapshot(self.helper, package, source, tempDir) if not source.ephemeral and snapshot: autoPathId = hashlib.md5(autoPath).digest() autoObj = FileFromFilesystem(snapshot, autoPathId) autoObj.flags.isAutoSource(set=True) autoObj.flags.isSource(set=True) autoFileId = autoObj.fileId() autoContents = filecontents.FromFilesystem(snapshot) filesToAdd[autoFileId] = (autoObj, autoContents, False) newTrove.addFile(autoPathId, autoPath, newTrove.getVersion(), autoFileId) # If the old and new troves are identical, just use the old one. if oldTrove and _sourcesIdentical( oldTrove, newTrove, [self.oldChangeSet, filesToAdd]): package.setDownstreamVersion(oldTrove.getVersion()) log.debug('Skipped %s=%s', oldTrove.getName(), oldTrove.getVersion()) continue # Add files and contents to changeset. for fileId, (fileObj, fileContents, cfgFile) in filesToAdd.items(): changeSet.addFileContents(fileObj.pathId(), fileObj.fileId(), ChangedFileTypes.file, fileContents, cfgFile) changeSet.addFile(None, fileObj.fileId(), fileObj.freeze()) # Create a changelog entry. changeLog = ChangeLog( name=self.helper.cfg.name, contact=self.helper.cfg.contact, message=self.helper.plan.commitMessage + '\n') newTrove.changeChangeLog(changeLog) # Calculate trove digests and add the trove to the changeset newTrove.invalidateDigests() newTrove.computeDigests() newTroveCs = newTrove.diff(None, absolute=True)[0] changeSet.newTrove(newTroveCs) doCommit = True package.setDownstreamVersion(newTrove.getVersion()) log.debug('Created %s=%s', newTrove.getName(), newTrove.getVersion()) if doCommit: cook.signAbsoluteChangesetByConfig(changeSet, self.helper.cfg) f = tempfile.NamedTemporaryFile(dir=os.getcwd(), suffix='.ccs', delete=False) f.close() changeSet.writeToFile(f.name) try: self.helper.getRepos().commitChangeSet(changeSet) except: log.error("Error committing changeset to repository, " "failed changeset is saved at %s", f.name) raise else: os.unlink(f.name) for path in deleteDirs: shutil.rmtree(path)