def testRdiff8(self): # CNY-1753 # Different files living on different branches raise testhelp.SkipTestException( "Unable to reproduce CNY-1753 in a test case") # Manifested in running conary rdiff # mkinitrd=conary.rpath.com@rpl:1--usplash.rb.rpath.com@rpl:1 rf1 = rephelp.RegularFile( contents='\000\001\002\003', perms=0644, mtime=1176921017, ) rf2 = rephelp.RegularFile( contents='\000\001\003\005', perms=0644, mtime=1176921317, ) v1 = versions.ThawVersion('/localhost@rpl:1/1:1-1-1') v2 = versions.ThawVersion('/localhost1@rpl:2/2:2-2-2') self.openRepository() self.openRepository(1) self.addComponent('foo:run', v1, [('/bin/foo', rf1)]) self.addCollection('foo', v1, [':run']) self.addComponent('foo:run', v2, [('/bin/foo', rf2)]) self.addCollection('foo', v2, [':run']) troveSpec = cmdline.parseChangeList('foo=%s--%s' % (v1, v2))[0] ret, outs = self.captureOutput(queryrep.diffTroves, self.cfg, troveSpec) self.assertEqual(outs, '')
def testLatestByLabel(self): def _build(*specList): for (v, f) in specList: self.addComponent('t:rt', v, flavor=f) v1 = versions.ThawVersion('/localhost@rpl:foo//1/1:1.0-1-1') v2 = versions.ThawVersion('/localhost@rpl:bar//1/2:1.0-1-2') l = v1.trailingLabel() defFlavor = deps.parseFlavor('readline,ssl') noReadLine = deps.parseFlavor('~!readline,ssl') reqNoReadLine = deps.parseFlavor('!readline,ssl') _build((v1, defFlavor), (v2, defFlavor)) repos = self.openRepository() d = repos.getTroveLatestByLabel({'t:rt': {l: None}}) assert (d['t:rt'].keys() == [v2]) d = repos.getTroveLatestByLabel({'t:rt': {l: [defFlavor]}}) assert (d['t:rt'].keys() == [v2]) d = repos.getTroveLatestByLabel({'t:rt': { l: [defFlavor] }}, bestFlavor=True) assert (d['t:rt'].keys() == [v2]) _build((v1, noReadLine)) d = repos.getTroveLatestByLabel({'t:rt': {l: None}}) assert (d['t:rt']) == {v1: [noReadLine], v2: [defFlavor]} d = repos.getTroveLatestByLabel({'t:rt': { l: [noReadLine] }}, bestFlavor=True) assert (d['t:rt']) == {v2: [defFlavor]} d = repos.getTroveLatestByLabel({'t:rt': { l: [reqNoReadLine] }}, bestFlavor=True) assert (d['t:rt']) == {v1: [noReadLine]} d = repos.getTroveLatestByLabel({'t:rt': {l: [noReadLine]}}) assert (d['t:rt']) == {v2: [defFlavor], v1: [noReadLine]} d = repos.getTroveLatestByLabel({'t:rt': {l: [defFlavor, noReadLine]}}) assert (d['t:rt']) == {v2: [defFlavor], v1: [noReadLine]} d = repos.getTroveLatestByLabel( {'t:rt': { l: [defFlavor, reqNoReadLine] }}, bestFlavor=True) assert (d['t:rt']) == {v2: [defFlavor], v1: [noReadLine]}
class JobTupleTest(testhelp.TestCase): old = (versions.ThawVersion('/conary.rpath.com@rpl:devel//2/1000000000.000:2.9.10-2-0.1'), deps.parseFlavor('is: x86_64')) new = (versions.ThawVersion('/conary.rpath.com@rpl:devel//2/1200000000.000:3.0.00-1-0.1'), deps.parseFlavor('is: x86_64')) def testNewTuple(self): n = 'tmpwatch' a = self.old b = self.new atup = (n, a[0], a[1]) btup = trovetup.TroveTuple(n, b[0], b[1]) self.assertEqual((n, a, b, False), trovetup.JobTuple((n, a, b, False))) self.assertEqual((n, a, b, False), trovetup.JobTuple(n, a, b, False)) self.assertEqual((n, a, b, False), trovetup.JobTuple(n, a, b)) self.assertEqual((n, a, b, False), trovetup.JobTuple(n, atup, btup)) self.assertEqual((n, (None, None), b, True), trovetup.JobTuple(n, new=b)) self.assertEqual((n, (None, None), b, True), trovetup.JobTuple(n, new=btup)) self.assertEqual((n, a, (None, None), False), trovetup.JobTuple(n, old=a)) self.assertEqual((n, a, (None, None), False), trovetup.JobTuple(n, old=atup)) self.assertEqual((n, (None, None), b, True), btup.asJob()) def testStringify(self): x = trovetup.JobTuple('tmpwatch', new=self.new) self.assertEqual(str(x), "tmpwatch=/conary.rpath.com@rpl:devel//2/3.0.00-1-0.1[is: x86_64]") self.assertEqual(repr(x), "JobTuple('tmpwatch=/conary.rpath.com@rpl:devel//2/1200000000.000:3.0.00-1-0.1[is: x86_64]')") x = x._replace(absolute=False) self.assertEqual(str(x), "tmpwatch=/conary.rpath.com@rpl:devel//2/3.0.00-1-0.1[is: x86_64]") self.assertEqual(repr(x), "JobTuple('tmpwatch=/conary.rpath.com@rpl:devel//2/1200000000.000:3.0.00-1-0.1[is: x86_64]', absolute=False)") x = trovetup.JobTuple('tmpwatch', self.old, self.new) self.assertEqual(str(x), "tmpwatch=/conary.rpath.com@rpl:devel//2/2.9.10-2-0.1[is: x86_64]" "--/conary.rpath.com@rpl:devel//2/3.0.00-1-0.1[is: x86_64]") self.assertEqual(repr(x), "JobTuple('tmpwatch=/conary.rpath.com@rpl:devel//2/1000000000.000:2.9.10-2-0.1[is: x86_64]" "--/conary.rpath.com@rpl:devel//2/1200000000.000:3.0.00-1-0.1[is: x86_64]')") x = x._replace(absolute=True) self.assertEqual(str(x), "tmpwatch=/conary.rpath.com@rpl:devel//2/2.9.10-2-0.1[is: x86_64]" "--/conary.rpath.com@rpl:devel//2/3.0.00-1-0.1[is: x86_64]") self.assertEqual(repr(x), "JobTuple('tmpwatch=/conary.rpath.com@rpl:devel//2/1000000000.000:2.9.10-2-0.1[is: x86_64]" "--/conary.rpath.com@rpl:devel//2/1200000000.000:3.0.00-1-0.1[is: x86_64]', absolute=True)") x = trovetup.JobTuple('tmpwatch', self.old) self.assertEqual(str(x), "tmpwatch=/conary.rpath.com@rpl:devel//2/2.9.10-2-0.1[is: x86_64]--") self.assertEqual(repr(x), "JobTuple('tmpwatch=/conary.rpath.com@rpl:devel//2/1000000000.000:2.9.10-2-0.1[is: x86_64]--')") def testParser(self): p = trovetup.JobTuple self.assertRaises(ParseError, p, u'spam\xFF=foo[bar]') self.assertEqual(p('tmpwatch=/conary.rpath.com@rpl:devel//2/1200000000.000:3.0.00-1-0.1[is: x86_64]'), ('tmpwatch', (None, None), self.new, True)) self.assertEqual(p('tmpwatch=/conary.rpath.com@rpl:devel//2/1000000000.000:2.9.10-2-0.1[is: x86_64]' '--/conary.rpath.com@rpl:devel//2/1200000000.000:3.0.00-1-0.1[is: x86_64]'), ('tmpwatch', self.old, self.new, False)) self.assertEqual(p('tmpwatch=/conary.rpath.com@rpl:devel//2/1000000000.000:2.9.10-2-0.1[is: x86_64]--'), ('tmpwatch', self.old, (None, None), False))
def parseLines(self, lines, stateVersion, repos): kwargs = {} while lines: fields = lines[0][:-1].split() # the file count ends the list of fields if len(fields) == 1: break assert (len(fields) == 2) del lines[0] what = fields[0] assert (not kwargs.has_key(what)) if what not in self.fields: raise ConaryStateError('Invalid field "%s"' % what) isVer = self.fields[what][0] if isVer: kwargs[what] = versions.ThawVersion(fields[1]) else: kwargs[what] = fields[1] required = set([x[0] for x in self.fields.items() if x[1][1]]) assert ((set(kwargs.keys()) & required) == required) SourceState.__init__(self, **kwargs) self._readFileList(lines, stateVersion, repos)
def __thaw__(item): if len(item) == 3: context = '' n, v, f = item else: n, v, f, context = item return (n, versions.ThawVersion(v), ThawFlavor(f), context)
def testStringVersion(self): # make sure you can represent VERSION -> None diff v1 = StringVersionStream() v2 = StringVersionStream() v1.set(versions.ThawVersion('/a@b:c/15:1.1-1')) assert (v1.freeze() == '/a@b:c/1.1-1') v1.twm(v2.diff(v1), v1) assert (v1.freeze() == '') # make sure that twm works properly v1.set(versions.ThawVersion('/a@b:c/15:1.1-1')) v2 = StringVersionStream() diff = v1.diff(v2) v2.twm(diff, v2) assert (v1 == v2) assert (v1.diff(v2) is None)
def deleteJobs(self, jobIdList): cu = self.db.cursor() troveIdList = [] logHashes = set() for jobId in jobIdList: cu.execute( '''SELECT troveId, troveName, version, flavor, logPath FROM BuildTroves WHERE jobId=?''', jobId) for troveId, name, version, flavor, logPath in cu: version = versions.ThawVersion(version) flavor = deps.ThawFlavor(flavor) if logPath: logHashes.add(logPath) cu.execute('DELETE FROM BinaryTroves where troveId=?', troveId) for table in [ 'Jobs', 'JobConfig', 'Subscriber', 'BuildTroves', 'StateLogs', 'JobQueue' ]: cu.execute('DELETE FROM %s WHERE jobId=?' % table, jobId) cu.execute( '''DELETE FROM JobConfig WHERE key="jobContext" AND value=?''', jobId) if logHashes: # Prebuilt troves can refer to logs produced by previous builds. # Keep any logs that are still referenced by jobs not being # deleted. placeholders = ','.join('?' for x in logHashes) cu.execute( "SELECT logPath FROM BuildTroves WHERE logPath IN (%s)" % (placeholders, ), list(logHashes)) for logPath, in cu: logHashes.discard(logPath) return logHashes
def _loadTimestamps(self): if self.version < (4, 0): return timeStampList = self._loadPickle(self._timeStampsPathId) for (name, frozenVersion) in timeStampList: thawed = versions.ThawVersion(frozenVersion) self.timeStampCache[(name, thawed)] = thawed
def _checkRemovals(self, group, updateId): """ Check to make sure that all configured package removals have happened. """ # get package removals from the config object. removePackages = self._cfg.updateRemovesPackages.get(updateId, []) removeObsoleted = self._cfg.removeObsoleted.get(updateId, []) removeSource = [x[0] for x in self._cfg.removeSource.get(updateId, [])] # get names and versions troves = set() labels = set() for pkgKey, pkgData in group.iteritems(): name = str(pkgData.name) version = None if pkgData.version: versionObj = versions.ThawVersion(pkgData.version) labels.add(versionObj.branch().label()) version = str(versionObj.asString()) flavor = None troves.add((name, version, flavor)) # Get flavors and such. foundTroves = set([ x for x in itertools.chain( *self._helper.findTroves(troves, labels=labels).itervalues()) ]) # get sources for each name version pair sources = self._helper.getSourceVersions(foundTroves) # collapse to sourceName: [ binNames, ] dictionary sourceNameMap = dict([(x[0].split(':')[0], [z[0] for z in y]) for x, y in sources.iteritems()]) binRemovals = set( itertools.chain( * [sourceNameMap[x] for x in removeSource if x in sourceNameMap])) # take the union removals = set(removePackages) | set(removeObsoleted) | binRemovals errors = [] # Make sure these packages are not in the group model. for pkgKey, pkgData in group.iteritems(): if pkgData.name in removals: errors.append(pkgData.name) if errors: log.info('found packages that should be removed %s' % errors) raise ExpectedRemovalValidationFailedError(updateId=updateId, pkgNames=errors)
def _checkNameVersionConflict(self, group): """ Check for packages taht have the same source name, but different versions. """ # get names and versions troves = set() labels = set() for pkgKey, pkgData in group.iteritems(): name = str(pkgData.name) version = None if pkgData.version: versionObj = versions.ThawVersion(pkgData.version) labels.add(versionObj.branch().label()) version = str(versionObj.asString()) flavor = None # FIXME: At some point we might want to add proper flavor handling, # note that group flavor handling is different than what # findTroves normally does. #if pkgData.flavor: # flavor = deps.ThawFlavor(str(pkgData.flavor)) troves.add((name, version, flavor)) # Get flavors and such. foundTroves = set([ x for x in itertools.chain( *self._helper.findTroves(troves, labels=labels).itervalues()) ]) # get sources for each name version pair sources = self._helper.getSourceVersions(foundTroves) seen = {} for (n, v, f), pkgSet in sources.iteritems(): binVer = list(pkgSet)[0][1] seen.setdefault(n, set()).add(binVer) binPkgs = {} conflicts = {} for name, vers in seen.iteritems(): if len(vers) > 1: log.error('found multiple versions of %s' % name) for binVer in vers: srcVer = binVer.getSourceVersion() nvf = (name, srcVer, None) conflicts.setdefault(name, []).append(srcVer) binPkgs[nvf] = sources[nvf] if conflicts: raise NameVersionConflictsFoundError(groupName=group.groupName, conflicts=conflicts, binPkgs=binPkgs)
def __thaw__(tupList): results = [] for tup in tupList: if len(tup) == 3 or not tup[3]: context = '' else: context = tup[3] results.append((tup[0], versions.ThawVersion(tup[1]), ThawFlavor(tup[2]), context)) return results
def __init__(self, conaryClient, troveSpec, troveChangeRequest=None, troveSpecOther=None): self.conaryClient = conaryClient n, v, f = conaryclient.cmdline.parseTroveSpec(troveSpec) self.trvName = n self.trvNewVersion = versions.ThawVersion(v) self.trvNewFlavor = f self._fromTroveChangeRequest(troveChangeRequest) self._fromOtherTroveSpec(troveSpecOther)
def _loadDepSolutions(self): if self.version < (2, 0): # Earlier versions were missing timestamps, which interferes with # dep solver tie-breaking. return depSolutionsList = self._loadPickle(self._depSolutionsPathId) for (sig, depSet, aResult) in depSolutionsList: depSet = deps.ThawDependencySet(depSet) allResults = [] for resultList in aResult: allResults.append([(x[0], versions.ThawVersion(x[1]), deps.ThawFlavor(x[2])) for x in resultList]) self.addDepSolution(sig, depSet, allResults)
def _loadDepSolutions(self): if self.version < (3, 0): # Version 1 was missing timestamps, which interferes with dep # solver tie-breaking. # Version 2 could have bogus unresolved dep solutions due to a bug # so the version was bumped to invalidate those. return depSolutionsList = self._loadPickle(self._depSolutionsPathId) for (sig, depSet, aResult) in depSolutionsList: depSet = deps.ThawDependencySet(depSet) allResults = [] for resultList in aResult: allResults.append([ (x[0], versions.ThawVersion(x[1]), deps.ThawFlavor(x[2])) for x in resultList]) self.addDepSolution(sig, depSet, allResults)
def thaw(self, data): del self[:] if not data: return l = data.split("\0") i = 0 while i < len(l): name = l[i] version = versions.ThawVersion(l[i + 1]) flavor = l[i + 2] flavor = deps.ThawFlavor(flavor) self.append((name, version, flavor)) i += 3
def testNewTuple(self): n, v, f = self.sample vo = versions.ThawVersion(v) fo = deps.parseFlavor(f) ex_str = '%s=%s[%s]' % (n, v, f) expect = "TroveTuple(%r)" % (ex_str,) p = trovetup.TroveTuple self.assertEquals(repr(p(n, v, f)), expect) self.assertEquals(repr(p((n, v, f))), expect) self.assertEquals(repr(p(ex_str)), expect) self.assertEquals(repr(p(ex_str.decode('ascii'))), expect) self.assertEquals(repr(p(n, vo, fo)), expect) self.assertEquals(repr(p((n, vo, fo))), expect) self.assertEquals(repr(p('%s=%s' % (n, v))), "TroveTuple('%s=%s[]')" % (n, v))
def _fromTroveChangeRequest(self, troveChangeRequest): if troveChangeRequest is None: return fromVersion = self.trvNewVersion versionChange = troveChangeRequest.get_versionChange() if versionChange is not None: fromVersionStr = versionChange.get_from() if fromVersionStr: fromVersion = versions.ThawVersion(fromVersionStr) self.trvOldVersion = fromVersion fromFlavor = self.trvNewFlavor flavorChange = troveChangeRequest.get_flavorChange() if flavorChange is not None: fromFlavorStr = flavorChange.get_from() if fromFlavorStr: fromFlavor = deps.parseFlavor(str(fromFlavorStr)) self.trvOldFlavor = fromFlavor
def troveInfo(self, auth, t, v): t = unquote(t) leaves = {} for serverName in self.serverNameList: newLeaves = self.repos.getTroveVersionList(serverName, {t: [None]}) leaves.update(newLeaves) if t not in leaves: return self._write("error", error='%s was not found on this server.' % t) versionList = sorted(leaves[t].keys(), reverse=True) if not v: reqVer = versionList[0] else: try: reqVer = versions.VersionFromString(v) except (versions.ParseError, ValueError): try: reqVer = versions.ThawVersion(v) except: return self._write("error", error="Invalid version: %s" % v) try: query = [(t, reqVer, x) for x in leaves[t][reqVer]] except KeyError: return self._write( "error", error="Version %s of %s was not found on this server." % (reqVer, t)) troves = self.repos.getTroves(query, withFiles=False) mdata = self.repos.getMetadata([t, reqVer.branch()], reqVer.branch().label()) if t in mdata: mdata = mdata[t] return self._write("trove_info", troveName=t, troves=troves, versionList=versionList, reqVer=reqVer, metadata=mdata)
def files(self, auth, t, v, f): v = versions.ThawVersion(v) f = deps.ThawFlavor(f) parentTrove = self.repos.getTrove(t, v, f, withFiles=False) # non-source group troves only show contained troves if trove.troveIsGroup(t): troves = sorted(parentTrove.iterTroveList(strongRefs=True)) return self._write("group_contents", troveName=t, troves=troves) fileIters = [] for n, v, f in self.repos.walkTroveSet(parentTrove, withFiles=False): files = self.repos.iterFilesInTrove(n, v, f, withFiles=True, sortByPath=True) fileIters.append(files) return self._write("files", troveName=t, fileIters=itertools.chain(*fileIters))
def deleteJobs(self, jobIdList): cu = self.db.cursor() troveIdList = [] troveList = [] for jobId in jobIdList: cu.execute('''SELECT troveId, troveName, version, flavor FROM BuildTroves WHERE jobId=?''', jobId) for troveId, name, version, flavor in cu: version = versions.ThawVersion(version) flavor = deps.ThawFlavor(flavor) troveList.append((jobId, name, version, flavor)) cu.execute('DELETE FROM BinaryTroves where troveId=?', troveId) for table in ['Jobs', 'JobConfig', 'Subscriber', 'BuildTroves', 'StateLogs', 'JobQueue' ]: cu.execute('DELETE FROM %s WHERE jobId=?' % table, jobId) cu.execute('''DELETE FROM JobConfig WHERE key="jobContext" AND value=?''', jobId) return troveList
def testRedirectOnBranch(self): # CNY-1181 # create test and test-foo on localhost@rpl:linux self.addComponent('test:source', '1.0') self.addComponent('test:runtime', '1.0') self.addComponent('test-foo:runtime', '1.0') self.addCollection('test', '1.0', [':runtime']) self.addCollection('test-foo', '1.0', [':runtime']) # branch test to /localhost@rpl:linux/:branch self.mkbranch("/localhost@rpl:linux", versions.Label("localhost@foo:branch"), "test") b = '/localhost@rpl:linux/1.0-1-0/branch/2.0-1-1' # add a new version self.addComponent('test:runtime', b) self.addCollection('test', b, [':runtime']) r = """ class testRedirect(RedirectRecipe): name = 'test' version = '1.0' clearBuildReqs() def setup(r): r.addRedirect("test-foo", "localhost@rpl:linux") """ # use the source version that would match :source on the branch v = versions.ThawVersion( '/localhost@rpl:linux/123.0:1.0-1/branch/456.0:2.0-1') built, str = self.captureOutput(self.buildRecipe, r, 'testRedirect', sourceVersion=v) self.checkUpdate(['test=:branch'], ['test-foo=--1.0', 'test-foo:runtime=--1.0'])
def searchTroves(cu, roleIds, label = None, filterSet = None, mkUrl = None, latest = True, start = 0, limit = None, name = None): d = { 'labelCheck' : '', 'nameCheck' : '' } args = [] regex = None if label: d['labelCheck'] = "label = ? AND" args.append(label) if name: if set('?.*[]\\()+') & set(name): # if only .* appears, replace them with '%' and use LIKE. this # code currently fails with \.* in the regex, but neither . # nor \* are valid trove names anyway likeName = name while '.*' in likeName: likeName = likeName.replace('.*', '%') if set('?.*[]\\()+') & set(name): regex = re.compile(name) else: d['nameCheck'] = "WHERE item LIKE ?" args.append(likeName) else: d['nameCheck' ] = "WHERE item = ?" args.append(name) d['roleIds'] = ",".join( str(x) for x in roleIds) if latest: cu.execute(""" SELECT item, version, flavor, ts FROM (SELECT DISTINCT Nodes.itemId AS itemId, Nodes.versionId AS versionId, flavorId, Nodes.timeStamps AS ts FROM Labels JOIN LabelMap USING (labelId) JOIN LatestCache USING (itemId, branchId) JOIN Nodes USING (itemId, versionId) WHERE %(labelCheck)s LatestCache.latestType = 1 AND LatestCache.userGroupId in (%(roleIds)s)) AS idTable JOIN Items USING (itemId) JOIN Versions ON (idTable.versionId = Versions.versionId) JOIN Flavors ON (idTable.flavorId = Flavors.flavorId) %(nameCheck)s ORDER BY item, version, flavor """ % d, *args) else: cu.execute(""" SELECT item, version, flavor, ts FROM (SELECT DISTINCT Instances.itemId AS itemId, Instances.versionId AS versionId, Instances.flavorId AS flavorId, Nodes.timeStamps AS ts FROM Labels JOIN LabelMap USING (labelId) JOIN Nodes USING (itemId, branchid) JOIN Instances USING (itemid, versionid) JOIN usergroupinstancescache AS ugi USING (instanceid) WHERE %(labelCheck)s ugi.userGroupId in (%(roleIds)s)) AS idTable JOIN Items USING (itemId) JOIN Versions ON (idTable.versionId = Versions.versionId) JOIN Flavors ON (idTable.flavorId = Flavors.flavorId) %(nameCheck)s ORDER BY item, version, flavor """ % d, *args) l = list(cu) filteredL = typeFilter(l, filterSet) if regex: filteredL = [ x for x in filteredL if regex.match(x[0]) ] if limit is None: limit = len(filteredL) - start troveList = datamodel.NamedTroveIdentList(total = len(filteredL), start = start) for (name, version, flavor, ts) in filteredL[start:start + limit]: flavor = str(deps.ThawFlavor(flavor)) frzVer = versions.strToFrozen(version, [ x for x in ts.split(":") ]) ver = versions.ThawVersion(frzVer) troveList.append(name = name, version = ver, flavor = flavor, mkUrl = mkUrl) return troveList
class CapsuleTest(rephelp.RepositoryHelper): id1 = md5FromString("00010001000100010001000100010001") id2 = md5FromString("00010001000100010001000100010002") id3 = md5FromString("00010001000100010001000100010003") id4 = md5FromString("00010001000100010001000100010004") id5 = md5FromString("00010001000100010001000100010005") fid1 = sha1FromString("1001000100010001000100010001000100010001") fid2 = sha1FromString("1001000100010001000100010001000100010002") fid3 = sha1FromString("1001000100010001000100010001000100010003") fid4 = sha1FromString("1001000100010001000100010001000100010004") fid5 = sha1FromString("1001000100010001000100010001000100010005") v1 = versions.ThawVersion('/localhost@foo:bar/1.0:1.0-1-1') @conary_test.rpm def test01_Trove(self): t = trove.Trove('foo:continer', self.v1, deps.Flavor()) t.addFile(self.id1, '/1', self.v1, self.fid1) t.addFile(self.id2, '/2', self.v1, self.fid2) h = { rpmhelper.NAME : 'foorpm', rpmhelper.VERSION : '1.0', rpmhelper.RELEASE : '1', rpmhelper.ARCH : 'i386', rpmhelper.EPOCH : [ 1 ] } t.addRpmCapsule('foo.rpm', self.v1, self.fid5, h) assert([ x[1] for x in t.iterFileList() ] == [ '/1', '/2'] ) assert([ x[1] for x in t.iterFileList(members = True) ] == [ '/1', '/2'] ) assert([ x[0:2] for x in t.iterFileList(capsules = True) ] == [ (trove.CAPSULE_PATHID, 'foo.rpm' ) ] ) assert([ x[1] for x in t.iterFileList(members = True, capsules = True) ] == [ '/1', 'foo.rpm', '/2' ]) assert([ x[1] for x in t.iterFileList(members = False, capsules = False) ] == []) @conary_test.rpm @testhelp.context('rollback') def test02_Repository(self): def csContents(repos, job): p = os.path.join(self.workDir, 'foo.ccs') repos.createChangeSetFile(job, p) fc = filecontainer.FileContainer( util.ExtendedFile(p, buffering = False)) l = [] info = fc.getNextFile() while info: l.append(info) info = fc.getNextFile() return l cmp = self.addRPMComponent("simple:rpm=1.0", 'simple-1.0-1.i386.rpm') repos = self.openRepository() reposCmp = repos.getTrove(*cmp.getNameVersionFlavor()) assert(reposCmp == cmp) l = csContents(repos, [ ("simple:rpm", (None, None), cmp.getNameVersionFlavor()[1:], True) ]) assert([ x[0][0:16] for x in l ] == ['CONARYCHANGESET', '\x8d\xeb\xb9\x15M!\xe0\xc5\x08D\x87\xf7\xe1\xf9fW', trove.CAPSULE_PATHID ]) cmp = self.addRPMComponent("simple:rpm=1.1", 'simple-1.1-1.i386.rpm') self.updatePkg('simple:rpm=1.0') assert(os.path.isdir(self.rootDir + "/dir")) self.verifyFile(self.rootDir + "/config", "config\n") self.verifyFile(self.rootDir + "/normal", "normal\n") self.updatePkg('simple:rpm=1.1') self.verifyFile(self.rootDir + "/config", "changed-config\n") self.verifyFile(self.rootDir + "/normal", "changed-normal\n") self.rollback(self.rootDir, 1) self.verifyFile(self.rootDir + "/config", "config\n") self.verifyFile(self.rootDir + "/normal", "normal\n") self.writeFile(self.rootDir + '/config', 'config\nlocal config\n') rc, str = self.captureOutput(self.updatePkg, 'simple:rpm=1.1') self.assertEquals(str, 'warning: /config saved as /config.rpmsave\n') self.verifyFile(self.rootDir + '/config', 'changed-config\n') self.rollback(self.rootDir, 1) self.verifyFile(self.rootDir + '/config', 'config\nlocal config\n') rc, str = self.captureOutput(self.erasePkg, self.rootDir, 'simple:rpm') self.assertEquals(str, 'warning: /config saved as /config.rpmsave\n') assert(not os.path.exists(self.rootDir + '/config')) self.rollback(self.rootDir, 1) self.verifyFile(self.rootDir + '/config', 'config\nlocal config\n') rc, str = self.captureOutput(self.rollback, self.rootDir, 0) self.assertEquals(str, 'warning: /config saved as /config.rpmsave\n') assert(not os.path.exists(self.rootDir + "/dir")) assert(not os.path.exists(self.rootDir + "/config")) assert(not os.path.exists(self.rootDir + "/normal")) @conary_test.rpm @testhelp.context('rollback') def test03_Overlap(self): osA1 = self.addRPMComponent("overlap-same-A:rpm=1.0", 'overlap-same-A-1.0-1.i386.rpm') osB1 = self.addRPMComponent("overlap-same-B:rpm=1.0", 'overlap-same-B-1.0-1.i386.rpm') self.updatePkg('overlap-same-A:rpm=1.0') self.updatePkg('overlap-same-B:rpm=1.0') assert(os.path.exists(self.rootDir + '/A-1')) assert(os.path.exists(self.rootDir + '/B-1')) self.checkOwners('/file', [ osA1, osB1 ]) self.erasePkg(self.rootDir, 'overlap-same-B:rpm') assert(os.path.exists(self.rootDir + '/A-1')) assert(os.path.exists(self.rootDir + '/file')) self.checkOwners('/file', [ osA1 ]) self.rollback(2) self.checkOwners('/file', [ osA1, osB1 ]) self.rollback(1) self.checkOwners('/file', [ osA1 ]) @conary_test.rpm def test04_DirectoryPreexisting(self): self.addRPMComponent("simple:rpm=1.0", 'simple-1.0-1.i386.rpm') os.mkdir(self.rootDir + '/dir') self.updatePkg('simple:rpm') assert(os.path.exists(self.rootDir + '/normal')) @conary_test.rpm def test05_NoJobSplitting(self): self.addRPMComponent("simple:rpm=1.0", 'simple-1.0-1.i386.rpm') self.addRPMComponent("ownerships:rpm=1.0", 'ownerships-1.0-1.i386.rpm') try: old = self.cfg.updateThreshold self.cfg.updateThreshold = 1 rc, txt = self.captureOutput(self.updatePkg, [ 'simple:rpm', 'ownerships:rpm' ], raiseError=True, info=True) # if job splitting happens you get "Job 1 of 2" here because of the # small updateThreashold self.assertEquals(txt, ' Install ownerships:rpm=1.0-1-1\n' ' Install simple:rpm=1.0-1-1\n') # make sure having a critical update doesn't make the splitting # break criticalUpdateInfo = updatecmd.CriticalUpdateInfo() criticalUpdateInfo.setCriticalTroveRegexps(['simple:rpm']) itemsList = [ ('simple:rpm', (None, None), (None, None), True), ('ownerships:rpm', (None, None), (None, None), True), ] client = conaryclient.ConaryClient(self.cfg) updJob = client.newUpdateJob() client.prepareUpdateJob(updJob, itemsList, migrate=True, criticalUpdateInfo = criticalUpdateInfo) finally: self.cfg.updateThreshold = old # info components should get split out of course CNY-3387 self.addComponent("info-disk:user=1.0") rc, txt = self.captureOutput(self.updatePkg, [ 'simple:rpm', 'info-disk:user' ], info = True ) self.assertEquals(txt, 'Job 1 of 2:\n' ' Install info-disk:user=1.0-1-1\n' 'Job 2 of 2:\n' ' Install simple:rpm=1.0-1-1\n') @conary_test.rpm def test06_GhostPreexisting(self): self.addRPMComponent("ghost:rpm=1.0", 'ghost-1.0-1.i386.rpm') os.mkdir(self.rootDir + '/foo') self.writeFile(self.rootDir + '/foo/ghost', 'orig contents') rc, str = self.captureOutput(self.updatePkg, 'ghost:rpm') assert(not str) self.verifyFile(self.rootDir + '/foo/ghost', 'orig contents') @conary_test.rpm def test07_BadRpmCapsule(self): cmp = self.addRPMComponent("ghost:rpm=1.0", 'epoch-1.0-1.i386.rpm') repos = self.openRepository() orig = self.workDir + '/ghost.ccs' modified = self.workDir + '/ghost-new.ccs' repos.createChangeSetFile([ (cmp.getName(), (None, None), cmp.getNameVersionFlavor()[1:], True) ], orig) fc = filecontainer.FileContainer( util.ExtendedFile(orig, buffering = False)) newFc = filecontainer.FileContainer( util.ExtendedFile(modified, "w", buffering = False)) # CONARYCHANGESET (name, tag, contents) = fc.getNextFile() newFc.addFile(name, filecontents.FromFile(contents), tag, precompressed = True) # the RPM (name, tag, contents) = fc.getNextFile() contents = filecontents.FromString("busted!") newFc.addFile(name, contents, tag) cs = changeset.ChangeSetFromFile(modified) # this throws away the output about the install failing self.assertRaises(files.Sha1Exception, self.captureOutput, self.updatePkg, self.rootDir, cs) @conary_test.rpm @testhelp.context('sysmodel', 'rollback') def test08_OverlapConflict(self): osA1 = self.addRPMComponent("overlap-same-A:rpm=1.0", 'overlap-same-A-1.0-1.i386.rpm') self.addCollection('overlap-same-A', '1.0', [ ':rpm' ]) osB1 = self.addRPMComponent("overlap-conflict:rpm", 'overlap-conflict-1.0-1.i386.rpm') self.addCollection('overlap-conflict', '1.0', [ ':rpm' ]) self.updatePkg('overlap-same-A:rpm=1.0') self.assertRaises(update.UpdateError, self.updatePkg, 'overlap-conflict:rpm=1.0', raiseError=True) self.updatePkg('overlap-conflict:rpm=1.0', replaceFiles = True) self.checkOwners('/file', [ osB1 ]) self.rollback(1) self.checkOwners('/file', [ osA1 ]) # now test that allowing overlaps via groups pathConflicts is OK # in system model self.addCollection('group-dist', '1.0', [ ('overlap-same-A:rpm', '1.0'), ('overlap-conflict:rpm', '1.0')], pathConflicts=['/file']) root = self.cfg.root util.mkdirChain(root+'/etc/conary') file(root+'/etc/conary/system-model', 'w').write( 'install group-dist=localhost@rpl:linux/1.0\n') model = cml.CML(self.cfg) modelFile = systemmodel.SystemModelFile(model) updatecmd.doModelUpdate(self.cfg, model, modelFile, [], keepExisting=True) self.resetRoot() self.updatePkg(['overlap-same-A:rpm', 'overlap-conflict:rpm=1.0'], replaceFiles = True) self.rollback(0) @conary_test.rpm def test08_CapsuleTroveDisplay(self): cmp = self.addRPMComponent("simple:rpm=1.0", 'simple-1.0-1.i386.rpm') repos = self.openRepository() cs = repos.createChangeSet([ (cmp.getName(), (None, None), cmp.getNameVersionFlavor()[1:], True) ]) db = self.openDatabase() self.updatePkg('simple:rpm') for method, args in [ (showchangeset.displayChangeSet, (None, cs, None, self.cfg) ), (queryrep.displayTroves, (self.cfg, [ "simple:rpm" ]) ), (query.displayTroves, (db, self.cfg, [ "simple:rpm" ]) ) ]: rc, res = self.captureOutput(method, ls = True, *args) self.assertEquals(res, '/config\n/dir\n/normal\n') rc, res = self.captureOutput(method, capsules = True, ls = True, *args) self.assertEquals(res, 'simple-1.0-1.i386.rpm\n') @conary_test.rpm def test09_CapsuleInstallFlags(self): # test some random flags, like --test, --justdb, and # --replace-unmanaged-files cmp = self.addRPMComponent("simple:rpm=1.0", 'simple-1.0-1.i386.rpm') self.updatePkg('simple:rpm', test = True) assert(not os.path.exists(self.rootDir + '/normal')) assert(not self.owners('/normal')) str = os.popen('rpm --root %s -qa' % self.rootDir).readlines() assert(not str) self.updatePkg('simple:rpm', justDatabase = True) assert(len(self.owners('/normal')) == 1) assert(not os.path.exists(self.rootDir + '/normal')) str = os.popen('rpm --root %s -qa' % self.rootDir).readlines() self.assertEquals(str, [ 'simple-1.0-1.i386\n' ]) rc, str = self.captureOutput(self.erasePkg, self.rootDir, 'simple:rpm', justDatabase = True) self.assertEquals(str, 'warning: cannot remove /normal: No such file or directory\n' 'warning: cannot remove /config: No such file or directory\n' 'warning: cannot remove /dir: No such file or directory\n') str = os.popen('rpm --root %s -qa' % self.rootDir).readlines() self.assertEquals(str, []) assert(not self.owners('/normal')) self.writeFile(self.rootDir + '/normal', 'placeholder') rc, str = self.captureOutput(self.updatePkg, 'simple:rpm') self.assertEquals(str, 'error: changeset cannot be applied:\n' 'applying update would cause errors:\n' '/normal is in the way of a newly created file in ' 'simple:rpm=/localhost@rpl:linux/1.0-1-1[]\n') rc, str = self.captureOutput(self.updatePkg, 'simple:rpm', replaceUnmanagedFiles = True) self.assertEquals(str, '') self.verifyFile(self.rootDir + '/normal', 'normal\n') self.resetRoot() self.updatePkg('simple:rpm', justDatabase = True, skipCapsuleOps = True) assert(len(self.owners('/normal')) == 1) assert(not os.path.exists(self.rootDir + '/normal')) str = os.popen('rpm --root %s -qa' % self.rootDir).readlines() self.assertEquals(str, [ ]) # syncCapsuleDatabase would helpfully erase the trove before we get a # chance to do the same thing, so turn it off for this test self.cfg.syncCapsuleDatabase = 'false' try: rc, str = self.captureOutput(self.erasePkg, self.rootDir, 'simple:rpm', justDatabase = True, skipCapsuleOps = True) finally: self.cfg.resetToDefault('syncCapsuleDatabase') self.assertEquals(str, 'warning: cannot remove /normal: No such file or directory\n' 'warning: cannot remove /config: No such file or directory\n' 'warning: cannot remove /dir: No such file or directory\n') str = os.popen('rpm --root %s -qa' % self.rootDir).readlines() self.assertEquals(str, []) assert(not self.owners('/normal')) @conary_test.rpm def test10_UnchangedRPM(self): cmp = self.addRPMComponent("simple:rpm=1.0-1-1", 'simple-1.0-1.i386.rpm') cmp = self.addRPMComponent("simple:rpm=1.0-1-2", 'simple-1.0-1.i386.rpm') self.updatePkg('simple:rpm=1.0-1-1') self.updatePkg('simple:rpm=1.0-1-2') # this makes sure the right version is installed self.erasePkg(self.rootDir, 'simple:rpm=1.0-1-2') @conary_test.rpm def test11_UnchangedUpdate(self): # CNY-3335 simple10 = self.addRPMComponent("simple:rpm=1.0-1-1", 'simple-1.0-1.i386.rpm') simple101 = self.addRPMComponent("simple:rpm=1.0.1-1-1", 'simple-1.0.1-1.i386.rpm', versus = simple10) self.updatePkg('simple:rpm=1.0-1-1') self.updatePkg('simple:rpm=1.0.1-1-1') @conary_test.rpm def test_unchangedFileid(self): # CNY-3719 simple10 = self.addRPMComponent("simple:rpm=1.0-1-1", 'simple-1.0-1.i386.rpm') # Commit a new version so all the file versions are new simple11 = self.addRPMComponent("simple:rpm=1.1-1-1", 'simple-1.1-1.i386.rpm', versus = simple10) # Now go back to the old fileids, the filevers will be new again simple101 = self.addRPMComponent("simple:rpm=1.0.1-1-1", 'simple-1.0.1-1.i386.rpm', versus = simple11) self.updatePkg('simple:rpm=1.0-1-1') self.updatePkg('simple:rpm=1.0.1-1-1') @conary_test.rpm def test12_TroveZeroEpoch(self): t = trove.Trove('foo:continer', self.v1, deps.Flavor()) t.addFile(self.id1, '/1', self.v1, self.fid1) t.addFile(self.id2, '/2', self.v1, self.fid2) h = { rpmhelper.NAME : 'foorpm', rpmhelper.VERSION : '1.0', rpmhelper.RELEASE : '1', rpmhelper.ARCH : 'i386', rpmhelper.EPOCH : [ 0 ] } t.addRpmCapsule('foo.rpm', self.v1, self.fid5, h) self.assertEqual(t.troveInfo.capsule.rpm.name(), 'foorpm') self.assertEqual(t.troveInfo.capsule.rpm.epoch(), 0) self.assertEqual(t.troveInfo.capsule.rpm.version(), '1.0') self.assertEqual(t.troveInfo.capsule.rpm.release(), '1') self.assertEqual(t.troveInfo.capsule.rpm.arch(), 'i386') @conary_test.rpm def testChangesetExploder(self): simple10 = self.addRPMComponent("simple:rpm=1.0-1-1", 'simple-1.0-1.i386.rpm') repos = self.openRepository() cs = repos.createChangeSet([ (simple10.getName(), (None, None), simple10.getNameVersionFlavor()[1:], True) ]) changeset.ChangesetExploder(cs, self.rootDir) assert(os.path.isdir(self.rootDir + '/dir')) self.assertEquals( os.stat(self.rootDir + '/normal').st_size, 7) @conary_test.rpm @testhelp.context('rollback') def testRpmFileColoring(self): if os.uname()[4] != 'x86_64': # this test only works on x86_64 platforms return i386md5 = '0fc54eafb8daf886ff7d43c4448acc71' x64md5 = '4cb13908ca1d7989be493c581a6fa1d3' oldtrv = self.addRPMComponent("tmpwatch:rpm=0.1-1-1", 'tmpwatch-2.9.1-1.i386.rpm') i386trv = self.addRPMComponent("tmpwatch:rpm=1.0-1-1", 'tmpwatch-2.9.7-1.1.el5.2.i386.rpm') x64trv = self.addRPMComponent("tmpwatch:rpm=2.0-1-1", 'tmpwatch-2.9.7-1.1.el5.2.x86_64.rpm') self.updatePkg('tmpwatch:rpm=1.0-1-1') self.checkMd5('/usr/sbin/tmpwatch', i386md5) self.checkOwners('/usr/sbin/tmpwatch', [ i386trv ]) self.updatePkg('tmpwatch:rpm=2.0-1-1', keepExisting = True) self.checkMd5('/usr/sbin/tmpwatch', x64md5) self.checkOwners('/usr/sbin/tmpwatch', [ x64trv ]) self.erasePkg(self.rootDir, 'tmpwatch:rpm=2.0-1-1') # it's a shame we don't restore the file here assert(not os.path.exists(self.rootDir + '/usr/sbin/tmpwatch')) self.rollback(2) self.checkMd5('/usr/sbin/tmpwatch', x64md5) self.rollback(1) self.checkMd5('/usr/sbin/tmpwatch', i386md5) self.checkOwners('/usr/sbin/tmpwatch', [ i386trv ]) self.resetRoot() self.updatePkg('tmpwatch:rpm=2.0-1-1') self.checkMd5('/usr/sbin/tmpwatch', x64md5) self.checkOwners('/usr/sbin/tmpwatch', [ x64trv ]) self.updatePkg('tmpwatch:rpm=1.0-1-1', keepExisting = True) self.checkMd5('/usr/sbin/tmpwatch', x64md5) self.checkOwners('/usr/sbin/tmpwatch', [ x64trv ]) self.erasePkg(self.rootDir, 'tmpwatch:rpm=1.0-1-1') self.checkMd5('/usr/sbin/tmpwatch', x64md5) self.resetRoot() self.updatePkg([ 'tmpwatch:rpm=1.0-1-1', 'tmpwatch:rpm=2.0-1-1' ]) self.checkMd5('/usr/sbin/tmpwatch', x64md5) self.checkOwners('/usr/sbin/tmpwatch', [ x64trv ]) # this still causes conflicts rc, str = self.captureOutput(self.updatePkg, 'tmpwatch:rpm=0.1') assert('conflicts' in str) @conary_test.rpm def testFileColorUsedByScript(self): """ Post script references a file that is being "shared" in the same job @tests: CNY-3884 """ if os.uname()[4] != 'x86_64': # this test only works on x86_64 platforms return i386md5 = '0fc54eafb8daf886ff7d43c4448acc71' x64md5 = '4cb13908ca1d7989be493c581a6fa1d3' i386trv = self.addRPMComponent("tmpwatch:rpm=1.0-1-1", 'tmpwatch-2.9.7-1.1.el5.2.i386.rpm') x64trv = self.addRPMComponent("tmpwatch:rpm=2.0-1-1", 'tmpwatch-2.9.7-1.1.el5.2.x86_64.rpm') consumer = self.addRPMComponent('usetmpwatch:rpm=1.0-1-1', 'usetmpwatch-1.0-1.x86_64.rpm') self.updatePkg('tmpwatch:rpm=2.0-1-1') self.checkMd5('/usr/sbin/tmpwatch', x64md5) self.checkOwners('/usr/sbin/tmpwatch', [ x64trv ]) rc, out = self.captureOutput(self.updatePkg, ['tmpwatch:rpm=1.0-1-1', 'usetmpwatch:rpm'], keepExisting=True) self.checkMd5('/usr/sbin/tmpwatch', x64md5) self.checkOwners('/usr/sbin/tmpwatch', [ x64trv ]) self.assertEqual(out, 'PRESENT\n') @conary_test.rpm @testhelp.context('rollback') def test14_testRpmSharedHardLinks(self): # we build fro msource here rather than use addRPMComponent to get # the hard links right recipestr1 = r""" class HardLinks(CapsuleRecipe): name = 'hardlinkconflict' version = '%s' clearBuildReqs() def setup(r): r.addCapsule('%s') """ built, d = self.buildRecipe( recipestr1 % ('1.0_1', 'hardlinkconflict-1.0-1.x86_64.rpm'), "HardLinks") built, d = self.buildRecipe( recipestr1 % ('1.0_2', 'hardlinkconflict-1.0-2.x86_64.rpm'), "HardLinks") self.updatePkg('hardlinkconflict=1.0_1') self.updatePkg('hardlinkconflict=1.0_2', keepExisting = True) assert(len(self.owners('/foo')) == 2) self.erasePkg(self.rootDir, 'hardlinkconflict=1.0_2') assert(len(self.owners('/foo')) == 1) self.resetRoot() self.updatePkg([ 'hardlinkconflict=1.0_1', 'hardlinkconflict=1.0_2' ]) assert(len(self.owners('/foo')) == 2) self.erasePkg(self.rootDir, 'hardlinkconflict=1.0_2') assert(len(self.owners('/foo')) == 1) @conary_test.rpm def test15_SetupHandling(self): oldTrv = self.addRPMComponent("setup:rpm=0.1-1-1", 'setup-2.5.58-7.el5.noarch.rpm') self.resetRoot() util.mkdirChain(self.rootDir + '/etc') self.writeFile(self.rootDir + '/etc/passwd', "passwd junk\n" "root:wrong rootuser\n") self.writeFile(self.rootDir + '/etc/group', "group junk\n" "root:wrong root group\n") self.updatePkg('setup:rpm', replaceFiles = True) p = open(self.rootDir + '/etc/passwd').readlines() self.assertEquals(p[0], 'root:*:0:0:root:/root:/bin/bash\n') self.assertEquals(p[-1], 'passwd junk\n') assert(not os.path.exists(self.rootDir + '/etc/passwd.rpmnew')) p = open(self.rootDir + '/etc/group').readlines() self.assertEquals(p[0], 'root::0:root\n') self.assertEquals(p[-1], 'group junk\n') assert(not os.path.exists(self.rootDir + '/etc/group.rpmnew')) @conary_test.rpm def testScriptFailures(self): 'test what happens when RPM scripts fail' # CNY-3454 f = self.addRPMComponent('aaa_first:rpm=1.0-1-1', 'aaa_first-1.0-1.noarch.rpm') f = self.addRPMComponent('failpost:rpm=1.0-1-1', 'failpost-1.0-1.noarch.rpm') f = self.addRPMComponent('failpostun:rpm=1.0-1-1', 'failpostun-1.0-1.noarch.rpm') f = self.addRPMComponent('failpre:rpm=1.0-1-1', 'failpre-1.0-1.noarch.rpm') f = self.addRPMComponent('failpreun:rpm=1.0-1-1', 'failpreun-1.0-1.noarch.rpm') f = self.addRPMComponent('zzz_last:rpm=1.0-1-1', 'zzz_last-1.0-1.noarch.rpm') f == f self.updatePkg('aaa_first:rpm=1.0-1-1') self.checkOrdering('aaa_first-1.0-1.noarch') self.verifyFile(self.rootDir + '/dummy/aaa_first') util.mkdirChain(self.rootDir+'/var/tmp') rc, str = self.captureOutput(self.updatePkg, 'failpost:rpm=1.0-1-1') self.assertEquals(str, 'warning: %post(failpost-1.0-1.noarch) scriptlet failed, exit status 127\n') self.checkOrdering('failpost-1.0-1.noarch') self.assertEquals(rc, None) self.verifyFile(self.rootDir + '/dummy/file') self.updatePkg('zzz_last:rpm=1.0-1-1') self.checkOrdering('zzz_last-1.0-1.noarch') self.verifyFile(self.rootDir + '/dummy/zzz_last') self.resetRoot(); util.mkdirChain(self.rootDir+'/var/tmp') rc, str = self.captureOutput(self.updatePkg, ['aaa_first:rpm=1.0-1-1', 'failpost:rpm=1.0-1-1', 'zzz_last:rpm=1.0-1-1']) self.assertEquals(str, 'warning: %post(failpost-1.0-1.noarch) scriptlet failed, exit status 127\n') self.assertEquals(rc, None) self.checkOrdering('aaa_first-1.0-1.noarch' ' failpost-1.0-1.noarch' ' zzz_last-1.0-1.noarch') self.verifyFile(self.rootDir + '/dummy/aaa_first') self.verifyFile(self.rootDir + '/dummy/file') self.verifyFile(self.rootDir + '/dummy/zzz_last') self.resetRoot(); util.mkdirChain(self.rootDir+'/var/tmp') self.updatePkg(['aaa_first:rpm=1.0-1-1', 'failpostun:rpm=1.0-1-1', 'zzz_last:rpm=1.0-1-1']) self.verifyFile(self.rootDir + '/dummy/aaa_first') self.verifyFile(self.rootDir + '/dummy/file') self.checkOrdering('aaa_first-1.0-1.noarch' ' failpostun-1.0-1.noarch' ' zzz_last-1.0-1.noarch') rc, str = self.captureOutput(self.erasePkg, self.rootDir, 'failpostun:rpm=1.0-1-1') self.assertEquals(str, 'warning: %postun(failpostun-1.0-1.noarch) scriptlet failed, exit status 127\n') self.verifyNoFile(self.rootDir + '/dummy/file') self.verifyFile(self.rootDir + '/dummy/zzz_last') self.resetRoot(); util.mkdirChain(self.rootDir+'/var/tmp') rc, str = self.captureOutput(self.updatePkg, ['aaa_first:rpm=1.0-1-1', 'failpre:rpm=1.0-1-1', 'zzz_last:rpm=1.0-1-1']) self.assertEquals(str, '\n'.join(( 'error: %pre(failpre-1.0-1.noarch) scriptlet failed, exit status 127', 'error: install: %pre scriptlet failed (2), skipping failpre-1.0-1', 'error: RPM failed to install requested packages: failpre-1.0-1.noarch', ''))) self.assertEquals(rc, None) self.checkOrdering('aaa_first-1.0-1.noarch' ' failpre-1.0-1.noarch' ' zzz_last-1.0-1.noarch') self.verifyFile(self.rootDir + '/dummy/aaa_first') self.verifyNoFile(self.rootDir + '/dummy/file') self.verifyFile(self.rootDir + '/dummy/zzz_last') self.resetRoot(); util.mkdirChain(self.rootDir+'/var/tmp') rc, str = self.captureOutput(self.updatePkg, ['aaa_first:rpm=1.0-1-1', 'failpreun:rpm=1.0-1-1', 'zzz_last:rpm=1.0-1-1']) self.assertEquals(rc, None) self.assertEquals(str, '') self.checkOrdering('aaa_first-1.0-1.noarch' ' failpreun-1.0-1.noarch' ' zzz_last-1.0-1.noarch') self.verifyFile(self.rootDir + '/dummy/aaa_first') self.verifyFile(self.rootDir + '/dummy/file') self.verifyFile(self.rootDir + '/dummy/zzz_last') rc, str = self.captureOutput(self.erasePkg, self.rootDir, 'failpreun:rpm=1.0-1-1') self.assertEquals(str, 'error: %preun(failpreun-1.0-1.noarch) scriptlet failed, exit status 127\n') self.verifyNoFile(self.rootDir + '/dummy/file') @conary_test.rpm def testNonRootUnpackFailures(self): 'test what happens when RPM unpack fails as non-root' # CNY-3462 f = self.addRPMComponent('aaa_first:rpm=1.0-1-1', 'aaa_first-1.0-1.noarch.rpm') f = self.addRPMComponent('dev:rpm=1.0-1-1', 'dev-1.0-1.noarch.rpm') rc, str = self.captureOutput(self.updatePkg, ['aaa_first:rpm=1.0-1-1', 'dev:rpm=1.0-1-1']) warning = str.strip().split('\n')[-1] self.assertEquals(warning, 'warning: RPM failed to unpack dev-1.0-1.noarch') self.verifyFile(self.rootDir + '/dummy/aaa_first') @conary_test.rpm def testDuplicateRpms(self): # CNY-3470 v1 = self.addRPMComponent("simple:rpm=1.0-1", 'simple-1.0-1.i386.rpm') v2 = self.addRPMComponent("simple:rpm=1.0-2", 'simple-1.0-1.i386.rpm') self.updatePkg('simple:rpm=1.0-1') self.updatePkg('simple:rpm=1.0-2', keepExisting = True) self.erasePkg(self.rootDir, 'simple:rpm=1.0-1') self.erasePkg(self.rootDir, 'simple:rpm=1.0-2') self.updatePkg('simple:rpm=1.0-1') self.updatePkg('simple:rpm=1.0-2', keepExisting = True) self.erasePkg(self.rootDir, [ 'simple:rpm=1.0-1', 'simple:rpm=1.0-2' ]) self.updatePkg('simple:rpm=1.0-1') self.updatePkg('simple:rpm=1.0-2') self.erasePkg(self.rootDir, 'simple:rpm=1.0-2') @conary_test.rpm def testNetSharedPath(self): # CNY-3503 p = self.addRPMComponent('netshared:rpm=1.0-1', 'netshared-1.0-1.noarch.rpm') util.mkdirChain(self.cfg.root + '/etc/rpm/') #self.updatePkg('netshared:rpm=1.0-1') #self.verifyFile(self.rootDir + '/local/shouldexist') ##self.verifyFile(self.rootDir + '/excluded/shouldnotexist') self.resetRoot() util.mkdirChain(self.cfg.root + '/etc/rpm/') util.mkdirChain(self.cfg.root + '/excluded') self.writeFile(self.cfg.root + '/excluded/shouldnotexist', 'unmanaged') # inside the method to let @conary_test.rpm keep the import conditional import rpm rpm.addMacro('_netsharedpath', '/excluded:/usr/local') try: self.updatePkg('netshared:rpm=1.0-1') finally: rpm.delMacro('_netsharedpath') self.verifyFile(self.rootDir + '/local/shouldexist') self.verifyFile(self.rootDir + '/excluded/shouldnotexist', 'unmanaged') self.erasePkg(self.rootDir, 'netshared:rpm') @conary_test.rpm def testFileOverrides(self): # CNY-3586; CNY-3590 # Unfortunately we can't use addRPMComponent, we need the policy to # mark files as being overwritten recipe = r""" class TestPackage(CapsuleRecipe): name = 'with-config-special' version = '0.1' clearBuildReqs() def setup(r): r.addCapsule('with-config-special-0.3-1.noarch.rpm') r.Create('/usr/share/with-config-special.txt', contents='some other content\n', mode=0755) r.Create('/usr/share/new-content.txt', contents='some new content\n', mode=0644) """ pkgname = 'with-config-special' self.makeSourceTrove(pkgname, recipe) built = self.cookFromRepository(pkgname) nvf = built[0] self.updatePkg('%s=0.1-1-1' % pkgname) self.verifyFile(self.rootDir + '/usr/share/with-config-special.txt', 'Some extra data\n', perms=0644) # File additions should be honored self.verifyFile(self.rootDir + '/usr/share/new-content.txt', 'some new content\n', perms=0644) @conary_test.rpm def testFileModeChanges(self): # CNY-3590 # Unfortunately we can't use addRPMComponent, we need the policy to # mark files as being overwritten recipe = r""" class TestPackage(CapsuleRecipe): name = 'with-config-special' version = '0.1' clearBuildReqs() def setup(r): r.addCapsule('with-config-special-0.3-1.noarch.rpm') r.SetModes('/usr/share/with-config-special.txt', 0755) """ pkgname = 'with-config-special' self.makeSourceTrove(pkgname, recipe) built = self.cookFromRepository(pkgname) nvf = built[0] self.updatePkg('%s=0.1-1-1' % pkgname) # Make sure we DO NOT change the mode here (see CNY-3590) self.verifyFile(self.rootDir + '/usr/share/with-config-special.txt', 'Some extra data\n', perms=0644) @conary_test.rpm def testUnchangedRPM(self): cmp1 = self.addRPMComponent("simple:rpm=1.0-1-1", 'simple-1.0-1.i386.rpm') self.updatePkg('simple:rpm') cmp1 = self.addRPMComponent("simple:rpm=1.0-1-2", 'simple-1.0-1.i386.rpm') self.updatePkg('simple:rpm') @conary_test.rpm @testhelp.context('rollback') def testFileTypeChange(self): self.addRPMComponent("file-type-change:rpm=1-1-1", 'file-type-change-1-1.i386.rpm') self.addRPMComponent("file-type-change:rpm=2-1-1", 'file-type-change-2-1.i386.rpm') self.updatePkg('file-type-change:rpm=1') self.assertEquals(os.readlink(self.rootDir + '/test'), 'foo') self.updatePkg('file-type-change:rpm=2') self.verifyFile(self.rootDir + '/test', '') self.rollback(1) self.assertEquals(os.readlink(self.rootDir + '/test'), 'foo') @conary_test.rpm def testChangingSharedUpdateRPM(self): 'CNY-3620' if 'x86_64' not in str(self.cfg.buildFlavor): raise testhelp.SkipTestException('Skip test on x86 arch') # avoid needing to flavor using names su1032 = self.addRPMComponent('shared-update-32:rpm=1.0', 'shared-update-1.0-1.i386.rpm') su1064 = self.addRPMComponent('shared-update-64:rpm=1.0', 'shared-update-1.0-1.x86_64.rpm') su1132 = self.addRPMComponent('shared-update-32:rpm=1.1', 'shared-update-1.1-1.i386.rpm', versus=su1032) su1164 = self.addRPMComponent('shared-update-64:rpm=1.1', 'shared-update-1.1-1.x86_64.rpm', versus=su1064) self.updatePkg(['shared-update-32:rpm=1.0', 'shared-update-64:rpm=1.0']) self.verifyFile(self.rootDir + '/usr/share/test', 'contents1.0\n') self.updatePkg(['shared-update-32:rpm=1.1', 'shared-update-64:rpm=1.1']) self.verifyFile(self.rootDir + '/usr/share/test', 'contents1.1\n') @conary_test.rpm def testRPMJobOrdering(self): """ Ensure that introducing a native conary package in the dependency chain between two encapsuled RPM packages causes Conary to split the three packages into separate jobs. foo:rpm -> bar:runtime -> baz:rpm """ self.addRPMComponent('baz:rpm=1.0', 'simple-1.0-1.i386.rpm') self.addComponent('bar:runtime=1.0', requires=deps.parseDep('trove: baz:rpm')) self.addRPMComponent('foo:rpm=1.0', 'ownerships-1.0-1.i386.rpm', requires=deps.parseDep('trove: bar:runtime')) rc, txt = self.captureOutput(self.updatePkg, [ 'foo:rpm', ], resolve=True, raiseError=True, info=True) self.assertEquals(txt, 'Job 1 of 3:\n' ' Install baz:rpm=1.0-1-1\n' 'Job 2 of 3:\n' ' Install bar:runtime=1.0-1-1\n' 'Job 3 of 3:\n' ' Install foo:rpm=1.0-1-1\n') @conary_test.rpm @testhelp.context('rollback') def testCapsuleLocalRollbacks(self): try: self.cfg.localRollbacks = True c = self.addRPMComponent("simple:rpm=1.0", 'simple-1.0-1.i386.rpm') csPath = self.workDir + '/simple.ccs' repos = self.getRepositoryClient() repos.createChangeSetFile([ (c.getName(), ( None, None ), ( c.getVersion(), c.getFlavor() ), True ) ] , csPath) file("/tmp/foo", "w").write(c.freeze()) self.addRPMComponent("simple:rpm=1.1", 'simple-1.1-1.i386.rpm') self.updatePkg('simple:rpm=1.0') testPath = os.path.join(self.rootDir, 'normal') self.verifyFile(testPath, 'normal\n') f = file(testPath, "w") f.write("rollback check") self.updatePkg('simple:rpm=1.1') self.verifyFile(testPath, 'changed-normal\n') e = self.assertRaises(errors.MissingRollbackCapsule, self.rollback, 1) assert('simple-1.0-1.i386.rpm' in str(e)) self.rollback(1, capsuleChangesets = [ csPath ] ) f.write("rollback check") self.updatePkg('simple:rpm=1.1') self.verifyFile(testPath, 'changed-normal\n') self.writeFile(self.workDir + '/other', 'some file') self.rollback(1, capsuleChangesets = [ self.workDir ] ) f.write("rollback check") self.erasePkg(self.rootDir, 'simple:rpm') self.rollback(1, capsuleChangesets = [ self.workDir ] ) finally: self.cfg.localRollbacks = False def checkMd5(self, path, md5): d = md5String(open(self.rootDir + path).read()) self.assertEquals(md5ToString(d), md5) def owners(self, path): db = self.openDatabase() return set( x[0:3] for x in db.iterFindPathReferences( path, justPresent = True) ) def checkOrdering(self, troves): lastOrder = [x[22:].strip() for x in file(self.rootDir + '/var/log/conary').readlines() if 'RPM install order' in x][-1] self.assertEquals(lastOrder.split(': ', 1)[1], troves) def checkOwners(self, path, troves): assert(self.owners(path) == set( x.getNameVersionFlavor() for x in troves )) @conary_test.rpm def testEncapToNative(self): """ Update from encapsulated package to native package with the same contents and modes, ensure that the file does not disappear. @tests: CNY-3762 """ self.addRPMComponent('foo:rpm=1.0', 'simple-1.0-1.i386.rpm') self.updatePkg('foo:rpm', raiseError=True) recipe = r""" class TestPackage(CapsuleRecipe): name = 'foo' version = '2.0' clearBuildReqs() def setup(r): r.addArchive('simple-1.0-1.i386.rpm', dir='/', preserveOwnership=True) """ src = self.makeSourceTrove('foo', recipe) self.cookFromRepository('foo')[0] self.updatePkg(['-foo:rpm', 'foo:runtime'], depCheck=False, raiseError=True) path = os.path.join(self.rootDir, 'normal') self.assertEqual(os.stat(path).st_size, 7) @conary_test.rpm def testEncapToNativeSloppy(self): """ Update from encapsulated package to native package with the same contents but different modes, ensure that the file does not disappear. @tests: CNY-3762 """ self.addRPMComponent('foo:rpm=1.0', 'simple-1.0-1.i386.rpm') self.updatePkg('foo:rpm', raiseError=True) recipe = r""" class TestPackage(CapsuleRecipe): name = 'foo' version = '2.0' clearBuildReqs() def setup(r): r.addArchive('simple-1.0-1.i386.rpm', dir='/') r.Ownership('nobody', 'nobody', '.*') r.SetModes('/dir', 0700) r.SetModes('/normal', 0600) """ src = self.makeSourceTrove('foo', recipe) self.cookFromRepository('foo')[0] self.updatePkg(['-foo:rpm', 'foo:runtime'], depCheck=False, raiseError=True) path = os.path.join(self.rootDir, 'normal') self.assertEqual(os.stat(path).st_size, 7) self.assertEqual(oct(os.stat(path).st_mode), '0100600') path = os.path.join(self.rootDir, 'dir') self.assertEqual(oct(os.stat(path).st_mode), '040700') @conary_test.rpm def testEncapToNativeChanged(self): """ Update from encapsulated to native package with some different contents @tests: CNY-3762 """ # Intentionally put a trailing slash on the root dir to tickle bugs # where a path not created with joinPaths() might cause mismatches. Of # course the most common real-world case, root = '/', has a "trailing" # slash, whereas usually in the testsuite a chroot is used and no # trailing slash is present. self.rootDir += '/' self.addRPMComponent('foo:rpm=1.0', 'simple-1.0-1.i386.rpm') self.updatePkg('foo:rpm', raiseError=True) recipe = r""" class TestPackage(CapsuleRecipe): name = 'foo' version = '2.0' clearBuildReqs() def setup(r): r.addArchive('simple-1.0-1.i386.rpm', dir='/') r.Ownership('nobody', 'nobody', '.*') r.SetModes('/dir', 0700) r.Create('/normal', contents='different stuff\n', mode=0600) """ src = self.makeSourceTrove('foo', recipe) self.cookFromRepository('foo')[0] self.updatePkg(['-foo:rpm', 'foo:runtime'], depCheck=False, raiseError=True) path = os.path.join(self.rootDir, 'normal') self.assertEqual(os.stat(path).st_size, 16) self.assertEqual(oct(os.stat(path).st_mode), '0100600') path = os.path.join(self.rootDir, 'dir') self.assertEqual(oct(os.stat(path).st_mode), '040700') @conary_test.rpm def testUsrmoveUpdate(self): """ Update file from /sbin to /usr/sbin while /sbin is a symlink @tests: CNY-3885 """ os.makedirs(os.path.join(self.rootDir, 'usr/sbin')) os.symlink('usr/sbin', os.path.join(self.rootDir, 'sbin')) self.addRPMComponent('usrmove:rpm=1.0', 'usrmove-1.0-1.x86_64.rpm') self.updatePkg('usrmove:rpm', raiseError=True) self.addRPMComponent('usrmove:rpm=2.0', 'usrmove-2.0-1.x86_64.rpm') self.updatePkg('usrmove:rpm', raiseError=True) self.assertEqual(open(os.path.join(self.rootDir, 'usr/sbin/usrmove')).read(), '2.0\n')
def __thaw__(jobList): return [(x[0], (None, None), (versions.ThawVersion(x[1]), ThawFlavor(x[2])), x[3]) for x in jobList]
def __thaw__(tupList): return [(x[0], versions.ThawVersion(x[1]), ThawFlavor(x[2])) for x in tupList]
def _fromOtherTroveSpec(self, troveSpec): if not troveSpec: return n, v, f = conaryclient.cmdline.parseTroveSpec(troveSpec) self.trvOldVersion = versions.ThawVersion(v) self.trvOldFlavor = f
def __thaw__((n, v, f)): return (n, versions.ThawVersion(v), ThawFlavor(f))
def __thaw__(versionStr): return versions.ThawVersion(versionStr)
def getTrove(cu, roleIds, name, version, flavor, mkUrl = None, thisHost = None, displayFlavor = None, excludeCapsules = False): def buildTupleList(tuples, name, mkUrl = mkUrl): l = getattr(datamodel.SingleTrove, name)() for troveInfo in sorted(tuples.iter()): l.append(name = troveInfo.name(), version = troveInfo.version(), flavor = troveInfo.flavor(), mkUrl = mkUrl) return l def fileQuery(gfcu, filesInstanceId, dirName = None): # XXX restricing by dirName seems and obvious thing to do here, # but it actually slows things down?? # # the distinct here is unfortunate, but conary repositories had # a bug for about a year which caused it to store duplicate paths # if a path was committed for the first time duplicate times in # a single commit job gfcu.execute(""" SELECT DISTINCT dirName, basename, version, pathId, fileId FROM TroveFiles JOIN Versions USING (versionId) JOIN FileStreams ON (TroveFiles.streamId = FileStreams.streamId) JOIN FilePaths ON (TroveFiles.filePathId = FilePaths.filePathId) JOIN DirNames ON FilePaths.dirNameId = DirNames.dirNameId JOIN Basenames ON (FilePaths.baseNameId = Basenames.baseNameId) WHERE TroveFiles.instanceId = ? ORDER BY dirName, basename """, filesInstanceId) cu.execute(""" SELECT Instances.instanceId, Nodes.timeStamps FROM Instances JOIN Nodes USING (itemId, versionId) JOIN Items USING (itemId) JOIN Versions ON (Instances.versionId = Versions.versionId) JOIN Flavors ON (Instances.flavorId = Flavors.flavorId) JOIN UserGroupInstancesCache AS ugi ON (instances.instanceId = ugi.instanceId AND ugi.userGroupId in (%s)) WHERE item = ? AND version = ? AND flavor = ? """ % ",".join( str(x) for x in roleIds), name, version, deps.parseFlavor(flavor).freeze()) l = [ (x[0], x[1]) for x in cu ] if not l: return None instanceId, timeStamps = l[0] frzVer = versions.strToFrozen(version, timeStamps.split(":")) verobj = versions.ThawVersion(frzVer) tupleLists = [ ( trove._TROVEINFO_TAG_BUILDDEPS, 'builddeps' ), ( trove._TROVEINFO_TAG_POLICY_PROV, 'policyprovider' ), ( trove._TROVEINFO_TAG_LOADEDTROVES, 'loadedtroves' ), ( trove._TROVEINFO_TAG_COPIED_FROM, 'copiedfrom' ), ( trove._TROVEINFO_TAG_DERIVEDFROM, 'derivedfrom' ) ] cu.execute(""" SELECT infoType, data FROM TroveInfo WHERE instanceId = ? AND infoType IN (%s) """ % ",".join(str(x) for x in [ trove._TROVEINFO_TAG_SOURCENAME, trove._TROVEINFO_TAG_CLONEDFROM, trove._TROVEINFO_TAG_CLONEDFROMLIST, trove._TROVEINFO_TAG_BUILDTIME, trove._TROVEINFO_TAG_SIZE, trove._TROVEINFO_TAG_METADATA, trove._TROVEINFO_TAG_CAPSULE, ] + [ x[0] for x in tupleLists ] ), instanceId) troveInfo = {} for infoType, data in cu: data = cu.frombinary(data) infoClass = trove.TroveInfo.streamDict[infoType][1] troveInfo[infoType] = infoClass(data) kwargs = { 'name' : name, 'version' : verobj, 'flavor' : flavor } if displayFlavor is not None: kwargs['displayflavor'] = displayFlavor if trove._TROVEINFO_TAG_BUILDTIME in troveInfo: kwargs['buildtime'] = int(troveInfo[trove._TROVEINFO_TAG_BUILDTIME]()) if trove._TROVEINFO_TAG_SOURCENAME in troveInfo: kwargs['source'] = (troveInfo[trove._TROVEINFO_TAG_SOURCENAME](), verobj.getSourceVersion(), '') if trove._TROVEINFO_TAG_SIZE in troveInfo: kwargs['size'] = troveInfo[trove._TROVEINFO_TAG_SIZE]() if trove._TROVEINFO_TAG_METADATA in troveInfo: md = troveInfo[trove._TROVEINFO_TAG_METADATA].get() kwargs['shortdesc'] = md['shortDesc'] kwargs['longdesc'] = md['longDesc'] if md['licenses']: kwargs['license'] = [ x for x in md['licenses' ]] if md['crypto']: kwargs['crypto'] = [ x for x in md['crypto'] ] for (tag, tagName) in tupleLists: if tag in troveInfo: kwargs[tagName] = buildTupleList(troveInfo[tag], tagName, mkUrl = mkUrl) t = datamodel.SingleTrove(mkUrl = mkUrl, thisHost = thisHost, **kwargs) if trove._TROVEINFO_TAG_CLONEDFROMLIST in troveInfo: clonedFromList = troveInfo[trove._TROVEINFO_TAG_CLONEDFROMLIST] elif (trove._TROVEINFO_TAG_CLONEDFROM in troveInfo): clonedFromList = [ troveInfo[trove._TROVEINFO_TAG_CLONEDFROM]() ] else: clonedFromList = [] for ver in clonedFromList: t.addClonedFrom(name, ver, flavor, mkUrl = mkUrl) hasCapsule = False if trove._TROVEINFO_TAG_CAPSULE in troveInfo: if troveInfo[trove._TROVEINFO_TAG_CAPSULE].type(): hasCapsule = True fileQuery(cu, instanceId) for (dirName, baseName, fileVersion, pathId, fileId) in cu: dirName = cu.frombinary(dirName) baseName = cu.frombinary(baseName) if pathId == trove.CAPSULE_PATHID: isCapsule = 1 contentAvailable = not excludeCapsules else: isCapsule = None contentAvailable = not hasCapsule fileObj = datamodel.FileReference( path = os.path.join(dirName, baseName), version = fileVersion, pathId = md5ToString(cu.frombinary(pathId)), fileId = sha1ToString(cu.frombinary(fileId)), isCapsule = isCapsule, contentAvailable = contentAvailable, mkUrl = mkUrl, thisHost = thisHost) t.addFile(fileObj) cu.execute(""" SELECT item, version, flavor, TroveTroves.includedId, Nodes.timeStamps FROM TroveTroves JOIN Instances ON (Instances.instanceId = TroveTroves.includedId) JOIN Nodes USING (itemId, versionId) JOIN Items USING (itemId) JOIN Versions ON (Versions.versionId = Instances.versionId) JOIN Flavors ON (Flavors.flavorId = Instances.flavorId) WHERE TroveTroves.instanceId = ? AND (TroveTroves.flags & %d) = 0 ORDER BY item, version, flavor """ % schema.TROVE_TROVES_WEAKREF, instanceId) for (subName, subVersion, subFlavor, refInstanceId, subTS) in cu: subFlavor = str(deps.ThawFlavor(subFlavor)) frzVer = versions.strToFrozen(subVersion, [ x for x in subTS.split(":") ]) subV = versions.ThawVersion(frzVer) t.addReferencedTrove(subName, subV, subFlavor, mkUrl = mkUrl) # It would be far better to use file tags to identify these build # logs, but it's significantly slower as well because they're in # the file objects rather than the trove (and those file objects # could be stored on a different repository) if not subName.endswith(':debuginfo'): continue fileQuery(cu, refInstanceId, dirName = '/usr/src/debug/buildlogs') logHost = subV.getHost() for (dirName, baseName, fileVersion, pathId, fileId) in cu: if (dirName) != '/usr/src/debug/buildlogs': continue if baseName.endswith('-log.bz2'): t.setBuildLog(logHost, sha1ToString(fileId)) elif baseName.endswith('-xml.bz2'): t.setXMLBuildLog(logHost, sha1ToString(fileId)) return t
def searchNodes(cu, roleIds, label = None, mkUrl = None, filterSet = None, db = None, name = None, latest = 1): args = [] d = { 'labelCheck' : '', 'itemCheck' : '' } d['roleIds'] = ",".join( str(x) for x in roleIds) d['SOURCENAME'] = trove._TROVEINFO_TAG_SOURCENAME d['METADATA'] = trove._TROVEINFO_TAG_METADATA if label: d['labelCheck'] = "label = ? AND" args.append(label) if name: d['itemCheck'] = "item = ? AND" args.append(name) if latest: cu.execute(""" SELECT idTable.item, version, ts, finalTs, SourceNameTroveInfo.data, MetadataTroveInfo.data FROM (SELECT DISTINCT Items.item AS item, Nodes.versionId AS versionId, Nodes.timeStamps AS ts, Nodes.finalTimeStamp as finalTs, MIN(Instances.instanceId) AS instanceId FROM Labels JOIN LabelMap USING (labelId) JOIN LatestCache USING (itemId, branchId) JOIN Nodes USING (itemId, versionId) JOIN Instances USING (itemId, versionId) JOIN Items USING (itemId) WHERE %(labelCheck)s %(itemCheck)s LatestCache.latestType = 1 AND LatestCache.userGroupId in (%(roleIds)s) GROUP BY Items.item, Nodes.versionId, Nodes.timeStamps, Nodes.finalTimestamp) AS idTable JOIN Versions ON (idTable.versionId = Versions.versionId) LEFT OUTER JOIN TroveInfo AS SourceNameTroveInfo ON idTable.instanceId = SourceNameTroveInfo.instanceId AND SourceNameTroveInfo.infoType = %(SOURCENAME)d LEFT OUTER JOIN TroveInfo AS MetadataTroveInfo ON idTable.instanceId = MetadataTroveInfo.instanceId AND MetadataTroveInfo.infoType = %(METADATA)d """ % d, args) else: cu.execute(""" SELECT idTable.item, version, ts, finalTs, SourceNameTroveInfo.data, MetadataTroveInfo.data FROM (SELECT DISTINCT Items.item AS item, Nodes.versionId AS versionId, Nodes.timeStamps AS ts, Nodes.finalTimeStamp as finalTs, MIN(Instances.instanceId) AS instanceId FROM Labels JOIN LabelMap USING (labelId) JOIN Nodes USING (itemId, branchId) JOIN Instances USING (itemId, versionId) JOIN Items USING (itemId) JOIN usergroupinstancescache AS ugi ON Instances.instanceId = ugi.instanceId WHERE %(labelCheck)s %(itemCheck)s ugi.userGroupId in (%(roleIds)s) GROUP BY Items.item, Nodes.versionId, Nodes.timeStamps, Nodes.finalTimestamp) AS idTable JOIN Versions ON (idTable.versionId = Versions.versionId) LEFT OUTER JOIN TroveInfo AS SourceNameTroveInfo ON idTable.instanceId = SourceNameTroveInfo.instanceId AND SourceNameTroveInfo.infoType = %(SOURCENAME)d LEFT OUTER JOIN TroveInfo AS MetadataTroveInfo ON idTable.instanceId = MetadataTroveInfo.instanceId AND MetadataTroveInfo.infoType = %(METADATA)d """ % d, args) l = list(cu) filteredL = typeFilter(l, filterSet) # sort based on (name, version, desc(finalTimestamp)) def sortorder(x, y): c = cmp(x[0], y[0]) if c: return c return -(cmp(x[3], y[3])) filteredL.sort(sortorder) if latest: # keep the latest newL = [] last = None for item in filteredL: if last and last[0] == item[0]: continue newL.append(item) last = item filteredL = newL nodeList = datamodel.NamedNodeList(total = len(filteredL), start = 0) addList = [] for (name, version, ts, finalTs, sourceName, metadata) in filteredL: sourceName = cu.frombinary(sourceName) if sourceName is None and trove.troveIsSourceComponent(name): sourceName = name addList.append((sourceName, str(versions.VersionFromString(version).getSourceVersion()))) schema.resetTable(cu, 'tmpNVF') # This is painful, but it converts the source name from a blob to # a string db.bulkload("tmpNVF", [ (x[0],) + x[1] for x in enumerate(addList) ], ["idx", "name", "version"], start_transaction = False) cu.execute(""" SELECT ChangeLogs.name, ChangeLogs.message, tmpNVF.name FROM tmpNVF JOIN Items AS SourceItems ON tmpNVF.name = SourceItems.item LEFT OUTER JOIN Versions AS SourceVersion ON tmpNVF.version = SourceVersion.version LEFT OUTER JOIN Nodes ON SourceItems.itemId = Nodes.itemId AND SourceVersion.versionId = Nodes.versionId LEFT OUTER JOIN ChangeLogs USING (nodeId) ORDER BY tmpNVF.idx """) for ( (name, version, ts, finalTs, sourceName, metadata), (clName, clMessage, troveName) ) in itertools.izip(filteredL, cu): frzVer = versions.strToFrozen(version, [ x for x in ts.split(":") ]) ver = versions.ThawVersion(frzVer) shortdesc = None if metadata: metadata = cu.frombinary(metadata) md = trove.Metadata(metadata) shortdesc = md.get()['shortDesc'] if clName: cl = datamodel.ChangeLog(name = clName, message = clMessage) else: cl = None nodeList.append(name = name, version = ver, mkUrl = mkUrl, changeLog = cl, shortdesc = shortdesc) return nodeList