summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorNarayan Desai <desai@mcs.anl.gov>2009-10-21 02:55:18 +0000
committerNarayan Desai <desai@mcs.anl.gov>2009-10-21 02:55:18 +0000
commitf08a3e2d8e2e9729142f792d2665265f3753408e (patch)
treea13d4fc3ad01e92c551263404f0070091493c261 /src
parent9bf76f4b581c37b03bac49636447325146531dc9 (diff)
downloadbcfg2-f08a3e2d8e2e9729142f792d2665265f3753408e.tar.gz
bcfg2-f08a3e2d8e2e9729142f792d2665265f3753408e.tar.bz2
bcfg2-f08a3e2d8e2e9729142f792d2665265f3753408e.zip
Packages: simplify package resolution logic (should resolve outstanding issues with prereq resolution)
git-svn-id: https://svn.mcs.anl.gov/repos/bcfg/trunk/bcfg2@5490 ce84e21b-d406-0410-9b95-82705330c041
Diffstat (limited to 'src')
-rw-r--r--src/lib/Server/Plugins/Packages.py200
1 files changed, 105 insertions, 95 deletions
diff --git a/src/lib/Server/Plugins/Packages.py b/src/lib/Server/Plugins/Packages.py
index 02596c5a8..0d71341f7 100644
--- a/src/lib/Server/Plugins/Packages.py
+++ b/src/lib/Server/Plugins/Packages.py
@@ -130,99 +130,93 @@ class Source(object):
def is_package(self, metadata, _):
return False
- def complete(self, metadata, packages, unresolved, debug=False):
- '''Construct the transitive closure of package dependencies for client
+ def resolve_requirement(self, metadata, requirement, packages, debug=False):
+ '''Resolve requirement to packages and or additional requirements
Arguments:
- metadata - client metadata instance
- packages - set of package names
- unresolved - set of unresolved dependency package names
- debug - boolean debug mode
+ metadata -- client metadata instance
+ requirement -- name of requirement
+ debug -- boolean debug flag
+
+ Returns => (packages, unresolved requirements)
'''
- # perhaps cache arch?
- #arch = [a for a in self.arches if a in metadata.groups][0]
- # return newpkg, unknown
- newpkg = set(packages)
- unknown = set()
- work = set(unresolved)
- seen = set()
- while work:
- item = work.pop()
- seen.add(item)
+ if self.is_package(metadata, requirement):
+ item_is_pkg = True
+ else:
+ item_is_pkg = False
+
+ try:
+ provset = self.get_provides(metadata, requirement)
+ item_is_virt = True
+ except:
+ item_is_virt = False
+
+ if True not in [item_is_pkg, item_is_virt]:
+ raise NoData
+
+ if debug:
+ logger.debug("Handling requirement %s" % (requirement))
+
+ if item_is_pkg and not item_is_virt:
+ deps = set()
if debug:
- logger.debug("Handling item %s" % item)
- item_is_pkg = self.is_package(metadata, item)
+ logger.debug("Adding Package %s" % requirement)
try:
- pset = self.get_provides(metadata, item)
- item_is_virt = True
- except NoData:
- item_is_virt = False
-
- #print "%s:%s:%s" % (item, item_is_pkg, item_is_virt)
- if (not item_is_pkg) and (not item_is_virt):
- unknown.add(item)
- continue
- if item_is_pkg and not item_is_virt:
- newpkg.add(item)
+ deps = self.get_deps(metadata, requirement)
+ if debug:
+ logger.debug("Package %s: adding new deps %s" \
+ % (requirement, deps))
+ except:
+ pass
+ return (set([requirement]), deps)
+ if item_is_virt:
+ if item_is_pkg:
+ # requirement can be used to satisfy virt requirement
+ provset.add(requirement)
+ if debug:
+ logger.debug("Requirement %s provided by %s" \
+ % (requirement, provset))
+
+ if len(provset) == 1:
+ # single choice for requirement
+ deps = set()
+ pname = list(provset)[0]
+ if debug:
+ logger.debug("Adding Package %s for %s" % (pname, requirement))
try:
- newdeps = set(self.get_deps(metadata, item))
- if debug and newdeps:
+ deps = self.get_deps(metadata, pname)
+ if debug:
logger.debug("Package %s: adding new deps %s" \
- %(item, str(newdeps)))
- work.update(newdeps.difference(newpkg))
- except NoData:
- continue
- elif item_is_virt:
- if item_is_pkg:
- pset.add(item)
+ % (pname, deps))
+ except:
+ pass
+ return (set([pname]), deps)
+
+ satisfiers = provset.intersection(packages)
+ if satisfiers:
+ # requirement already satisfied
if debug:
- logger.debug("Package(s) %s provide(s) %s" \
- % (list(pset), item))
+ logger.debug("Requirement %s satisfied by %s" \
+ % (requirement, satisfiers))
+ return (set(), set())
- if len(pset) == 1:
- provider = list(pset)[0]
+ if item_is_pkg:
+ # fall back to package with name of requirement
+ deps = set()
+ if debug:
+ logger.debug("Adding Package %s for %s" \
+ % (requirement, requirement))
+ try:
+ deps = self.get_deps(metadata, requirement)
if debug:
- logger.debug("Using package %s for requirement %s" \
- % (provider, item))
- newpkg.add(provider)
- # add deps for provider
- try:
- newdeps = set(self.get_deps(metadata, provider))
- work.update(newdeps.difference(newpkg))
- except NoData:
- pass
- else:
- if True in [p in newpkg for p in pset]:
- # dep satisfied
- try:
- newdeps = set(self.get_deps(metadata, item))
- if debug and newdeps:
- logger.debug("Package %s: adding new deps %s" \
- %(item, str(newdeps)))
- work.update(newdeps.difference(newpkg))
- except NoData:
- pass
- elif item_is_pkg:
- # add this pkg as a default action
- if debug:
- logger.debug("Adding Package %s" % item)
- newpkg.add(item)
- try:
- newdeps = set(self.get_deps(metadata, item))
- if debug and newdeps:
- logger.debug("Package %s: adding new deps %s" \
- %(item, str(newdeps)))
- work.update(newdeps.difference(newpkg))
- except NoData:
- pass
- else:
- # dep unsatisfied
- # FIXME: hacky; multiple provides still not forced
- unknown.add(item)
- else:
- unknown.add(item)
- work.difference_update(seen)
- return (newpkg, unknown)
+ logger.debug("Package %s: adding new deps %s" \
+ % (requirement, deps))
+ except:
+ pass
+ return (set([requirement]), deps)
+
+ print "wtf man. %s" % requirement
+ raise NoData
class YUMSource(Source):
xp = '{http://linux.duke.edu/metadata/common}'
@@ -368,9 +362,11 @@ class YUMSource(Source):
else:
raise NoData
- def complete(self, metadata, packages, unknown, debug):
- p1, u1 = Source.complete(self, metadata, packages, unknown, debug)
- return (p1, set([u for u in u1 if not u.startswith('rpmlib')]))
+ def resolve_requirement(self, m, r, p, d):
+ if r.startswith('rpmlib'):
+ return (set(), set())
+ else:
+ return Source.resolve_requirement(self, m, r, p, d)
class APTSource(Source):
basegroups = ['debian', 'ubuntu', 'nexenta']
@@ -549,18 +545,32 @@ class Packages(Bcfg2.Server.Plugin.Plugin,
if len(ptype) < 1:
return set(), set(), 'failed'
pkgs = set(packages)
- unknown = set(packages)
- oldp = set()
- oldu = set()
- while unknown and (pkgs != oldp or unknown != oldu):
- # loop through sources until no progress is made
- oldp = pkgs
- oldu = unknown
+ needed = set(packages)
+ unknown = set()
+ examined = set()
+
+ while needed:
+ # process requirements until all done or no progress
+ current = needed.pop()
+ examined.add(current)
+ found = False
for source in sources:
try:
- pkgs, unknown = source.complete(meta, pkgs, unknown, debug)
+ newp, newr = source.resolve_requirement(meta, current,
+ packages, debug)
+ found = True
+ break
+ except NoData:
+ continue
except:
- self.logger.error("Packages: complete call failed unexpectedly:", exc_info=1)
+ self.logger.error("Packages: resolve_requirement call failed unexpectedly", exc_info=1)
+ if found:
+ pkgs = pkgs.union(newp)
+ needed = needed.union(newr)
+ needed.difference_update(examined)
+ else:
+ unknown.add(current)
+
return pkgs, unknown, ptype.pop()
def validate_structures(self, meta, structures):