def testConvertPackageNameToClassName(self): data = {'foo': 'Foo', 'foobar': 'Foobar', 'foo-bar': 'FooBar'} for input, expectedOutput in data.iteritems(): self.assertEquals(util.convertPackageNameToClassName(input), expectedOutput)
def createProductVersion(self, fqdn, version, namespace, description, platformLabel): product = self.getProduct(fqdn) if not namespace: namespace = product.namespace projectId = product.productId # Check the namespace projects._validateNamespace(namespace) # make sure it is a valid product version projects._validateProductVersion(version) # initial product definition prodDef = helperfuncs.sanitizeProductDefinition(product.name, description, product.repositoryHostname, product.shortname, version, '', namespace) label = prodDef.getDefaultLabel() # validate the label, which will be added later. This is done # here so the project is not created before this error occurs if projects.validLabel.match(label) == None: raise mint_error.InvalidLabel(label) if platformLabel: cclient = self.reposMgr.getUserClient() prodDef.rebase(cclient, platformLabel) self.setProductVersionDefinition(fqdn, version, prodDef) try: versionId = self.db.db.productVersions.new(projectId=projectId, namespace=namespace, name=version, description=description, label=prodDef.getProductDefinitionLabel(), timeCreated=time.time()) except mint_error.DuplicateItem: raise mint_error.DuplicateProductVersion if product.prodtype == 'Appliance' or product.prodtype == 'PlatformFoundation': groupName = helperfuncs.getDefaultImageGroupName(product.hostname) className = util.convertPackageNameToClassName(groupName) # convert from unicode recipeStr = str(templates.write(groupTemplate, cfg = self.cfg, groupApplianceLabel=platformLabel, groupName=groupName, recipeClassName=className, version=version) + '\n') self.reposMgr.createSourceTrove(fqdn, groupName, label, version, {'%s.recipe' % groupName: recipeStr}, 'Initial appliance image group template') return versionId
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 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)