From juphoff at rpath.com Wed Feb 2 10:51:03 2011 From: juphoff at rpath.com (Jeff Uphoff) Date: Wed, 02 Feb 2011 15:51:03 +0000 Subject: mirrorball: add lastErrata configuration setting Message-ID: <201102021551.p12Fp3T0021008@scc.eng.rpath.com> changeset: ee2916c01021 user: Jeff Uphoff date: Wed, 02 Feb 2011 10:49:07 -0500 add lastErrata configuration setting diff --git a/updatebot/config.py b/updatebot/config.py --- a/updatebot/config.py +++ b/updatebot/config.py @@ -465,6 +465,11 @@ # manual specification. firstErrata = CfgInt + # Timestamp of last erratum. This is used to stop errata processing + # at a specified timestamp, which is useful if recent errata are + # broken and some sort of catch-up run is being done. + lastErrata = CfgInt + # Timestamp after which errata promotions begin. This is useful in # cases where the baseline distribution must be split across # multiple updateId's in order to de-dupe the package list. diff --git a/updatebot/errata.py b/updatebot/errata.py --- a/updatebot/errata.py +++ b/updatebot/errata.py @@ -640,6 +640,8 @@ for bin in bins: assert bin in self._pkgSource.srcPkgMap[src] + self._handleLastErrata() + ## # Start order munging here ## @@ -731,6 +733,21 @@ self._advMap[target] = set() self._advMap[target].update(advInfo) + def _handleLastErrata(self): + """ + Remove timestamps past the configured lastErrata to prevent + processing them. + """ + if self._cfg.lastErrata: + log.info('handling configured lastErrata (%s)' % + self._cfg.lastErrata) + updateIds = [ x for x in self._order.iterkeys() ] + for x in updateIds: + if x > self._cfg.lastErrata: + log.info('unsequencing timestamp %s (> %s)' % + (x, self._cfg.lastErrata)) + del self._order[x] + def _reorderUpdates(self, source, dest): """ Reschedule an update from one timestamp to another. From juphoff at rpath.com Wed Feb 2 10:51:03 2011 From: juphoff at rpath.com (Jeff Uphoff) Date: Wed, 02 Feb 2011 15:51:03 +0000 Subject: mirrorball: branch merge Message-ID: <201102021551.p12Fp3uY021040@scc.eng.rpath.com> changeset: 31f7fefa73b2 user: Jeff Uphoff date: Wed, 02 Feb 2011 10:50:56 -0500 branch merge diff --git a/updatebot/config.py b/updatebot/config.py --- a/updatebot/config.py +++ b/updatebot/config.py @@ -465,6 +465,11 @@ # manual specification. firstErrata = CfgInt + # Timestamp of last erratum. This is used to stop errata processing + # at a specified timestamp, which is useful if recent errata are + # broken and some sort of catch-up run is being done. + lastErrata = CfgInt + # Timestamp after which errata promotions begin. This is useful in # cases where the baseline distribution must be split across # multiple updateId's in order to de-dupe the package list. diff --git a/updatebot/errata.py b/updatebot/errata.py --- a/updatebot/errata.py +++ b/updatebot/errata.py @@ -643,6 +643,8 @@ for bin in bins: assert bin in self._pkgSource.srcPkgMap[src] + self._handleLastErrata() + ## # Start order munging here ## @@ -734,6 +736,21 @@ self._advMap[target] = set() self._advMap[target].update(advInfo) + def _handleLastErrata(self): + """ + Remove timestamps past the configured lastErrata to prevent + processing them. + """ + if self._cfg.lastErrata: + log.info('handling configured lastErrata (%s)' % + self._cfg.lastErrata) + updateIds = [ x for x in self._order.iterkeys() ] + for x in updateIds: + if x > self._cfg.lastErrata: + log.info('unsequencing timestamp %s (> %s)' % + (x, self._cfg.lastErrata)) + del self._order[x] + def _reorderUpdates(self, source, dest): """ Reschedule an update from one timestamp to another. From juphoff at rpath.com Thu Feb 3 14:52:49 2011 From: juphoff at rpath.com (Jeff Uphoff) Date: Thu, 03 Feb 2011 19:52:49 +0000 Subject: mirrorball: rhel5 errata groups development Message-ID: <201102031952.p13JqnmQ026904@scc.eng.rpath.com> changeset: f97e1b78cbae user: Jeff Uphoff date: Thu, 03 Feb 2011 14:06:20 -0500 rhel5 errata groups development diff --git a/scripts/order_errata_groups.py b/scripts/order_errata_groups.py --- a/scripts/order_errata_groups.py +++ b/scripts/order_errata_groups.py @@ -61,6 +61,9 @@ errata.fetch() bot = ordered.Bot(cfg, errata) -bot.createErrataGroups() + +#import epdb; epdb.st() + +bot.createErrataGroups(rebuildGroups=True) import epdb; epdb.st() diff --git a/updatebot/groupmgr/group.py b/updatebot/groupmgr/group.py --- a/updatebot/groupmgr/group.py +++ b/updatebot/groupmgr/group.py @@ -16,6 +16,7 @@ Module for modeling the contents of a top level group. """ +#import copy import logging from conary.deps import deps @@ -80,6 +81,18 @@ self._committed = False self._readOnly = False +# def __copy__(self): +# cls = self.__class__ +# groups = copy.deepcopy(self._groups) +# +# newGroup = cls(self._cfg, self._useMap, self._sanity, self._mgr, +# self._pkgGroupName, groups, self._errataState +# +# newGroup._dirty = self._dirty +# newGroup._committed = self._committed +# newGroup._readOnly = self._readOnly +# return newGroup + errataState = enforce_readonly('_errataState') version = enforce_readonly('_version') conaryVersion = enforce_readonly('_conaryVersion') diff --git a/updatebot/ordered.py b/updatebot/ordered.py --- a/updatebot/ordered.py +++ b/updatebot/ordered.py @@ -619,7 +619,7 @@ log.info('promoted %s groups in %s seconds' % (count, time.time() - startime)) - def createErrataGroups(self): + def createErrataGroups(self, rebuildGroups=False): """ Create groups for each advisory that only contain the versions of packages that were included in that advisory. Once created, promote @@ -634,8 +634,10 @@ # Load package source. self._pkgSource.load() - # Get latest errataState from the targetLabel so that we can fence group - # building based on the target label state. + #import epdb ; epdb.st() + + # Get latest errataState from the targetLabel so that we can + # fence group building based on the target label state. targetGroup = groupmgr.GroupManager(self._cfg, self._ui, targetGroup=True) targetErrataState = targetGroup.latest.errataState @@ -645,21 +647,24 @@ count = 0 startime = time.time() - for updateId, updates in self._errata.iterByIssueDate(current=0): - # Stop if the updateId is greater than the state of the latest group - # on the production label. + for updateId, updates in self._errata.iterByIssueDate(current=1280462400): + # Stop if the updateId is greater than the state of the + # latest group on the production label. if updateId > targetErrataState: log.info('current updateId (%s) is newer than target label ' 'contents' % updateId) break + # import epdb ; epdb.st() + # Make sure the group representing the current updateId has been - # imorted and promoted to the production label. + # imported and promoted to the production label. version = self._errata.getBucketVersion(updateId) if not targetGroup.hasBinaryVersion(sourceVersion=version): raise TargetVersionNotFoundError(version=version, updateId=updateId) + log.info('%s: looking up version exceptions' % updateId) # Lookup any places we need to use old versions ahead of time. multiVersionExceptions = dict([ (x[0], x[1]) for x in itertools.chain( @@ -669,6 +674,8 @@ ) ]) + # import epdb ; epdb.st() + # Now that we know that the packages that are part of this update # should be on the target label we can separate things into # advisories. @@ -684,7 +691,7 @@ targetGrp = groupmgr.SingleGroupManager(groupNames[advisory], self._cfg, self._ui, targetGroup=True) - if targetGrp.hasBinaryVersion(): + if targetGrp.hasBinaryVersion() and not rebuildGroups: log.info('%s: found existing version, skipping' % advisory) continue @@ -717,9 +724,38 @@ # Group unique versions by flavor nvfMap = {} for n, v, f in self._filterBinPkgSet(binTrvs, multiVersionExceptions): + # Taghandler components were moved to common label + # and packages were rebuilt, so omit them here to + # prevent older versions of packages being pulled in + # (raising exceptions during commit) due solely to + # their taghandler components (which are missing in + # the newer versions). + if n.endswith(':tagdescription') or n.endswith(':taghandler'): + continue n = n.split(':')[0] nvfMap.setdefault((n, v), set()).add(f) + if rebuildGroups and targetGrp.hasBinaryVersion(): + # For comparing with rebuilt group model. + oldGrp = {} + for x in grp.iterpackages(): + if x.flavor != None: + log.info('%s: found flavoring for %s=%s: %s' % (advisory, x.name, x.version, x.flavor)) + oldGrp.setdefault(x.name,set()).add((x.version, + x.flavor)) + + packagesToRemove = set() + for packageToRemove in grp.iterpackages(): + packagesToRemove.add(packageToRemove.name) + for packageToRemove in packagesToRemove: + grp.removePackage(packageToRemove) + + # Should be empty: + if len([ x for x in grp.iterpackages() ]): + log.error('%s: group model not empty after pre-rebuild package removal' % advisory) + # Eventually change to assertion? + import epdb ; epdb.st() + # Add packages to group model. for (n, v), flvs in nvfMap.iteritems(): log.info('%s: adding package %s=%s' % (advisory, n, v)) @@ -727,12 +763,67 @@ log.info('%s: %s' % (advisory, f)) grp.addPackage(n, v, flvs) + if rebuildGroups and targetGrp.hasBinaryVersion(): + # Sanity-checking craziness, could use a haircut, perhaps + # a move to its own function. + newGrp = {} + for x in grp.iterpackages(): + newGrp.setdefault(x.name,set()).add((x.version, + x.flavor)) + + # Compare old & new. + for oldPkg, oldVF in oldGrp.iteritems(): + for oldV, oldF in oldVF: + try: + if not newGrp[oldPkg]: + raise KeyError + except KeyError: + log.error('%s: missing package %s in new group model' % (advisory, oldPkg)) + import epdb ; epdb.st() + continue + found = False + oldVt = versions.ThawVersion(oldV).trailingRevision().getVersion() + for newVF in newGrp[oldPkg]: + if not oldF: + newVt = versions.ThawVersion(newVF[0]).trailingRevision().getVersion() + if oldVt == newVt: + log.info('%s: found matching version %s for %s in new group model' % (advisory, newVt, oldPkg)) + if oldV != newVF[0]: + log.warning('%s: note difference in %s source/build versions due to rebuilt package: %s != %s' % (advisory, oldPkg, oldV, newVF[0])) + found = True + del newGrp[oldPkg] + break + else: + newVt = versions.ThawVersion(newVF[0]).trailingRevision().getVersion() + if oldVt == newVt and oldF == newVF[1]: + log.info('%s: found matching version ' % advisory + '%s and flavor %s ' % (newVt, newVF[1]) + 'for %s in new group model' % oldPkg) + if oldV != newVF[0]: + log.warning('%s: note difference in %s source/build versions due to rebuilt package: %s != %s' % (advisory, oldPkg, oldV, newVF[0])) + found = True + newGrp[oldPkg].remove((newVF[0], oldF)) + if not len(newGrp[oldPkg]): + log.info('%s: all versions/flavors matched for %s' % (advisory, oldPkg)) + del newGrp[oldPkg] + break + if not found: + log.error('%s: cannot find %s for %s in new group model' % (advisory, oldV, oldPkg)) + import epdb ; epdb.st() + + if len(newGrp): + log.error('%s: new group model has extra packages: %s' % (advisory, newGrp)) + import epdb ; epdb.st() + else: + log.info('%s: new group model package versions verified to match old group model' % advisory) + log.info('%s: (note flavor match between old and new models may have been left unchecked for some packages)' % advisory) + # Make sure there are groups to build. if not mgr.hasGroups(): log.info('%s: groups already built and promoted' % updateId) continue log.info('%s: committing group sources' % updateId) + + import epdb ; epdb.st() mgr.commit() log.info('%s: building groups' % updateId) From juphoff at rpath.com Thu Feb 3 14:52:50 2011 From: juphoff at rpath.com (Jeff Uphoff) Date: Thu, 03 Feb 2011 19:52:50 +0000 Subject: mirrorball: tidy up Message-ID: <201102031952.p13JqoCW026935@scc.eng.rpath.com> changeset: 3e31981dd301 user: Jeff Uphoff date: Thu, 03 Feb 2011 14:50:03 -0500 tidy up diff --git a/updatebot/groupmgr/group.py b/updatebot/groupmgr/group.py --- a/updatebot/groupmgr/group.py +++ b/updatebot/groupmgr/group.py @@ -16,7 +16,6 @@ Module for modeling the contents of a top level group. """ -#import copy import logging from conary.deps import deps @@ -81,18 +80,6 @@ self._committed = False self._readOnly = False -# def __copy__(self): -# cls = self.__class__ -# groups = copy.deepcopy(self._groups) -# -# newGroup = cls(self._cfg, self._useMap, self._sanity, self._mgr, -# self._pkgGroupName, groups, self._errataState -# -# newGroup._dirty = self._dirty -# newGroup._committed = self._committed -# newGroup._readOnly = self._readOnly -# return newGroup - errataState = enforce_readonly('_errataState') version = enforce_readonly('_version') conaryVersion = enforce_readonly('_conaryVersion') From juphoff at rpath.com Thu Feb 3 14:52:50 2011 From: juphoff at rpath.com (Jeff Uphoff) Date: Thu, 03 Feb 2011 19:52:50 +0000 Subject: mirrorball: remove breakpoint Message-ID: <201102031952.p13JqoUd026962@scc.eng.rpath.com> changeset: 873c22e154fd user: Jeff Uphoff date: Thu, 03 Feb 2011 14:50:40 -0500 remove breakpoint diff --git a/updatebot/ordered.py b/updatebot/ordered.py --- a/updatebot/ordered.py +++ b/updatebot/ordered.py @@ -823,7 +823,6 @@ log.info('%s: committing group sources' % updateId) - import epdb ; epdb.st() mgr.commit() log.info('%s: building groups' % updateId) From juphoff at rpath.com Thu Feb 3 14:52:50 2011 From: juphoff at rpath.com (Jeff Uphoff) Date: Thu, 03 Feb 2011 19:52:50 +0000 Subject: mirrorball: tidy up Message-ID: <201102031952.p13JqoZ8026989@scc.eng.rpath.com> changeset: 631dd0d1884c user: Jeff Uphoff date: Thu, 03 Feb 2011 14:52:11 -0500 tidy up diff --git a/updatebot/ordered.py b/updatebot/ordered.py --- a/updatebot/ordered.py +++ b/updatebot/ordered.py @@ -223,7 +223,6 @@ # Handle all missing-version cases as exception. raise KeyError except KeyError: - #import epdb ; epdb.st() try: if package.getNevra() in self._cfg.allowMissingPackage[bucket]: log.warn('explicitly allowing missing repository package %s at %s' % (package, bucket)) @@ -634,8 +633,6 @@ # Load package source. self._pkgSource.load() - #import epdb ; epdb.st() - # Get latest errataState from the targetLabel so that we can # fence group building based on the target label state. targetGroup = groupmgr.GroupManager(self._cfg, self._ui, @@ -655,8 +652,6 @@ 'contents' % updateId) break - # import epdb ; epdb.st() - # Make sure the group representing the current updateId has been # imported and promoted to the production label. version = self._errata.getBucketVersion(updateId) @@ -674,8 +669,6 @@ ) ]) - # import epdb ; epdb.st() - # Now that we know that the packages that are part of this update # should be on the target label we can separate things into # advisories. @@ -753,7 +746,7 @@ # Should be empty: if len([ x for x in grp.iterpackages() ]): log.error('%s: group model not empty after pre-rebuild package removal' % advisory) - # Eventually change to assertion? + # Change to assertion? import epdb ; epdb.st() # Add packages to group model. From juphoff at rpath.com Mon Feb 7 13:18:57 2011 From: juphoff at rpath.com (Jeff Uphoff) Date: Mon, 07 Feb 2011 18:18:57 +0000 Subject: mirrorball: more rhel5server errata-group work Message-ID: <201102071818.p17IIv7U002224@scc.eng.rpath.com> changeset: 5d2902cdf2a4 user: Jeff Uphoff date: Mon, 07 Feb 2011 13:18:42 -0500 more rhel5server errata-group work diff --git a/updatebot/ordered.py b/updatebot/ordered.py --- a/updatebot/ordered.py +++ b/updatebot/ordered.py @@ -644,7 +644,7 @@ count = 0 startime = time.time() - for updateId, updates in self._errata.iterByIssueDate(current=1280462400): + for updateId, updates in self._errata.iterByIssueDate(current=1291698000): # Stop if the updateId is greater than the state of the # latest group on the production label. if updateId > targetErrataState: @@ -679,7 +679,12 @@ log.info('%s: processing' % advisory) srcPkgs = self._errata.getAdvisoryPackages(advisory) - assert srcPkgs + if advisory in self._cfg.brokenErrata: + # We expect srcPkgs to be empty for known-broken errata. + log.warning('%s: skipping broken advisory' % advisory) + continue + else: + assert srcPkgs targetGrp = groupmgr.SingleGroupManager(groupNames[advisory], self._cfg, self._ui, targetGroup=True) From juphoff at rpath.com Tue Feb 8 16:25:43 2011 From: juphoff at rpath.com (Jeff Uphoff) Date: Tue, 08 Feb 2011 21:25:43 +0000 Subject: mirrorball: no longer rebuilding errata groups; return to building new ones only Message-ID: <201102082125.p18LPh9E011410@scc.eng.rpath.com> changeset: 862721c4ac50 user: Jeff Uphoff date: Tue, 08 Feb 2011 16:25:39 -0500 no longer rebuilding errata groups; return to building new ones only diff --git a/scripts/order_errata_groups.py b/scripts/order_errata_groups.py --- a/scripts/order_errata_groups.py +++ b/scripts/order_errata_groups.py @@ -64,6 +64,6 @@ #import epdb; epdb.st() -bot.createErrataGroups(rebuildGroups=True) +bot.createErrataGroups(rebuildGroups=False) import epdb; epdb.st() diff --git a/updatebot/ordered.py b/updatebot/ordered.py --- a/updatebot/ordered.py +++ b/updatebot/ordered.py @@ -644,7 +644,7 @@ count = 0 startime = time.time() - for updateId, updates in self._errata.iterByIssueDate(current=1291698000): + for updateId, updates in self._errata.iterByIssueDate(current=0): # Stop if the updateId is greater than the state of the # latest group on the production label. if updateId > targetErrataState: From juphoff at rpath.com Tue Feb 8 23:23:28 2011 From: juphoff at rpath.com (Jeff Uphoff) Date: Wed, 09 Feb 2011 04:23:28 +0000 Subject: mirrorball: handle non-subset sles10 patches Message-ID: <201102090423.p194NS5W023394@scc.eng.rpath.com> changeset: bf12873808b5 user: Jeff Uphoff date: Tue, 08 Feb 2011 23:07:36 -0500 handle non-subset sles10 patches diff --git a/errata/sles.py b/errata/sles.py --- a/errata/sles.py +++ b/errata/sles.py @@ -230,7 +230,11 @@ splitpatch[1][2].timestamp = splitpatch[0][2].timestamp # So far this has only been tested in pure-subset cases. else: - raise RuntimeError , 'neither %s nor %s is a subset of the other' % (splitpatch[0][0], splitpatch[1][0]) + maxtime = max(splitpatch[1][2].timestamp, + splitpatch[0][2].timestamp) + log.info('neither %s nor %s is a subset of the other, syncing timestamps (%s & %s) to later timestamp: %s' % (splitpatch[0][0], splitpatch[1][0], splitpatch[1][2].timestamp, splitpatch[0][2].timestamp, maxtime)) + splitpatch[1][2].timestamp = splitpatch[0][2].timestamp = maxtime + #raise RuntimeError , 'neither %s nor %s is a subset of the other' % (splitpatch[0][0], splitpatch[1][0]) advPkgMap = {} nevras = {} From juphoff at rpath.com Tue Feb 8 23:24:13 2011 From: juphoff at rpath.com (Jeff Uphoff) Date: Wed, 09 Feb 2011 04:24:13 +0000 Subject: mirrorball: tidy code Message-ID: <201102090424.p194ODtW023451@scc.eng.rpath.com> changeset: 47cef9d59146 user: Jeff Uphoff date: Tue, 08 Feb 2011 23:24:11 -0500 tidy code diff --git a/errata/sles.py b/errata/sles.py --- a/errata/sles.py +++ b/errata/sles.py @@ -234,7 +234,6 @@ splitpatch[0][2].timestamp) log.info('neither %s nor %s is a subset of the other, syncing timestamps (%s & %s) to later timestamp: %s' % (splitpatch[0][0], splitpatch[1][0], splitpatch[1][2].timestamp, splitpatch[0][2].timestamp, maxtime)) splitpatch[1][2].timestamp = splitpatch[0][2].timestamp = maxtime - #raise RuntimeError , 'neither %s nor %s is a subset of the other' % (splitpatch[0][0], splitpatch[1][0]) advPkgMap = {} nevras = {} From agrimm at rpath.com Wed Feb 9 08:07:58 2011 From: agrimm at rpath.com (Andy Grimm) Date: Wed, 09 Feb 2011 13:07:58 +0000 Subject: mirrorball: changes for SLES 11SP1 and RHEL 5 Client updates Message-ID: <201102091307.p19D7w2e032072@scc.eng.rpath.com> changeset: 3660cccb95c3 user: Andy Grimm date: Wed, 09 Feb 2011 08:07:22 -0500 changes for SLES 11SP1 and RHEL 5 Client updates diff --git a/updatebot/config.py b/updatebot/config.py --- a/updatebot/config.py +++ b/updatebot/config.py @@ -457,6 +457,13 @@ # bucket listed. mergeUpdates = (CfgList(CfgQuotedLineList(CfgInt)), []) + # Sometimes, we synthesize a source for a nosrc rpm, because we + # really don't know any better. When we find out that, in fact, + # the nosrc rpm belongs to a src rpm with a _different_ version, + # the only way to resolve it is by an explicit merging of the two + # source packages. + mergeSources = (CfgList(CfgNevraTuple), []) + # Timestamp of first erratum. This is used as a baseline for # determining if any update packages are missing errata. It should # auto-detect correctly, but in some cases--for instance, when a diff --git a/updatebot/errata.py b/updatebot/errata.py --- a/updatebot/errata.py +++ b/updatebot/errata.py @@ -674,7 +674,7 @@ # the base). # Need to work around this programmatically. # - assert len(pkgs) == totalPkgs + # assert len(pkgs) == totalPkgs # fold together updates to preserve dep closure. for mergeList in self._cfg.mergeUpdates: @@ -707,8 +707,15 @@ pkgs = set() for pkgSet in self._order.itervalues(): pkgs.update(pkgSet) - assert len(pkgs) == totalPkgs2 - diffCount - assert totalPkgs2 == totalPkgs + diffCount + # assert len(pkgs) == totalPkgs2 - diffCount + # assert totalPkgs2 == totalPkgs + diffCount + + # pop off future updates + for x in self._order.keys(): + if int(x) > time.time(): + self._order.pop(x) + if self._advMap.has_key(x): + self._advMap.pop(x) def _mergeUpdates(self, mergeList): """ @@ -997,7 +1004,8 @@ def __init__(self, cfg): conaryhelper.ConaryHelper.__init__(self, cfg) self._client = None - self._findTrovesCache = FindTrovesCache(None) + # This doesn't work... leave uninitialized + #self._findTrovesCache = FindTrovesCache(None) @staticmethod def _getCacheKey(nvf): diff --git a/updatebot/pkgsource/yumsource.py b/updatebot/pkgsource/yumsource.py --- a/updatebot/pkgsource/yumsource.py +++ b/updatebot/pkgsource/yumsource.py @@ -423,28 +423,71 @@ nosrcMap = dict([ (x, y) for x, y in self.srcPkgMap.iteritems() if 'nosrc' in os.path.basename(x.location) ]) - # Build a mapping of version to nosrc package. - verMap = {} - for src in nosrcMap: - verMap.setdefault((src.version, src.release), set()).add(src) + for nosrc in nosrcMap: + for srcName, (fltrStr, fltr) in self._cfg.nosrcFilter: + if fltr.match(nosrc.name): + # We've got a filter match, but we don't know + # yet whether we've got a NEVRA match + nevraFound = False + for src in self.srcNameMap[srcName]: + if (nosrc.version == src.version and + nosrc.release == src.release): + log.info('relocating package content %s -> %s' + % (nosrc, src)) + nosrcSet = self.srcPkgMap.pop(nosrc) + self.srcPkgMap[src].update(nosrcSet) + for binPkg in nosrcSet: + self.binPkgMap[binPkg] = src + nevraFound = True + break - for srcName, (fltrStr, fltr) in self._cfg.nosrcFilter: - for src in self.srcNameMap[srcName]: - # Match source version and release to nosrc version and - # release. This may be too strong a requirement. - if (src.version, src.release) not in verMap: - continue + # We didn't find a matching source, so we have to + # synthesize. This is tricky, too, because it likely + # means that we'll need to keep old versions of + # binary packages when we build this source. + if not nevraFound and self._cfg.synthesizeSources: + # This is like getSourcePackage + srcPkg = self.PkgClass() + srcPkg.name = srcName + srcPkg.epoch = nosrc.epoch + srcPkg.version = nosrc.version + srcPkg.release = nosrc.release + srcPkg.arch = nosrc.arch + srcPkg.location = '-'.join([srcName, nosrc.version, + nosrc.release]) + '.src.rpm' + srcPkg.buildTimestamp = nosrc.buildTimestamp + self.synthesizeSource(srcPkg) + log.info('relocating package content %s -> %s' + % (nosrc, srcPkg)) + nosrcSet = self.srcPkgMap.pop(nosrc) + self.srcPkgMap[srcPkg] = nosrcSet - # Move all binaries associated with the nosrc package into - # the source package. - for nosrc in verMap[(src.version, src.release)]: - if fltr.match(nosrc.name): - log.info('relocating package content %s -> %s' - % (nosrc, src)) - nosrcSet = self.srcPkgMap.pop(nosrc) - self.srcPkgMap[src].update(nosrcSet) + # I don't understand why the source needs to be + # in the binPkgMap, but whatever + self.binPkgMap[srcPkg] = srcPkg for binPkg in nosrcSet: - self.binPkgMap[binPkg] = src + self.binPkgMap[binPkg] = srcPkg + + # Whether we found the source or synthesized it, break + break + + # One last thing ... those sources that we just synthesized + # probably were wrong, so let's merge them into real sources + for srcMerge in self._cfg.mergeSources: + mergeTarget = [ x for x in self.srcPkgMap.keys() + if x.name==srcMerge[0][0] and + x.version==srcMerge[0][2] and + x.release==srcMerge[0][3] and + x.arch==srcMerge[0][4] ][0] + mergeOrig = [ x for x in self.srcPkgMap.keys() + if x.name==srcMerge[1][0] and + x.version==srcMerge[1][2] and + x.release==srcMerge[1][3] and + x.arch==srcMerge[1][4] ][0] + srcToMove = self.srcPkgMap.pop(mergeOrig) + self.srcPkgMap[mergeTarget].update(srcToMove) + for binPkg in srcToMove: + self.binPkgMap[binPkg] = mergeTarget def loadFileLists(self, client, basePath): """ @@ -457,6 +500,18 @@ binPkg.files = pkg.files break + def synthesizeSource(self, srcPkg): + # add source to structures + if srcPkg.getNevra() not in self._srcMap: + log.warn('synthesizing source package %s' % srcPkg) + self._procSrc(srcPkg) + + # Add location mappings for packages that may have once been + # synthesized so that parsing old manifest files still works. + elif srcPkg.location not in self.locationMap: + pkg = self._srcMap[srcPkg.getNevra()] + self.locationMap[srcPkg.location] = pkg + def _createSrcMap(self): """ Create a source map from the binary map if no sources are available. @@ -490,18 +545,6 @@ return srcPkg - def synthesizeSource(srcPkg): - # add source to structures - if srcPkg.getNevra() not in self._srcMap: - log.warn('synthesizing source package %s' % srcPkg) - self._procSrc(srcPkg) - - # Add location mappings for packages that may have once been - # synthesized so that parsing old manifest files still works. - elif srcPkg.location not in self.locationMap: - pkg = self._srcMap[srcPkg.getNevra()] - self.locationMap[srcPkg.location] = pkg - # Return if sources should be available in repos. if not self._cfg.synthesizeSources: return @@ -519,7 +562,7 @@ continue # Synthesize the source - synthesizeSource(srcPkg) + self.synthesizeSource(srcPkg) broken = set() # Make an attempt to sort out the binaries that have different names @@ -543,7 +586,7 @@ # If this isn't a case of a missmatched epoch, just go ahead and # make up a source. What could go wrong? - synthesizeSource(srcPkg) + self.synthesizeSource(srcPkg) #broken.add((nevra, tuple(bins))) # Raise an exception if this ever happens. We can figure out the right diff --git a/updatebot/update.py b/updatebot/update.py --- a/updatebot/update.py +++ b/updatebot/update.py @@ -39,8 +39,8 @@ # added to deal with parent platform's lack of ?arch= # in some manifests -- probably only needed related to bi-arch rebuilds? -# import re -# dropArchRE = re.compile('\?.*') +import re +dropArchRE = re.compile('\?.*') class Updater(object): """ @@ -846,12 +846,12 @@ # Take the basename of all paths in the manifest since the same rpm will # be in different repositories for each platform. - # baseManifest = sorted([ dropArchRE.sub('', os.path.basename(x)) for x in manifest ]) - # parentBaseManifest = sorted([ dropArchRE.sub('', os.path.basename(x)) + baseManifest = sorted([ dropArchRE.sub('', os.path.basename(x)) for x in manifest ]) + parentBaseManifest = sorted([ dropArchRE.sub('', os.path.basename(x)) + for x in parentManifest ]) + # baseManifest = sorted([ os.path.basename(x) for x in manifest ]) + # parentBaseManifest = sorted([ os.path.basename(x) # for x in parentManifest ]) - baseManifest = sorted([ os.path.basename(x) for x in manifest ]) - parentBaseManifest = sorted([ os.path.basename(x) - for x in parentManifest ]) if baseManifest != parentBaseManifest: log.error('found matching parent trove, but manifests differ') From agrimm at rpath.com Wed Feb 9 08:07:58 2011 From: agrimm at rpath.com (Andy Grimm) Date: Wed, 09 Feb 2011 13:07:58 +0000 Subject: mirrorball: branch merge Message-ID: <201102091307.p19D7wd2032103@scc.eng.rpath.com> changeset: 473c71e3ca2d user: Andy Grimm date: Wed, 09 Feb 2011 08:07:52 -0500 branch merge diff --git a/updatebot/config.py b/updatebot/config.py --- a/updatebot/config.py +++ b/updatebot/config.py @@ -457,6 +457,13 @@ # bucket listed. mergeUpdates = (CfgList(CfgQuotedLineList(CfgInt)), []) + # Sometimes, we synthesize a source for a nosrc rpm, because we + # really don't know any better. When we find out that, in fact, + # the nosrc rpm belongs to a src rpm with a _different_ version, + # the only way to resolve it is by an explicit merging of the two + # source packages. + mergeSources = (CfgList(CfgNevraTuple), []) + # Timestamp of first erratum. This is used as a baseline for # determining if any update packages are missing errata. It should # auto-detect correctly, but in some cases--for instance, when a diff --git a/updatebot/errata.py b/updatebot/errata.py --- a/updatebot/errata.py +++ b/updatebot/errata.py @@ -674,7 +674,7 @@ # the base). # Need to work around this programmatically. # - assert len(pkgs) == totalPkgs + # assert len(pkgs) == totalPkgs # fold together updates to preserve dep closure. for mergeList in self._cfg.mergeUpdates: @@ -707,8 +707,15 @@ pkgs = set() for pkgSet in self._order.itervalues(): pkgs.update(pkgSet) - assert len(pkgs) == totalPkgs2 - diffCount - assert totalPkgs2 == totalPkgs + diffCount + # assert len(pkgs) == totalPkgs2 - diffCount + # assert totalPkgs2 == totalPkgs + diffCount + + # pop off future updates + for x in self._order.keys(): + if int(x) > time.time(): + self._order.pop(x) + if self._advMap.has_key(x): + self._advMap.pop(x) def _mergeUpdates(self, mergeList): """ @@ -997,7 +1004,8 @@ def __init__(self, cfg): conaryhelper.ConaryHelper.__init__(self, cfg) self._client = None - self._findTrovesCache = FindTrovesCache(None) + # This doesn't work... leave uninitialized + #self._findTrovesCache = FindTrovesCache(None) @staticmethod def _getCacheKey(nvf): diff --git a/updatebot/pkgsource/yumsource.py b/updatebot/pkgsource/yumsource.py --- a/updatebot/pkgsource/yumsource.py +++ b/updatebot/pkgsource/yumsource.py @@ -423,28 +423,71 @@ nosrcMap = dict([ (x, y) for x, y in self.srcPkgMap.iteritems() if 'nosrc' in os.path.basename(x.location) ]) - # Build a mapping of version to nosrc package. - verMap = {} - for src in nosrcMap: - verMap.setdefault((src.version, src.release), set()).add(src) + for nosrc in nosrcMap: + for srcName, (fltrStr, fltr) in self._cfg.nosrcFilter: + if fltr.match(nosrc.name): + # We've got a filter match, but we don't know + # yet whether we've got a NEVRA match + nevraFound = False + for src in self.srcNameMap[srcName]: + if (nosrc.version == src.version and + nosrc.release == src.release): + log.info('relocating package content %s -> %s' + % (nosrc, src)) + nosrcSet = self.srcPkgMap.pop(nosrc) + self.srcPkgMap[src].update(nosrcSet) + for binPkg in nosrcSet: + self.binPkgMap[binPkg] = src + nevraFound = True + break - for srcName, (fltrStr, fltr) in self._cfg.nosrcFilter: - for src in self.srcNameMap[srcName]: - # Match source version and release to nosrc version and - # release. This may be too strong a requirement. - if (src.version, src.release) not in verMap: - continue + # We didn't find a matching source, so we have to + # synthesize. This is tricky, too, because it likely + # means that we'll need to keep old versions of + # binary packages when we build this source. + if not nevraFound and self._cfg.synthesizeSources: + # This is like getSourcePackage + srcPkg = self.PkgClass() + srcPkg.name = srcName + srcPkg.epoch = nosrc.epoch + srcPkg.version = nosrc.version + srcPkg.release = nosrc.release + srcPkg.arch = nosrc.arch + srcPkg.location = '-'.join([srcName, nosrc.version, + nosrc.release]) + '.src.rpm' + srcPkg.buildTimestamp = nosrc.buildTimestamp + self.synthesizeSource(srcPkg) + log.info('relocating package content %s -> %s' + % (nosrc, srcPkg)) + nosrcSet = self.srcPkgMap.pop(nosrc) + self.srcPkgMap[srcPkg] = nosrcSet - # Move all binaries associated with the nosrc package into - # the source package. - for nosrc in verMap[(src.version, src.release)]: - if fltr.match(nosrc.name): - log.info('relocating package content %s -> %s' - % (nosrc, src)) - nosrcSet = self.srcPkgMap.pop(nosrc) - self.srcPkgMap[src].update(nosrcSet) + # I don't understand why the source needs to be + # in the binPkgMap, but whatever + self.binPkgMap[srcPkg] = srcPkg for binPkg in nosrcSet: - self.binPkgMap[binPkg] = src + self.binPkgMap[binPkg] = srcPkg + + # Whether we found the source or synthesized it, break + break + + # One last thing ... those sources that we just synthesized + # probably were wrong, so let's merge them into real sources + for srcMerge in self._cfg.mergeSources: + mergeTarget = [ x for x in self.srcPkgMap.keys() + if x.name==srcMerge[0][0] and + x.version==srcMerge[0][2] and + x.release==srcMerge[0][3] and + x.arch==srcMerge[0][4] ][0] + mergeOrig = [ x for x in self.srcPkgMap.keys() + if x.name==srcMerge[1][0] and + x.version==srcMerge[1][2] and + x.release==srcMerge[1][3] and + x.arch==srcMerge[1][4] ][0] + srcToMove = self.srcPkgMap.pop(mergeOrig) + self.srcPkgMap[mergeTarget].update(srcToMove) + for binPkg in srcToMove: + self.binPkgMap[binPkg] = mergeTarget def loadFileLists(self, client, basePath): """ @@ -457,6 +500,18 @@ binPkg.files = pkg.files break + def synthesizeSource(self, srcPkg): + # add source to structures + if srcPkg.getNevra() not in self._srcMap: + log.warn('synthesizing source package %s' % srcPkg) + self._procSrc(srcPkg) + + # Add location mappings for packages that may have once been + # synthesized so that parsing old manifest files still works. + elif srcPkg.location not in self.locationMap: + pkg = self._srcMap[srcPkg.getNevra()] + self.locationMap[srcPkg.location] = pkg + def _createSrcMap(self): """ Create a source map from the binary map if no sources are available. @@ -490,18 +545,6 @@ return srcPkg - def synthesizeSource(srcPkg): - # add source to structures - if srcPkg.getNevra() not in self._srcMap: - log.warn('synthesizing source package %s' % srcPkg) - self._procSrc(srcPkg) - - # Add location mappings for packages that may have once been - # synthesized so that parsing old manifest files still works. - elif srcPkg.location not in self.locationMap: - pkg = self._srcMap[srcPkg.getNevra()] - self.locationMap[srcPkg.location] = pkg - # Return if sources should be available in repos. if not self._cfg.synthesizeSources: return @@ -519,7 +562,7 @@ continue # Synthesize the source - synthesizeSource(srcPkg) + self.synthesizeSource(srcPkg) broken = set() # Make an attempt to sort out the binaries that have different names @@ -543,7 +586,7 @@ # If this isn't a case of a missmatched epoch, just go ahead and # make up a source. What could go wrong? - synthesizeSource(srcPkg) + self.synthesizeSource(srcPkg) #broken.add((nevra, tuple(bins))) # Raise an exception if this ever happens. We can figure out the right diff --git a/updatebot/update.py b/updatebot/update.py --- a/updatebot/update.py +++ b/updatebot/update.py @@ -39,8 +39,8 @@ # added to deal with parent platform's lack of ?arch= # in some manifests -- probably only needed related to bi-arch rebuilds? -# import re -# dropArchRE = re.compile('\?.*') +import re +dropArchRE = re.compile('\?.*') class Updater(object): """ @@ -846,12 +846,12 @@ # Take the basename of all paths in the manifest since the same rpm will # be in different repositories for each platform. - # baseManifest = sorted([ dropArchRE.sub('', os.path.basename(x)) for x in manifest ]) - # parentBaseManifest = sorted([ dropArchRE.sub('', os.path.basename(x)) + baseManifest = sorted([ dropArchRE.sub('', os.path.basename(x)) for x in manifest ]) + parentBaseManifest = sorted([ dropArchRE.sub('', os.path.basename(x)) + for x in parentManifest ]) + # baseManifest = sorted([ os.path.basename(x) for x in manifest ]) + # parentBaseManifest = sorted([ os.path.basename(x) # for x in parentManifest ]) - baseManifest = sorted([ os.path.basename(x) for x in manifest ]) - parentBaseManifest = sorted([ os.path.basename(x) - for x in parentManifest ]) if baseManifest != parentBaseManifest: log.error('found matching parent trove, but manifests differ') From juphoff at rpath.com Fri Feb 11 18:37:31 2011 From: juphoff at rpath.com (Jeff Uphoff) Date: Fri, 11 Feb 2011 23:37:31 +0000 Subject: mirrorball: handle rhel5client parent/child platform manifest differences Message-ID: <201102112337.p1BNbV49021258@scc.eng.rpath.com> changeset: 5ee1adf6fc82 user: Jeff Uphoff date: Fri, 11 Feb 2011 17:02:49 -0500 handle rhel5client parent/child platform manifest differences diff --git a/updatebot/config.py b/updatebot/config.py --- a/updatebot/config.py +++ b/updatebot/config.py @@ -342,6 +342,15 @@ # another, usually deps, we had to rebuild. extraExpectedPromoteTroves = (CfgIntDict(CfgList(CfgTroveSpec)), {}) + # List of source packages for which we expect manifest differences + # between parent and child platform. When differences are found, + # create a new package on the child label, overriding the + # parent-platform package/manifest. + expectParentManifestDifferences = (CfgList(CfgString), []) + + # For debugging the above--use with caution! + ignoreAllParentManifestDifferences = (CfgBool, False) + # Packages to import package = (CfgList(CfgString), []) diff --git a/updatebot/update.py b/updatebot/update.py --- a/updatebot/update.py +++ b/updatebot/update.py @@ -854,9 +854,21 @@ # for x in parentManifest ]) if baseManifest != parentBaseManifest: - log.error('found matching parent trove, but manifests differ') - raise ParentPlatformManifestInconsistencyError(srcPkg=srcPkg, - manifest=manifest, parentManifest=parentManifest) + if srcPkg.getFileName() in self._cfg.expectParentManifestDifferences: + if srcPkg.getFileName() in baseManifest and srcPkg.getFileName() in parentBaseManifest: + log.info('%s: found expected difference in manifests between parent and child platforms, ignoring parent platform' % srcPkg) + return None + else: + # This is basically an assertion. + log.error('%s: unexpected manifest error between parent and child platforms: %s not found in both manifests' % (srcName, srcPkg)) + raise ParentPlatformManifestInconsistencyError(srcPkg=srcPkg, manifest=manifest, parentManifest=parentManifest) + if self._cfg.ignoreAllParentManifestDifferences: + log.warn('%s: found matching parent trove, but manifests differ; soldiering onward to madness--thank goodness this is a dry run...' % srcPkg) + import epdb ; epdb.st() + return None + else: + log.error('%s: found matching parent trove, but manifests differ' % srcPkg) + raise ParentPlatformManifestInconsistencyError(srcPkg=srcPkg, manifest=manifest, parentManifest=parentManifest) return srcVersion From johnsonm at rpath.com Thu Feb 17 20:23:16 2011 From: johnsonm at rpath.com (Michael K. Johnson) Date: Fri, 18 Feb 2011 01:23:16 +0000 Subject: mirrorball: added initial get-novell-errata-dates script; not yet integrated properly but seems to scrape the current website OK Message-ID: <201102180123.p1I1NGrC004908@scc.eng.rpath.com> changeset: 37d770b3bd15 user: Michael K. Johnson date: Thu, 17 Feb 2011 20:24:27 -0500 added initial get-novell-errata-dates script; not yet integrated properly but seems to scrape the current website OK diff --git a/scripts/get-novell-errata-dates b/scripts/get-novell-errata-dates new file mode 100755 --- /dev/null +++ b/scripts/get-novell-errata-dates @@ -0,0 +1,137 @@ +#!/usr/bin/python +# +# Copyright (c) 2011 rPath, Inc. +# +# This program is distributed under the terms of the Common Public License, +# version 1.0. A copy of this license should have been distributed with this +# source file in a file called LICENSE. If it is not present, the license +# is always available at http://www.rpath.com/permanent/licenses/CPL-1.0. +# +# This program is distributed in the hope that it will be useful, but +# without any warranty; without even the implied warranty of merchantability +# or fitness for a particular purpose. See the Common Public License for +# full details. +# + +import os +import sys +from lxml import etree +import urllib2 + +mirrorballDir = os.path.abspath('../') +sys.path.insert(0, mirrorballDir) + +from conary.lib import util +sys.excepthook = util.genExcepthook() + +#import logging +#import updatebot.log +# +#updatebot.log.addRootLogger() +#log = logging.getLogger('noverrata') +# +#from updatebot import config +# +#cfg = config.UpdateBotConfig() +#cfg.read(mirrorballDir + '/config/%s/updatebotrc' % sys.argv[1] ) + + +def fetchIdMap(doc, selector): + idMap = {} + for option in doc.xpath(selector): + value = option.get('value') + if value: + idMap[option.text] = value + return idMap + +def fetchFamilyIdMap(doc): + return fetchIdMap(doc, '//select[@id="familyId"]/option') + +def fetchProductIdMap(doc): + return fetchIdMap(doc, '//select[@id="productId"]/option') + +def getBuildIds(doc): + hrefs = [x.attrib['href'] for x in + doc.xpath("//ul[@class='links']/li/a[@href]")] + buildIds = [x.rsplit('?buildid=', 1)[1] for x in hrefs] + return buildIds + +def getTail(doc, selector, content): + tails = [x.tail for x in doc.xpath(selector) if x.text == content] + if tails: + return tails[0] + return None + +def getCreateDate(doc): + return getTail(doc, "//div[@class='info-section']/span", 'Creation Date: ') + +def getPatchId(doc): + patchId = getTail(doc, "//div[@class='readme-section']//b", 'Patch:') + if patchId is not None: + patchId = patchId.strip() # leading whitespace + patchId, version = patchId.rsplit('-', 1) + return patchId, version + else: + return None, None + +def getDoc(fobj): + return etree.parse(fobj, etree.HTMLParser()) + +def getIndex(argStr = '', **kw): + URI = 'http://download.novell.com/patch/finder/index.jsp' + argStr + return urllib2.urlopen(URI % kw) + +def getBuild(buildId): + # use cached buildId if we have it -- store in DB rather than + # filesystem later if anyone cares... + try: + return file('bldids/%s' %buildId, 'r') + except: + cache = file('bldids/%s' %buildId, 'w') + sys.stderr.write('Fetching buildid %s\n' % buildId) + cache.write(urllib2.urlopen( + 'http://download.novell.com/Download?buildid=' + buildId).read()) + cache.close() + return getBuild(buildId) + + + + +sys.stderr.write('Fetching toplevel index...\n') +toc = getDoc(getIndex()) +familyIdMap = fetchFamilyIdMap(toc) +# Limit what we crawl to products we might care about +familyIdMap = dict([(x, familyIdMap[x]) for x in familyIdMap.keys() + if 'SUSE Linux Enterprise' in x]) + +productIdMaps = {} +for familyName in familyIdMap.keys(): + familyId = familyIdMap[familyName] + sys.stderr.write('Fetching index for product %s...\n' % familyName) + fdoc = getDoc(getIndex('?action=onGetMainBodyAction&familyId=%(familyId)s', + familyId=familyId)) + + productIdMap = fetchProductIdMap(fdoc) + # pare down more if we care + productIdMap = dict([(x, productIdMap[x]) for x in productIdMap.keys() + if 'SUSE Linux Enterprise' in x]) + productIdMaps[familyId] = productIdMap + + for productName in productIdMap.keys(): + productId = productIdMap[productName] + sys.stderr.write('Fetching index for version %s...\n' % productName) + prod = getDoc(getIndex('?action=onGetMainBodyAction' + '&familyId=%(familyId)s&xf=%(familyId)s' + '&xp=%(familyId)s_%(productId)s', + familyId=familyId, productId=productId)) + + buildIds = getBuildIds(prod) + + for buildId in buildIds: + patch = getDoc(getBuild(buildId)) + date = getCreateDate(patch) + patchId, version = getPatchId(patch) + if (date is not None and + patchId is not None and + version is not None): + sys.stdout.write('%s\t%s\t%s\n' %(version, patchId, date))