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))