def testPrintDirectoryStatus(self): handle = self.getRbuildHandle() from rbuild_plugins import status mock.mockMethod(handle.Status._printOneDirectoryStatus) mock.mock(dirstore, 'CheckoutProductStore') dirstore.CheckoutProductStore( ).getProductDefinitionDirectory._mock.setDefaultReturn( '/full/path/.rbuild/product-definition') dirstore.CheckoutProductStore( ).getBaseDirectory._mock.setDefaultReturn('/full/path') handle.Status._printOneDirectoryStatus._mock.setDefaultReturn(None) self.mock( os, 'walk', lambda x: [('/full/path', ['Development', '.rbuild'], False)]) handle.Status.printDirectoryStatus('/full/path', product=True) self.unmock() handle.Status._printOneDirectoryStatus._mock.assertCalled( '/full/path/.rbuild/product-definition', 'Product Definition', status.DEFAULT, proddef=True, local=True, repository=True) handle.Status._printOneDirectoryStatus._mock.assertCalled( '/full/path', '/full/path', status.DEFAULT, '', local=True, repository=True) handle.Status._printOneDirectoryStatus._mock.assertCalled( '/full/path/Development', 'Development', status.DEFAULT, None, local=True, repository=True) self.mock(os, 'walk', lambda x: []) handle.Status.printDirectoryStatus('bogus', product=True) self.unmock() handle.Status._printOneDirectoryStatus._mock.assertCalled( '/full/path/.rbuild/product-definition', 'Product Definition', status.DEFAULT, proddef=True, local=True, repository=True) handle.Status._printOneDirectoryStatus._mock.assertCalled( 'bogus', 'bogus', status.DEFAULT, '', local=True, repository=True) self.assertRaises(ValueError, handle.Status.printDirectoryStatus, 'bogus', product=True, local=False, repository=False)
def testCheckoutProductStore(self): self._prepProductStore() util.mkdirChain('foo/stable/package') os.chdir('foo/stable/package') handle = self.getRbuildHandle(productStore=mock.MockObject()) productStore = dirstore.CheckoutProductStore(handle) self.assertEquals(productStore.getBaseDirectory(), self.workDir + '/foo') self.assertEquals(productStore.getActiveStageName(), 'stable') productStore = dirstore.CheckoutProductStore( handle, baseDirectory=self.workDir + '/foo') self.assertEquals(productStore.getBaseDirectory(), self.workDir + '/foo')
def testSaveProduct(self): self._prepProductStore() os.chdir('foo/stable') handle = self.getRbuildHandle(productStore=mock.MockObject()) productStore = dirstore.CheckoutProductStore(handle) mock.mockMethod(productStore._getSourceTroveVersion, returnValue='cny.tv@ns:1/2-3') prodDef = productStore.getProduct() self.assertEqual(prodDef.getProductDescription(), 'More foo') # Update the product definition, and make sure save will persist it prodDef.setProductDescription("Even more foo") productStore.save(prodDef) prodDef = productStore.getProduct() self.assertEqual(prodDef.getProductDescription(), 'Even more foo')
def testCore(self): handle = self.getRbuildHandle() productClass = mock.MockObject(stableReturnValues=True) stage = mock.MockObject(label='localhost@rpl:1') productClass().getStage._mock.setReturn(stage, 'foo') productClass._mock.popCall() self.mock(proddef, 'ProductDefinition', productClass) os.chdir(self.workDir) util.mkdirChain('foo/.rbuild/product-definition') self.writeFile('foo/.rbuild/product-definition/product-definition.xml', '') p = dirstore.CheckoutProductStore(handle, 'foo') err = self.assertRaises(errors.RbuildError, p.getActiveStageName) self.assertEquals(str(err), 'No current stage (setActiveStageName)') mock.mock(dirstore.CheckoutProductStore, 'checkStageIsValid') p.setActiveStageName('foo') assert(p.getActiveStageName() == 'foo') mock.mockMethod(p._getSourceTroveVersion, returnValue='cny.tv@ns:1/2-3') proddefObj = p.getProduct() _, kw = productClass._mock.popCall() kw = dict(kw) kw.pop('fromStream') configPath = self.workDir + '/foo/.rbuild/product-definition/rmakerc' self.assertEquals(p.getRmakeConfigPath(), configPath) mock.mockMethod(handle.facade.conary.updateCheckout) p.update() rbuildDir = p.getProductDefinitionDirectory() platformDir = p.getPlatformDefinitionDirectory() assert(platformDir == self.workDir + '/foo/.rbuild/platform-definition') handle.facade.conary.updateCheckout._mock.assertCalled(rbuildDir) proddefObj.getStages._mock.setDefaultReturn( [mock.MockObject(name='a'), mock.MockObject(name='b'), mock.MockObject(name='c')]) stageNames = [x for x in p.iterStageNames()] self.assertEquals(stageNames, ['a', 'b', 'c'])
def getHandle(dirName=None, prodDefLabel=None): """ Initializes an rBuild handle object, with a product definition as defined by the C{dirName} parameter (which provides a C{dirstore.CheckoutProductStore} product store) or the C{prodDefLabel} parameter (which provides a more limited C{abstract.ProductStore} product store that is insufficient for many plugin operations). If no parameter is specified, a C{dirstore.CheckoutProductStore} product store is provided based on the current directory. @param dirName: (None) directory for product store @param prodDefLabel: (None) label for product definition. @return: C{handle} instance """ cfg = handle.RbuildHandle.configClass(readConfigFiles=True) if prodDefLabel: productStore = None else: # note that if dirName is None, this defaults to current directory productStore = dirstore.CheckoutProductStore(baseDirectory=dirName) plugins = pluginloader.getPlugins([], cfg.pluginDirs) h = handle.RbuildHandle(cfg=cfg, pluginManager=plugins, productStore=productStore) if prodDefLabel: productStore = abstract.ProductStore() product = productStore.getProduct() client = h.facade.conary._getConaryClient() stream, _ = product._getStreamFromRepository(client, prodDefLabel) stream.seek(0) product.parseStream(stream) return h
def testEditProductDefinition(self): proddef = self.newProductDefinition() projDir = os.path.join(self.workDir, 'myproject') prodDefDir = os.path.join(projDir, '.rbuild/product-definition') prodDefPath = os.path.join(prodDefDir, 'product-definition.xml') os.makedirs(prodDefDir) proddef.serialize(file(prodDefPath, "w")) productStore = dirstore.CheckoutProductStore(baseDirectory=projDir) handle = self.getRbuildHandle(productStore=productStore) mock.mock(handle.facade, 'conary') facade = handle.facade.conary message = "commit message" # Return a consistent temp file tmpf = handle.Edit._makeTemporaryFile() mock.mockMethod(handle.Edit._makeTemporaryFile, tmpf) class MockMethod(object): def __init__(self): self.retval = None self.callList = [] self.realFunction = None self._idx = 0 def __call__(self, *args, **kwargs): self.callList.append((args, kwargs)) if self.realFunction is None: return self.retval if isinstance(self.realFunction, list): func = self.realFunction[self._idx] self._idx += 1 else: func = self.realFunction return func(*args, **kwargs) def reset(self): self._idx = 0 del self.callList[:] invEditor = MockMethod() self.mock(handle.Edit, '_invokeEditor', invEditor) # Simulate edit error invEditor.retval = 1 self.assertEquals(handle.Edit.editProductDefinition(message), 1) tmpf.seek(0) tmpf.truncate() invEditor.reset() # Simulate no change (mtime of file doesn't change) invEditor.retval = 0 self.assertEquals(handle.Edit.editProductDefinition(message), 0) tmpf.seek(0) tmpf.truncate() invEditor.reset() def _changedProdDef(stream): # Change the proddef prod = self.newProductDefinition() prod.setProductName('awesome name, changed') stream.seek(0) stream.truncate() prod.serialize(stream) return 0 invEditor.realFunction = _changedProdDef self.assertEquals(handle.Edit.editProductDefinition(message), 0) self.assertEquals(len(invEditor.callList), 1) facade.commit._mock.assertCalled(prodDefDir, message=message) # Test some of the more possible errors tmpf.seek(0) tmpf.truncate() invEditor.reset() def _invalidXml(stream): stream.seek(0) stream.truncate() stream.write("<invalid xml") stream.flush() return 0 invEditor.realFunction = _invalidXml uiInput = mock.mockMethod(handle.ui.input) uiInput._mock.setReturn('n', 'Do you want to retry? (Y/n) ') self.assertEquals(handle.Edit.editProductDefinition(message), 3) # Invalid xml first, then correct one tmpf.seek(0) tmpf.truncate() invEditor.reset() invEditor.realFunction = [_invalidXml, _invalidXml, _changedProdDef] uiInput._mock.setReturn('y', 'Do you want to retry? (Y/n) ') self.assertEquals(handle.Edit.editProductDefinition(message), 0) facade.commit._mock.assertCalled(prodDefDir, message=message) def _xmlNoNamespace(stream): stream.seek(0) stream.truncate() stream.write("<productDefinition/>") stream.flush() return 0 tmpf.seek(0) tmpf.truncate() invEditor.reset() invEditor.realFunction = _xmlNoNamespace uiInput._mock.setReturn('n', 'Do you want to retry? (Y/n) ') self.assertEquals(handle.Edit.editProductDefinition(message), 1) def _xmlNamespacedNoVersion(stream): stream.seek(0) stream.truncate() stream.write("<productDefinition xmlns='http://dummy'/>") stream.flush() return 0 tmpf.seek(0) tmpf.truncate() invEditor.reset() invEditor.realFunction = _xmlNamespacedNoVersion uiInput._mock.setReturn('n', 'Do you want to retry? (Y/n) ') self.assertEquals(handle.Edit.editProductDefinition(message), 2)
def printDirectoryStatus(self, directory, verbosity=DEFAULT, product=False, local=True, repository=True): #pylint: disable-msg=R0913,R0914 # conflating arguments would just make this harder to understand # not amenable to refactoring to split up local variables ''' Prints status of various things based on the current working directory. The default output displays what packages and files have changed, but not the contents of the changes to the files. @param directory: name of directory to print status of @param verbosity: level of change to display @param product: Display changes to product similar to packages @param local: Display local filesystem changes not yet committed @param repository: Display changes committed to the repository but not yet applied locally At least one of C{local} and C{repository} must be set. ''' if not local and not repository: raise ValueError( 'At least one of local and repository must be True') productStore = dirstore.CheckoutProductStore(self.handle, directory) proddefDir = productStore.getProductDefinitionDirectory() if product: self._printOneDirectoryStatus(proddefDir, 'Product Definition', verbosity, proddef=True, local=local, repository=repository) baseDir = productStore.getBaseDirectory() baseDirLen = len(baseDir) def stripPrefix(dirName): # Get the name relative to the checkout, not the current # working directory. This is like most version control # systems -- see "hg stat" for one of many examples if dirName == baseDir: # no empty baseDir return baseDir if dirName.startswith(baseDir): # make relative to baseDir return dirName[baseDirLen + 1:] return dirName pendingAnnounce = self._printOneDirectoryStatus(directory, stripPrefix(directory), verbosity, '', local=local, repository=repository) for dirpath, dirnames, _ in os.walk(directory): for oneDir in sorted(dirnames): if oneDir == '.rbuild': # product store already handled separately if # appropriate, stop from recursing dirnames.remove('.rbuild') continue dirName = os.path.join(dirpath, oneDir) pendingAnnounce = self._printOneDirectoryStatus( dirName, stripPrefix(dirName), verbosity, pendingAnnounce, local=local, repository=repository)
def createProductDirectory(self, version, productDir=None): handle = self.handle if productDir is None: productDir = tempfile.mkdtemp(dir=os.getcwd()) tempDir = productDir else: tempDir = None try: util.mkdirChain(productDir + '/.rbuild') os.mkdir(productDir + '/.rbuild/tracebacks', 0700) targetDir = productDir + '/.rbuild/product-definition' handle.facade.conary.checkout('product-definition', version, targetDir=targetDir) productStore = dirstore.CheckoutProductStore(handle, productDir) product = productStore.getProduct() if tempDir: productDir = '%s-%s' % (product.getProductShortname(), product.getProductVersion()) if os.path.exists(productDir): raise errors.PluginError( 'Directory %s already exists.' % productDir) os.rename(tempDir, productDir) tempDir = None targetDir = productDir + '/.rbuild/product-definition' finally: if tempDir: util.rmtree(tempDir) logRoot = productDir + '/.rbuild' handle.ui.resetLogFile(logRoot) # This redundant log entry is the first entry in the new log, # corresponding to a similar entry in the toplevel log handle.ui._log('rBuild %s initialized %s-%s in %s', rbuild.constants.VERSION, product.getProductShortname(), product.getProductVersion(), productDir) stages = product.getStages() for stage in stages: stageDir = productDir + '/' + stage.name os.mkdir(stageDir) open(stageDir + '/.stage', 'w').write(stage.name + '\n') stageLabel = product.getLabelForStage(stage.name) open(stageDir + '/conaryrc', 'w').write( '# This file may be automatically overwritten by rbuild\n' 'buildLabel %s\n' 'installLabelPath %s\n' %(stageLabel, stageLabel)) oldumask = os.umask(077) try: handle.getConfig().writeCheckoutFile( productDir + '/.rbuild/rbuildrc') finally: os.umask(oldumask) handle.ui.info('Created checkout for %s at %s', product.getProductDefinitionLabel(), productDir) # get the versions that point to the real checkout now handle.productStore = dirstore.CheckoutProductStore(None, productDir) handle.product = handle.productStore.getProduct() return handle.productStore
def __init__(self, cfg=None, pluginManager=None, productStore=None, userInterface=None, logRoot=None): super(RbuildHandle, self).__init__() self.product = None if cfg is None: cfg = self.configClass(readConfigFiles=True) if pluginManager is None: pluginManager = pluginloader.getPlugins([], cfg.pluginDirs) # Unknown sections are initially stashed aside by the config object # After the plugins are loaded we try to process their data pluginManager.addPluginConfigurationClasses(cfg) cfg.setIgnoreErrors(False) cfg.processPluginSections() pluginManager.setPluginConfigurations(cfg) self._cfg = cfg self._pluginManager = pluginManager for plugin in pluginManager.plugins: pluginName = plugin.__class__.__name__ self[pluginName] = plugin plugin.setHandle(self) # Provide access to facades self.facade = _PluginProxy(self._getFacades()) # Provide the command manager as if it were a plugin self['Commands'] = CommandManager() if userInterface is not None: self.ui = userInterface else: if logRoot is not False: if not logRoot: logRoot = errors._findCheckoutRoot() if logRoot: logRoot += '/.rbuild' #pylint: disable-msg=C0103 # this name is intentional self.ui = ui.UserInterface(self._cfg, logRoot=logRoot) if productStore is None: # default product store is directory-based # Note: will still be None for some cases, such as rbuild init proddir = dirstore.getDefaultProductDirectory() if proddir is not None: productStore = dirstore.CheckoutProductStore(None, proddir) self.productStore = productStore if productStore: self.product = productStore.getProduct() if hasattr(productStore, 'getRbuildConfigPath'): rBuildConfigPath = productStore.getRbuildConfigPath() if rBuildConfigPath is not None: self._cfg.read(rBuildConfigPath, exception=False) elif hasattr(productStore, 'getRbuildConfigData'): RbuildConfigData = productStore.getRbuildConfigData() if RbuildConfigData is not None: self._cfg.readObject('INTERNAL', RbuildConfigData)