bitbake: toaster: get all dependents for pkg for removal

For customised image package removal change behavior.
From:
    Only display the immediate dependents of the requested package
    to remove, not the full dependent list, that is dependents of
    dependents ...
    Do not remove the displayed dependents, just notify the user
    of the list.
To:
    Display the complete dependent tree, traversing all reverse
    dependencies starting from the package to be removed and then it's
    dependents.
    Change the modal dialog to note that all of these dependents will
    be removed automatically.

[YOCTO #9121]

(Bitbake rev: 1185a5bfe1b05a1b63a927c9583dfc031fdac8a9)

Signed-off-by: Dave Lerner <dave.lerner@windriver.com>
Signed-off-by: Elliot Smith <elliot.smith@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
This commit is contained in:
Dave Lerner 2016-03-24 12:12:11 +00:00 committed by Richard Purdie
parent 9bf98a9351
commit b036afb537
1 changed files with 79 additions and 12 deletions

View File

@ -2538,6 +2538,60 @@ if True:
return response
def _traverse_dependents(next_package_id, rev_deps, all_current_packages, tree_level=0):
"""
Recurse through reverse dependency tree for next_package_id.
Limit the reverse dependency search to packages not already scanned,
that is, not already in rev_deps.
Limit the scan to a depth (tree_level) not exceeding the count of
all packages in the custom image, and if that depth is exceeded
return False, pop out of the recursion, and write a warning
to the log, but this is unlikely, suggesting a dependency loop
not caught by bitbake.
On return, the input/output arg rev_deps is appended with queryset
dictionary elements, annotated for use in the customimage template.
The list has unsorted, but unique elements.
"""
max_dependency_tree_depth = all_current_packages.count()
if tree_level >= max_dependency_tree_depth:
logger.warning(
"The number of reverse dependencies "
"for this package exceeds " + max_dependency_tree_depth +
" and the remaining reverse dependencies will not be removed")
return True
package = CustomImagePackage.objects.get(id=next_package_id)
dependents = \
package.package_dependencies_target.annotate(
name=F('package__name'),
pk=F('package__pk'),
size=F('package__size'),
).values("name", "pk", "size").exclude(
~Q(pk__in=all_current_packages)
)
for pkg in dependents:
if pkg in rev_deps:
# already seen, skip dependent search
continue
rev_deps.append(pkg)
if (_traverse_dependents(
pkg["pk"], rev_deps, all_current_packages, tree_level+1)):
return True
return False
def _get_all_dependents(package_id, all_current_packages):
"""
Returns sorted list of recursive reverse dependencies for package_id,
as a list of dictionary items, by recursing through dependency
relationships.
"""
rev_deps = []
_traverse_dependents(package_id, rev_deps, all_current_packages)
rev_deps = sorted(rev_deps, key=lambda x: x["name"])
return rev_deps
@xhr_response
def xhr_customrecipe_packages(request, recipe_id, package_id):
@ -2606,15 +2660,9 @@ if True:
)
# Reverse dependencies which are needed by packages that are
# in the image
reverse_deps = package.package_dependencies_target.annotate(
name=F('package__name'),
pk=F('package__pk'),
size=F('package__size'),
).values("name", "pk", "size").exclude(
~Q(pk__in=all_current_packages)
)
# in the image. Recursive search providing all dependents,
# not just immediate dependents.
reverse_deps = _get_all_dependents(package_id, all_current_packages)
total_size_deps = 0
total_size_reverse_deps = 0
@ -2658,6 +2706,11 @@ if True:
else:
recipe.appends_set.add(package)
# Make sure that package is not in the excludes set
try:
recipe.excludes_set.remove(package)
except:
pass
# Add the dependencies we think will be added to the recipe
# as a result of appending this package.
# TODO this should recurse down the entire deps tree
@ -2668,11 +2721,12 @@ if True:
recipe.includes_set.add(cust_package)
try:
# when adding the pre-requisite package make sure it's not in the
# excluded list from a prior removal.
# When adding the pre-requisite package, make
# sure it's not in the excluded list from a
# prior removal.
recipe.excludes_set.remove(cust_package)
except Package.DoesNotExist:
# Don't care if the package had never been excluded
# Don't care if the package had never been excluded
pass
except:
logger.warning("Could not add package's suggested"
@ -2688,6 +2742,19 @@ if True:
recipe.excludes_set.add(package)
else:
recipe.appends_set.remove(package)
all_current_packages = recipe.get_all_packages()
reverse_deps_dictlist = _get_all_dependents(package.pk, all_current_packages)
ids = [entry['pk'] for entry in reverse_deps_dictlist]
reverse_deps = CustomImagePackage.objects.filter(id__in=ids)
for r in reverse_deps:
try:
if r.id in included_packages:
recipe.excludes_set.add(r)
else:
recipe.appends_set.remove(r)
except:
pass
return {"error": "ok"}
except CustomImageRecipe.DoesNotExist:
return {"error": "Tried to remove package that wasn't present"}